MasterKeyStorageManagerTest.kt 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* _____ _
  2. * |_ _| |_ _ _ ___ ___ _ __ __ _
  3. * | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. * |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. *
  6. * Threema for Android
  7. * Copyright (c) 2025 Threema GmbH
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Affero General Public License, version 3,
  11. * as published by the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. */
  21. package ch.threema.localcrypto
  22. import ch.threema.localcrypto.MasterKeyTestData.MASTER_KEY
  23. import ch.threema.localcrypto.models.MasterKeyData
  24. import ch.threema.localcrypto.models.MasterKeyState
  25. import ch.threema.localcrypto.models.MasterKeyStorageData
  26. import ch.threema.localcrypto.models.Version1MasterKeyStorageData
  27. import io.mockk.every
  28. import io.mockk.mockk
  29. import io.mockk.verify
  30. import kotlin.test.Test
  31. import kotlin.test.assertEquals
  32. import kotlin.test.assertFails
  33. import kotlin.test.assertFalse
  34. import kotlin.test.assertTrue
  35. class MasterKeyStorageManagerTest {
  36. @Test
  37. fun `no key exists`() {
  38. val keyStorageManager = MasterKeyStorageManager(
  39. version2KeyFileManager = mockk {
  40. every { keyFileExists() } returns false
  41. },
  42. version1KeyFileManager = mockk {
  43. every { keyFileExists() } returns false
  44. },
  45. )
  46. assertFalse(keyStorageManager.keyExists())
  47. }
  48. @Test
  49. fun `reading from existing version 2 key file`() {
  50. val keyStorageDataMock = mockk<MasterKeyStorageData>()
  51. val keyStateMock = mockk<MasterKeyState>()
  52. val keyStorageManager = MasterKeyStorageManager(
  53. version2KeyFileManager = mockk {
  54. every { keyFileExists() } returns true
  55. every { readKeyFile() } returns keyStorageDataMock
  56. },
  57. version1KeyFileManager = mockk(),
  58. storageStateConverter = mockk {
  59. every { toKeyState(keyStorageDataMock) } returns keyStateMock
  60. },
  61. )
  62. assertTrue(keyStorageManager.keyExists())
  63. assertEquals(keyStateMock, keyStorageManager.readKey())
  64. }
  65. @Test
  66. fun `reading from existing version 1 key file`() {
  67. val keyStorageDataMock = mockk<MasterKeyStorageData.Version1>()
  68. val keyStateMock = mockk<MasterKeyState>()
  69. val keyStorageManager = MasterKeyStorageManager(
  70. version2KeyFileManager = mockk {
  71. every { keyFileExists() } returns false
  72. },
  73. version1KeyFileManager = mockk {
  74. every { keyFileExists() } returns true
  75. every { readKeyFile() } returns keyStorageDataMock
  76. },
  77. storageStateConverter = mockk {
  78. every { toKeyState(keyStorageDataMock) } returns keyStateMock
  79. },
  80. )
  81. assertTrue(keyStorageManager.keyExists())
  82. assertEquals(keyStateMock, keyStorageManager.readKey())
  83. }
  84. @Test
  85. fun `writing key when version 1 key does not exist`() {
  86. val version2KeyFileManagerMock = mockk<Version2MasterKeyFileManager>(relaxed = true)
  87. val version1KeyFileManagerMock = mockk<Version1MasterKeyFileManager>(relaxed = true) {
  88. every { keyFileExists() } returns false
  89. }
  90. val keyStateMock = mockk<MasterKeyState>()
  91. val storageDataMock = mockk<MasterKeyStorageData.Version2>()
  92. val keyStorageManager = MasterKeyStorageManager(
  93. version2KeyFileManager = version2KeyFileManagerMock,
  94. version1KeyFileManager = version1KeyFileManagerMock,
  95. storageStateConverter = mockk {
  96. every { toStorageData(keyStateMock) } returns storageDataMock
  97. },
  98. )
  99. keyStorageManager.writeKey(keyStateMock)
  100. verify(exactly = 1) { version2KeyFileManagerMock.writeKeyFile(storageDataMock) }
  101. verify(exactly = 1) { version1KeyFileManagerMock.deleteFile() }
  102. }
  103. @Test
  104. fun `writing key when version 1 key exists`() {
  105. val version2KeyFileManagerMock = mockk<Version2MasterKeyFileManager>(relaxed = true)
  106. val version1KeyFileManagerMock = mockk<Version1MasterKeyFileManager>(relaxed = true) {
  107. every { keyFileExists() } returns true
  108. every { readKeyFile() } returns MasterKeyStorageData.Version1(
  109. data = Version1MasterKeyStorageData.Unprotected(
  110. masterKeyData = MasterKeyData(
  111. value = MASTER_KEY,
  112. ),
  113. verification = mockk(),
  114. ),
  115. )
  116. }
  117. val keyStateMock = mockk<MasterKeyState.Plain> {
  118. every { masterKeyData } returns MasterKeyData(
  119. value = MASTER_KEY.copyOf(),
  120. )
  121. }
  122. val storageDataMock = mockk<MasterKeyStorageData.Version2>()
  123. val keyStorageManager = MasterKeyStorageManager(
  124. version2KeyFileManager = version2KeyFileManagerMock,
  125. version1KeyFileManager = version1KeyFileManagerMock,
  126. storageStateConverter = mockk {
  127. every { toStorageData(keyStateMock as MasterKeyState) } returns storageDataMock
  128. },
  129. )
  130. keyStorageManager.writeKey(keyStateMock)
  131. verify(exactly = 1) { version2KeyFileManagerMock.writeKeyFile(storageDataMock) }
  132. verify(exactly = 1) { version1KeyFileManagerMock.deleteFile() }
  133. }
  134. @Test
  135. fun `writing key fails when version 1 key exists but has different value`() {
  136. val version2KeyFileManagerMock = mockk<Version2MasterKeyFileManager>(relaxed = true)
  137. val version1KeyFileManagerMock = mockk<Version1MasterKeyFileManager>(relaxed = true) {
  138. every { keyFileExists() } returns true
  139. every { readKeyFile() } returns MasterKeyStorageData.Version1(
  140. data = Version1MasterKeyStorageData.Unprotected(
  141. masterKeyData = MasterKeyData(
  142. value = MASTER_KEY,
  143. ),
  144. verification = mockk(),
  145. ),
  146. )
  147. }
  148. val corruptedKey = MASTER_KEY.copyOf()
  149. corruptedKey[0]++
  150. val keyStateMock = mockk<MasterKeyState.Plain> {
  151. every { masterKeyData } returns MasterKeyData(
  152. value = corruptedKey,
  153. )
  154. }
  155. val storageDataMock = mockk<MasterKeyStorageData.Version2>()
  156. val keyStorageManager = MasterKeyStorageManager(
  157. version2KeyFileManager = version2KeyFileManagerMock,
  158. version1KeyFileManager = version1KeyFileManagerMock,
  159. storageStateConverter = mockk {
  160. every { toStorageData(keyStateMock as MasterKeyState) } returns storageDataMock
  161. },
  162. )
  163. assertFails {
  164. keyStorageManager.writeKey(keyStateMock)
  165. }
  166. verify(exactly = 0) { version2KeyFileManagerMock.writeKeyFile(storageDataMock) }
  167. verify(exactly = 0) { version1KeyFileManagerMock.deleteFile() }
  168. }
  169. }