Coverage Summary for Class: BackupCrypto (com.georgeci.moneysurfer.data.backup.crypto)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| BackupCrypto |
100%
(1/1)
|
100%
(5/5)
|
|
100%
(10/10)
|
100%
(78/78)
|
package com.georgeci.moneysurfer.data.backup.crypto
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.Mac
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
internal actual object BackupCrypto {
private val secureRandom = SecureRandom()
actual fun randomBytes(count: Int): ByteArray =
ByteArray(count).also(secureRandom::nextBytes)
actual fun pbkdf2Sha256(
passphrase: String,
salt: ByteArray,
iterations: Int,
keyLengthBytes: Int,
): ByteArray {
// JCA's PBKDF2WithHmacSHA256 encodes the char[] as UTF-8 — matching
// the byte-oriented CommonCrypto actual on iOS.
val spec = PBEKeySpec(passphrase.toCharArray(), salt, iterations, keyLengthBytes * Byte.SIZE_BITS)
return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(spec).encoded
}
actual fun aesCtr(key: ByteArray, iv: ByteArray, data: ByteArray): ByteArray {
val cipher = Cipher.getInstance("AES/CTR/NoPadding")
// CTR is symmetric; ENCRYPT_MODE serves both directions.
cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
return cipher.doFinal(data)
}
actual fun hmacSha256(key: ByteArray, data: ByteArray): ByteArray {
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(key, "HmacSHA256"))
return mac.doFinal(data)
}
}