Version2MasterKeyStorageEncoder.kt 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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.base.utils.toByteString
  23. import ch.threema.common.toU16littleEndian
  24. import ch.threema.localcrypto.models.Argon2Version
  25. import ch.threema.localcrypto.models.MasterKeyStorageData
  26. import ch.threema.localcrypto.models.Version2MasterKeyStorageInnerData
  27. import ch.threema.localcrypto.models.Version2MasterKeyStorageOuterData
  28. import ch.threema.localcrypto.protobuf.InnerKeyStorage
  29. import ch.threema.localcrypto.protobuf.IntermediateKeyStorage
  30. import ch.threema.localcrypto.protobuf.IntermediateKeyStorageV1Kt.remoteSecretProtected
  31. import ch.threema.localcrypto.protobuf.OuterKeyStorage
  32. import ch.threema.localcrypto.protobuf.OuterKeyStorageV1.Argon2idProtected
  33. import ch.threema.localcrypto.protobuf.OuterKeyStorageV1Kt
  34. import ch.threema.localcrypto.protobuf.innerKeyStorageV1
  35. import ch.threema.localcrypto.protobuf.intermediateKeyStorageV1
  36. import ch.threema.localcrypto.protobuf.outerKeyStorageV1
  37. import ch.threema.protobuf.combineEncryptedDataAndNonce
  38. import com.google.protobuf.ByteString
  39. import com.google.protobuf.Internal
  40. import com.google.protobuf.MessageLite
  41. import com.google.protobuf.kotlin.plus
  42. import com.google.protobuf.kotlin.toByteString
  43. class Version2MasterKeyStorageEncoder {
  44. fun encodeMasterKeyStorageData(masterKeyStorageData: MasterKeyStorageData.Version2): ByteString =
  45. encodeOuterData(masterKeyStorageData.outerData)
  46. private fun encodeOuterData(outerData: Version2MasterKeyStorageOuterData): ByteString =
  47. encodeVersionedMessage(
  48. version = OuterKeyStorage.Version.V1_0,
  49. message = outerKeyStorageV1 {
  50. when (outerData) {
  51. is Version2MasterKeyStorageOuterData.PassphraseProtected -> {
  52. argon2IdProtectedIntermediate = encodePassphraseProtected(outerData)
  53. }
  54. is Version2MasterKeyStorageOuterData.NotPassphraseProtected -> {
  55. plaintextIntermediate = encodeInnerData(outerData.innerData)
  56. }
  57. }
  58. },
  59. )
  60. private fun encodePassphraseProtected(outerData: Version2MasterKeyStorageOuterData.PassphraseProtected): Argon2idProtected =
  61. OuterKeyStorageV1Kt.argon2idProtected {
  62. version = when (outerData.argonVersion) {
  63. Argon2Version.VERSION_1_3 -> Argon2idProtected.Argon2Version.VERSION_1_3
  64. }
  65. iterations = outerData.iterations
  66. memoryBytes = outerData.memoryBytes
  67. parallelism = outerData.parallelism
  68. salt = outerData.salt.toByteString()
  69. encryptedIntermediate = combineEncryptedDataAndNonce(
  70. data = outerData.encryptedData.value,
  71. nonce = outerData.nonce.value,
  72. ).toByteString()
  73. }
  74. fun encodeInnerData(innerData: Version2MasterKeyStorageInnerData): ByteString =
  75. encodeVersionedMessage(
  76. version = IntermediateKeyStorage.Version.V1_0,
  77. message = intermediateKeyStorageV1 {
  78. when (innerData) {
  79. is Version2MasterKeyStorageInnerData.RemoteSecretProtected -> {
  80. this.remoteSecretProtectedInner = remoteSecretProtected {
  81. remoteSecretHash = innerData.parameters.remoteSecretHash.toByteString()
  82. remoteSecretAuthenticationToken = innerData.parameters.authenticationToken.toByteString()
  83. encryptedInner = innerData.encryptedData.toByteString()
  84. }
  85. }
  86. is Version2MasterKeyStorageInnerData.Unprotected -> {
  87. plaintextInner = encodeVersionedMessage(
  88. version = InnerKeyStorage.Version.V1_0,
  89. message = innerKeyStorageV1 {
  90. masterKey = innerData.masterKeyData.toByteString()
  91. },
  92. )
  93. }
  94. }
  95. },
  96. )
  97. private fun encodeVersionedMessage(version: Internal.EnumLite, message: MessageLite): ByteString =
  98. version.toByteString() + message.toByteString()
  99. private fun Internal.EnumLite.toByteString(): ByteString =
  100. number.toU16littleEndian().toByteString()
  101. }