Implement AES backup algorithm (WIP need to check with valere the private key thing)
This commit is contained in:
parent
1d26207df7
commit
03272a9c8f
@ -42,6 +42,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCurve25519AuthData
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
|
||||
import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
@ -321,7 +322,8 @@ class KeysBackupTest : InstrumentedTest {
|
||||
put(cryptoTestData.roomId, roomKeysBackupData)
|
||||
}
|
||||
)
|
||||
val sessionsData = algorithm.decryptSessions(keyBackupCreationInfo.recoveryKey, keysBackupData)
|
||||
algorithm.setRecoveryKey(keyBackupCreationInfo.recoveryKey)
|
||||
val sessionsData = algorithm.decryptSessions(keysBackupData)
|
||||
val sessionData = sessionsData.firstOrNull()
|
||||
assertNotNull(sessionData)
|
||||
// - Compare the decrypted megolm key with the original one
|
||||
|
@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
||||
import org.matrix.android.sdk.api.auth.data.Credentials
|
||||
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_CURVE_25519_BACKUP
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.failure.MatrixError
|
||||
import org.matrix.android.sdk.api.listeners.ProgressListener
|
||||
@ -45,6 +46,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.computeRecoveryKey
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
|
||||
import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
@ -630,8 +632,9 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
|
||||
// Get backed up keys from the homeserver
|
||||
val data = getKeys(sessionId, roomId, keysVersionResult.version)
|
||||
algorithm?.setRecoveryKey(recoveryKey)
|
||||
val sessionsData = withContext(coroutineDispatchers.computation) {
|
||||
algorithm?.decryptSessions(recoveryKey, data)
|
||||
algorithm?.decryptSessions(data)
|
||||
}.orEmpty()
|
||||
// Do not trigger a backup for them if they come from the backup version we are using
|
||||
val backUp = keysVersionResult.version != keysBackupVersion?.version
|
||||
@ -998,7 +1001,8 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
private fun isValidRecoveryKeyForKeysBackupVersion(recoveryKey: String, keysBackupData: KeysVersionResult): Boolean {
|
||||
return try {
|
||||
val algorithm = algorithmFactory.create(keysBackupData)
|
||||
val isValid = algorithm.keyMatches(recoveryKey)
|
||||
val privateKey = extractCurveKeyFromRecoveryKey(recoveryKey) ?: return false
|
||||
val isValid = algorithm.keyMatches(privateKey)
|
||||
algorithm.release()
|
||||
isValid
|
||||
} catch (failure: Throwable) {
|
||||
@ -1133,7 +1137,8 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
// Gather data to send to the homeserver
|
||||
// roomId -> sessionId -> MXKeyBackupData
|
||||
val keysBackupData = KeysBackupData()
|
||||
|
||||
val recoveryKey = cryptoStore.getKeyBackupRecoveryKeyInfo()?.recoveryKey
|
||||
algorithm?.setRecoveryKey(recoveryKey)
|
||||
olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper ->
|
||||
val roomId = olmInboundGroupSessionWrapper.roomId ?: return@forEach
|
||||
val olmInboundGroupSession = olmInboundGroupSessionWrapper.session
|
||||
@ -1242,7 +1247,9 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
}
|
||||
?: return null
|
||||
|
||||
val sessionBackupData = algorithm?.encryptSession(sessionData) ?: return null
|
||||
val sessionBackupData = tryOrNull {
|
||||
algorithm?.encryptSession(sessionData)
|
||||
} ?: return null
|
||||
return KeyBackupData(
|
||||
firstMessageIndex = try {
|
||||
olmInboundGroupSessionWrapper.session.firstKnownIndex
|
||||
@ -1265,6 +1272,10 @@ internal class DefaultKeysBackupService @Inject constructor(
|
||||
return sessionData.sharedHistory
|
||||
}
|
||||
|
||||
private fun getPrivateKey(): ByteArray {
|
||||
return byteArrayOf()
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
* For test only
|
||||
* ========================================================================================== */
|
||||
|
@ -20,15 +20,24 @@ import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_AES_256_BACKUP
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAes256AuthData
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
|
||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.api.util.fromBase64
|
||||
import org.matrix.android.sdk.api.util.toBase64NoPadding
|
||||
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
|
||||
import org.matrix.android.sdk.internal.crypto.tools.AesHmacSha2
|
||||
import org.matrix.olm.OlmException
|
||||
import timber.log.Timber
|
||||
import java.security.InvalidParameterException
|
||||
import java.util.Arrays
|
||||
|
||||
internal class KeysBackupAes256Algorithm(keysVersions: KeysVersionResult) : KeysBackupAlgorithm {
|
||||
|
||||
override val untrusted: Boolean = true
|
||||
override val untrusted: Boolean = false
|
||||
|
||||
private val aesAuthData: MegolmBackupAes256AuthData
|
||||
private var privateKey: ByteArray? = null
|
||||
|
||||
init {
|
||||
if (keysVersions.algorithm != MXCRYPTO_ALGORITHM_AES_256_BACKUP) {
|
||||
@ -37,21 +46,92 @@ internal class KeysBackupAes256Algorithm(keysVersions: KeysVersionResult) : Keys
|
||||
aesAuthData = keysVersions.getAuthDataAsMegolmBackupAuthData() as MegolmBackupAes256AuthData
|
||||
}
|
||||
|
||||
override fun encryptSession(sessionData: MegolmSessionData): JsonDict? {
|
||||
TODO("Not yet implemented")
|
||||
override fun setRecoveryKey(recoveryKey: String?) {
|
||||
privateKey = extractCurveKeyFromRecoveryKey(recoveryKey)
|
||||
}
|
||||
|
||||
override fun decryptSessions(recoveryKey: String, data: KeysBackupData): List<MegolmSessionData> {
|
||||
TODO("Not yet implemented")
|
||||
override fun encryptSession(sessionData: MegolmSessionData): JsonDict? {
|
||||
val privateKey = privateKey
|
||||
if (privateKey == null || !keyMatches(privateKey)) {
|
||||
Timber.e("Key does not match")
|
||||
throw IllegalStateException("Key does not match")
|
||||
}
|
||||
val encryptedSessionBackupData = try {
|
||||
val sessionDataJson = sessionData.asBackupJson()
|
||||
AesHmacSha2.encrypt(privateKey = privateKey, secretName = sessionData.sessionId ?: "", sessionDataJson)
|
||||
} catch (e: OlmException) {
|
||||
Timber.e(e, "Error while encrypting backup data.")
|
||||
null
|
||||
} ?: return null
|
||||
|
||||
return mapOf(
|
||||
"ciphertext" to encryptedSessionBackupData.cipherRawBytes.toBase64NoPadding(),
|
||||
"mac" to encryptedSessionBackupData.mac.toBase64NoPadding(),
|
||||
"iv" to encryptedSessionBackupData.initializationVector.toBase64NoPadding()
|
||||
)
|
||||
}
|
||||
|
||||
override fun decryptSessions(data: KeysBackupData): List<MegolmSessionData> {
|
||||
val privateKey = privateKey
|
||||
if (privateKey == null || !keyMatches(privateKey)) {
|
||||
Timber.e("Invalid recovery key for this keys version")
|
||||
throw InvalidParameterException("Invalid recovery key")
|
||||
}
|
||||
val sessionsData = ArrayList<MegolmSessionData>()
|
||||
// Restore that data
|
||||
var sessionsFromHsCount = 0
|
||||
for ((roomIdLoop, backupData) in data.roomIdToRoomKeysBackupData) {
|
||||
for ((sessionIdLoop, keyBackupData) in backupData.sessionIdToKeyBackupData) {
|
||||
sessionsFromHsCount++
|
||||
val sessionData = decryptSession(keyBackupData.sessionData, sessionIdLoop, roomIdLoop, privateKey)
|
||||
sessionData?.let {
|
||||
sessionsData.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
Timber.v(
|
||||
"Decrypted ${sessionsData.size} keys out of $sessionsFromHsCount from the backup store on the homeserver"
|
||||
)
|
||||
return sessionsData
|
||||
}
|
||||
|
||||
private fun decryptSession(sessionData: JsonDict, sessionId: String, roomId: String, privateKey: ByteArray): MegolmSessionData? {
|
||||
|
||||
val cipherRawBytes = sessionData["ciphertext"]?.toString()?.fromBase64() ?: return null
|
||||
val mac = sessionData["mac"]?.toString()?.fromBase64() ?: throw IllegalStateException("Bad mac")
|
||||
val iv = sessionData["iv"]?.toString()?.fromBase64() ?: ByteArray(16)
|
||||
|
||||
val encryptionInfo = AesHmacSha2.EncryptionInfo(
|
||||
cipherRawBytes = cipherRawBytes,
|
||||
mac = mac,
|
||||
initializationVector = iv
|
||||
)
|
||||
return try {
|
||||
val decrypted = AesHmacSha2.decrypt(privateKey, sessionId, encryptionInfo)
|
||||
createMegolmSessionData(decrypted, sessionId, roomId)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Exception while decrypting")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun release() {
|
||||
TODO("Not yet implemented")
|
||||
privateKey?.apply {
|
||||
Arrays.fill(this, 0)
|
||||
}
|
||||
privateKey = null
|
||||
}
|
||||
|
||||
override val authData: MegolmBackupAuthData = aesAuthData
|
||||
|
||||
override fun keyMatches(key: String): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
override fun keyMatches(privateKey: ByteArray): Boolean {
|
||||
return if (aesAuthData.mac != null) {
|
||||
val keyCheckMac = AesHmacSha2.calculateKeyCheck(privateKey, aesAuthData.iv).mac
|
||||
val authDataMac = aesAuthData.mac.fromBase64()
|
||||
return keyCheckMac.contentEquals(authDataMac)
|
||||
} else {
|
||||
// if we have no information, we have to assume the key is right
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,13 +20,43 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
|
||||
internal interface KeysBackupAlgorithm {
|
||||
|
||||
val authData: MegolmBackupAuthData
|
||||
val untrusted: Boolean
|
||||
|
||||
fun setRecoveryKey(recoveryKey: String?)
|
||||
fun encryptSession(sessionData: MegolmSessionData): JsonDict?
|
||||
fun decryptSessions(recoveryKey: String, data: KeysBackupData): List<MegolmSessionData>
|
||||
fun keyMatches(key: String): Boolean
|
||||
fun decryptSessions(data: KeysBackupData): List<MegolmSessionData>
|
||||
fun keyMatches(privateKey: ByteArray): Boolean
|
||||
fun release()
|
||||
}
|
||||
|
||||
internal fun KeysBackupAlgorithm.createMegolmSessionData(decrypted: String, sessionId: String, roomId: String): MegolmSessionData? {
|
||||
val moshi = MoshiProvider.providesMoshi()
|
||||
val adapter = moshi.adapter(MegolmSessionData::class.java)
|
||||
val sessionBackupData: MegolmSessionData = adapter.fromJson(decrypted) ?: return null
|
||||
return sessionBackupData.copy(
|
||||
sessionId = sessionId,
|
||||
roomId = roomId,
|
||||
untrusted = untrusted
|
||||
)
|
||||
}
|
||||
|
||||
internal fun MegolmSessionData.asBackupJson(): String {
|
||||
val sessionBackupData = mapOf(
|
||||
"algorithm" to algorithm,
|
||||
"sender_key" to senderKey,
|
||||
"sender_claimed_keys" to senderClaimedKeys,
|
||||
"forwarding_curve25519_key_chain" to (forwardingCurve25519KeyChain.orEmpty()),
|
||||
"session_key" to sessionKey,
|
||||
"org.matrix.msc3061.shared_history" to sharedHistory,
|
||||
"untrusted" to untrusted
|
||||
)
|
||||
return MoshiProvider.providesMoshi()
|
||||
.adapter(Map::class.java)
|
||||
.toJson(sessionBackupData)
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromR
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
|
||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||
import org.matrix.olm.OlmException
|
||||
import org.matrix.olm.OlmPkDecryption
|
||||
import org.matrix.olm.OlmPkEncryption
|
||||
@ -40,6 +39,7 @@ internal class KeysBackupCurve25519Algorithm(keysVersions: KeysVersionResult) :
|
||||
private val publicKey: String
|
||||
|
||||
private val encryptionKey: OlmPkEncryption
|
||||
private var privateKey: ByteArray? = null
|
||||
|
||||
init {
|
||||
if (keysVersions.algorithm != MXCRYPTO_ALGORITHM_CURVE_25519_BACKUP) {
|
||||
@ -52,26 +52,17 @@ internal class KeysBackupCurve25519Algorithm(keysVersions: KeysVersionResult) :
|
||||
}
|
||||
}
|
||||
|
||||
override fun setRecoveryKey(recoveryKey: String?) {
|
||||
privateKey = extractCurveKeyFromRecoveryKey(recoveryKey)
|
||||
}
|
||||
|
||||
override fun encryptSession(sessionData: MegolmSessionData): JsonDict? {
|
||||
val sessionBackupData = mapOf(
|
||||
"algorithm" to sessionData.algorithm,
|
||||
"sender_key" to sessionData.senderKey,
|
||||
"sender_claimed_keys" to sessionData.senderClaimedKeys,
|
||||
"forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain.orEmpty()),
|
||||
"session_key" to sessionData.sessionKey,
|
||||
"org.matrix.msc3061.shared_history" to sessionData.sharedHistory,
|
||||
"untrusted" to sessionData.untrusted
|
||||
)
|
||||
|
||||
val json = MoshiProvider.providesMoshi()
|
||||
.adapter(Map::class.java)
|
||||
.toJson(sessionBackupData)
|
||||
|
||||
val encryptedSessionBackupData = try {
|
||||
encryptionKey.encrypt(json)
|
||||
val sessionDataJson = sessionData.asBackupJson()
|
||||
encryptionKey.encrypt(sessionDataJson)
|
||||
} catch (e: OlmException) {
|
||||
Timber.e(e, "Error while encrypting backup data.")
|
||||
null
|
||||
throw e
|
||||
} ?: return null
|
||||
|
||||
return mapOf(
|
||||
@ -81,29 +72,25 @@ internal class KeysBackupCurve25519Algorithm(keysVersions: KeysVersionResult) :
|
||||
)
|
||||
}
|
||||
|
||||
override fun decryptSessions(recoveryKey: String, data: KeysBackupData): List<MegolmSessionData> {
|
||||
fun pkDecryptionFromRecoveryKey(recoveryKey: String): OlmPkDecryption? {
|
||||
// Extract the primary key
|
||||
val privateKey = extractCurveKeyFromRecoveryKey(recoveryKey)
|
||||
// Built the PK decryption with it
|
||||
override fun decryptSessions(data: KeysBackupData): List<MegolmSessionData> {
|
||||
fun pkDecryptionFromPrivateKey(privateKey: ByteArray): OlmPkDecryption? {
|
||||
var decryption: OlmPkDecryption? = null
|
||||
if (privateKey != null) {
|
||||
try {
|
||||
decryption = OlmPkDecryption()
|
||||
decryption.setPrivateKey(privateKey)
|
||||
} catch (e: OlmException) {
|
||||
Timber.e(e, "OlmException")
|
||||
}
|
||||
try {
|
||||
decryption = OlmPkDecryption()
|
||||
decryption.setPrivateKey(privateKey)
|
||||
} catch (e: OlmException) {
|
||||
Timber.e(e, "OlmException")
|
||||
}
|
||||
return decryption
|
||||
}
|
||||
|
||||
if (!keyMatches(recoveryKey)) {
|
||||
val privateKey = this.privateKey
|
||||
if (privateKey == null || !keyMatches(privateKey)) {
|
||||
Timber.e("Invalid recovery key for this keys version")
|
||||
throw InvalidParameterException("Invalid recovery key")
|
||||
}
|
||||
// Get a PK decryption instance
|
||||
val decryption = pkDecryptionFromRecoveryKey(recoveryKey)
|
||||
val decryption = pkDecryptionFromPrivateKey(privateKey)
|
||||
if (decryption == null) {
|
||||
// This should not happen anymore
|
||||
Timber.e("Invalid recovery key. Error")
|
||||
@ -121,6 +108,7 @@ internal class KeysBackupCurve25519Algorithm(keysVersions: KeysVersionResult) :
|
||||
}
|
||||
}
|
||||
}
|
||||
decryption.releaseDecryption()
|
||||
Timber.v(
|
||||
"Decrypted ${sessionsData.size} keys out of $sessionsFromHsCount from the backup store on the homeserver"
|
||||
)
|
||||
@ -128,39 +116,26 @@ internal class KeysBackupCurve25519Algorithm(keysVersions: KeysVersionResult) :
|
||||
}
|
||||
|
||||
private fun decryptSession(sessionData: JsonDict, sessionId: String, roomId: String, decryption: OlmPkDecryption): MegolmSessionData? {
|
||||
var sessionBackupData: MegolmSessionData? = null
|
||||
|
||||
val ciphertext = sessionData["ciphertext"]?.toString()
|
||||
val mac = sessionData["mac"]?.toString()
|
||||
val ephemeralKey = sessionData["ephemeral"]?.toString()
|
||||
|
||||
if (ciphertext != null && mac != null && ephemeralKey != null) {
|
||||
return if (ciphertext != null && mac != null && ephemeralKey != null) {
|
||||
val encrypted = OlmPkMessage()
|
||||
encrypted.mCipherText = ciphertext
|
||||
encrypted.mMac = mac
|
||||
encrypted.mEphemeralKey = ephemeralKey
|
||||
|
||||
try {
|
||||
val decrypted = decryption.decrypt(encrypted)
|
||||
|
||||
val moshi = MoshiProvider.providesMoshi()
|
||||
val adapter = moshi.adapter(MegolmSessionData::class.java)
|
||||
|
||||
sessionBackupData = adapter.fromJson(decrypted)
|
||||
createMegolmSessionData(decrypted, sessionId, roomId)
|
||||
} catch (e: OlmException) {
|
||||
Timber.e(e, "OlmException")
|
||||
}
|
||||
|
||||
if (sessionBackupData != null) {
|
||||
sessionBackupData = sessionBackupData.copy(
|
||||
sessionId = sessionId,
|
||||
roomId = roomId,
|
||||
untrusted = untrusted
|
||||
)
|
||||
Timber.e(e, "Exception while decrypting")
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return sessionBackupData
|
||||
}
|
||||
|
||||
override fun release() {
|
||||
@ -169,14 +144,8 @@ internal class KeysBackupCurve25519Algorithm(keysVersions: KeysVersionResult) :
|
||||
|
||||
override val authData: MegolmBackupAuthData = curveAuthData
|
||||
|
||||
override fun keyMatches(key: String): Boolean {
|
||||
fun pkPublicKeyFromRecoveryKey(recoveryKey: String): String? {
|
||||
// Extract the primary key
|
||||
val privateKey = extractCurveKeyFromRecoveryKey(recoveryKey)
|
||||
if (privateKey == null) {
|
||||
Timber.w("pkPublicKeyFromRecoveryKey: private key is null")
|
||||
return null
|
||||
}
|
||||
override fun keyMatches(privateKey: ByteArray): Boolean {
|
||||
fun pkPublicKeyFromPrivateKey(privateKey: ByteArray): String? {
|
||||
// Built the PK decryption with it
|
||||
val decryption = OlmPkDecryption()
|
||||
val pkPublicKey = try {
|
||||
@ -189,7 +158,7 @@ internal class KeysBackupCurve25519Algorithm(keysVersions: KeysVersionResult) :
|
||||
return pkPublicKey
|
||||
}
|
||||
|
||||
val publicKey = pkPublicKeyFromRecoveryKey(key)
|
||||
val publicKey = pkPublicKeyFromPrivateKey(privateKey)
|
||||
if (publicKey == null) {
|
||||
Timber.w("Public key is null")
|
||||
return false
|
||||
|
@ -221,12 +221,12 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
|
||||
val iv = cipherContent.initializationVector?.fromBase64() ?: ByteArray(16)
|
||||
val cipher = cipherContent.ciphertext?.fromBase64() ?: throw SharedSecretStorageError.BadCipherText
|
||||
val mac = cipherContent.mac?.fromBase64() ?: throw SharedSecretStorageError.BadMac
|
||||
val encryptedResult = AesHmacSha2.Result(
|
||||
val encryptionInfo = AesHmacSha2.EncryptionInfo(
|
||||
cipherRawBytes = cipher,
|
||||
initializationVector = iv,
|
||||
mac = mac
|
||||
)
|
||||
return AesHmacSha2.decrypt(secretKey.privateKey, secretName, encryptedResult)
|
||||
return AesHmacSha2.decrypt(secretKey.privateKey, secretName, encryptionInfo)
|
||||
}
|
||||
|
||||
override fun getAlgorithmsForSecret(name: String): List<KeyInfoResult> {
|
||||
|
@ -27,7 +27,7 @@ import kotlin.experimental.and
|
||||
|
||||
internal object AesHmacSha2 {
|
||||
|
||||
class Result(
|
||||
class EncryptionInfo(
|
||||
val cipherRawBytes: ByteArray,
|
||||
val mac: ByteArray,
|
||||
val initializationVector: ByteArray
|
||||
@ -55,7 +55,7 @@ internal object AesHmacSha2 {
|
||||
* (We use AES-CTR to match file encryption and key exports.)
|
||||
*/
|
||||
@Throws
|
||||
fun encrypt(privateKey: ByteArray, secretName: String, clearDataBase64: String, ivString: String? = null): Result {
|
||||
fun encrypt(privateKey: ByteArray, secretName: String, clearDataBase64: String, ivString: String? = null): EncryptionInfo {
|
||||
val pseudoRandomKey = HkdfSha256.deriveSecret(
|
||||
privateKey,
|
||||
ByteArray(32) { 0.toByte() },
|
||||
@ -94,14 +94,14 @@ internal object AesHmacSha2 {
|
||||
mac.init(macKeySpec)
|
||||
val digest = mac.doFinal(cipherBytes)
|
||||
|
||||
return Result(
|
||||
return EncryptionInfo(
|
||||
cipherRawBytes = cipherBytes,
|
||||
initializationVector = iv,
|
||||
mac = digest
|
||||
)
|
||||
}
|
||||
|
||||
fun decrypt(privateKey: ByteArray, secretName: String, aesHmacSha2Result: Result): String {
|
||||
fun decrypt(privateKey: ByteArray, secretName: String, aesHmacSha2Result: EncryptionInfo): String {
|
||||
val pseudoRandomKey = HkdfSha256.deriveSecret(
|
||||
privateKey,
|
||||
zeroByteArray(32),
|
||||
@ -140,9 +140,9 @@ internal object AesHmacSha2 {
|
||||
* @param {ByteArray} [key] the key to use
|
||||
* @param {string} [iv] The initialization vector as a base64-encoded string.
|
||||
* If omitted, a random initialization vector will be created.
|
||||
* @return [Result] An object that contains, `mac` and `iv` properties.
|
||||
* @return [EncryptionInfo] An object that contains, `mac` and `iv` properties.
|
||||
*/
|
||||
fun calculateKeyCheck(key: ByteArray, iv: String?): Result {
|
||||
fun calculateKeyCheck(key: ByteArray, iv: String?): EncryptionInfo {
|
||||
val zerosStr = String(zeroByteArray(32))
|
||||
return encrypt(key, "", zerosStr, iv)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user