Skip to content

Commit

Permalink
[android] Use tutasdk RSA impl in Android
Browse files Browse the repository at this point in the history
This brings it in line with the earlier iOS change.
  • Loading branch information
paw-hub committed Aug 6, 2024
1 parent f0651f6 commit c3a0d6a
Showing 1 changed file with 11 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,8 @@ import kotlinx.coroutines.withContext
import org.apache.commons.io.IOUtils
import org.apache.commons.io.input.BoundedInputStream
import java.io.*
import java.math.BigInteger
import java.security.*
import java.security.interfaces.RSAPrivateCrtKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.InvalidKeySpecException
import java.security.spec.MGF1ParameterSpec
import java.security.spec.RSAPrivateKeySpec
import java.security.spec.RSAPublicKeySpec
import java.util.*
import javax.crypto.*
import javax.crypto.spec.IvParameterSpec
Expand All @@ -38,7 +32,6 @@ class AndroidNativeCryptoFacade(
const val AES_BLOCK_SIZE_BYTES = 16
val FIXED_IV = ByteArray(AES_BLOCK_SIZE_BYTES).apply { fill(0x88.toByte()) }
const val RSA_KEY_LENGTH_IN_BITS = 2048
const val RSA_ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
const val RSA_PUBLIC_EXPONENT = 65537

/**
Expand Down Expand Up @@ -195,69 +188,34 @@ class AndroidNativeCryptoFacade(
seed: DataWrapper,
): DataWrapper {
try {
return this.rsaEncrypt(
javaPublicKey(publicKey),
return de.tutao.tutasdk.rsaEncryptWithPublicKeyComponents(
data.data,
seed.data
seed.data,
publicKey.modulus,
publicKey.publicExponent.toUInt()
).wrap()
} catch (e: InvalidKeySpecException) {
} catch (e: de.tutao.tutasdk.SimpleRsaException) {
// These types of errors can happen and that's okay, they should be handled gracefully.
throw CryptoError(e)
}
}

/**
* Encrypts an aes key with RSA to a byte array.
*/
@Throws(CryptoError::class)
fun rsaEncrypt(publicKey: PublicKey, data: ByteArray, random: ByteArray): ByteArray {
randomizer.setSeed(random)
return rsaEncrypt(data, publicKey, randomizer)
}

@Throws(CryptoError::class)
private fun rsaEncrypt(data: ByteArray, publicKey: PublicKey, randomizer: SecureRandom): ByteArray {
return try {
val cipher = Cipher.getInstance(RSA_ALGORITHM)
cipher.init(Cipher.ENCRYPT_MODE, publicKey, OAEP_PARAMETER_SPEC, randomizer)
cipher.doFinal(data)
} catch (e: BadPaddingException) {
throw CryptoError(e)
} catch (e: IllegalBlockSizeException) {
throw CryptoError(e)
} catch (e: InvalidKeyException) {
throw CryptoError(e)
}
}

@Throws(CryptoError::class)
override suspend fun rsaDecrypt(privateKey: RsaPrivateKey, data: DataWrapper): DataWrapper {
try {
return rsaDecrypt(
javaPrivateKey(privateKey),
return de.tutao.tutasdk.rsaDecryptWithPrivateKeyComponents(
data.data,
privateKey.modulus,
privateKey.privateExponent,
privateKey.primeP,
privateKey.primeQ
).wrap()
} catch (e: InvalidKeySpecException) {
} catch (e: de.tutao.tutasdk.SimpleRsaException) {
// These types of errors can happen and that's okay, they should be handled gracefully.
throw CryptoError(e)
}
}

@Throws(CryptoError::class)
fun rsaDecrypt(privateKey: PrivateKey, encryptedKey: ByteArray): ByteArray {
return try {
val cipher = Cipher.getInstance(RSA_ALGORITHM)
cipher.init(Cipher.DECRYPT_MODE, privateKey, OAEP_PARAMETER_SPEC, randomizer)
cipher.doFinal(encryptedKey)
} catch (e: BadPaddingException) {
throw CryptoError(e)
} catch (e: InvalidKeyException) {
throw CryptoError(e)
} catch (e: IllegalBlockSizeException) {
throw CryptoError(e)
}
}

@Throws(IOException::class, CryptoError::class)
override suspend fun aesEncryptFile(key: DataWrapper, fileUri: String, iv: DataWrapper): EncryptedFileInfo {
val parsedFileUri = Uri.parse(fileUri)
Expand Down Expand Up @@ -501,43 +459,6 @@ class AndroidNativeCryptoFacade(
}
}

@Throws(InvalidKeySpecException::class)
private fun javaPublicKey(key: RsaPublicKey): PublicKey {
val modulus = BigInteger(key.modulus.base64ToBytes())
val keyFactory = KeyFactory.getInstance("RSA")
return keyFactory.generatePublic(RSAPublicKeySpec(modulus, BigInteger.valueOf(RSA_PUBLIC_EXPONENT.toLong())))
}

@Throws(InvalidKeySpecException::class)
private fun javaPrivateKey(key: RsaPrivateKey): PrivateKey {
val modulus = BigInteger(key.modulus.base64ToBytes())
val privateExponent = BigInteger(key.privateExponent.base64ToBytes())
val keyFactory = KeyFactory.getInstance("RSA")
return keyFactory.generatePrivate(RSAPrivateKeySpec(modulus, privateExponent))
}

private fun BigInteger.toBase64() = toByteArray().toBase64()

private fun PrivateKey(javaKey: RSAPrivateCrtKey) = RsaPrivateKey(
version = 0,
// TODO: is this correct?
keyLength = RSA_KEY_LENGTH_IN_BITS,
modulus = javaKey.modulus.toBase64(),
privateExponent = javaKey.privateExponent.toBase64(),
primeP = javaKey.primeP.toBase64(),
primeQ = javaKey.primeQ.toBase64(),
primeExponentP = javaKey.primeExponentP.toBase64(),
primeExponentQ = javaKey.primeExponentQ.toBase64(),
crtCoefficient = javaKey.crtCoefficient.toBase64(),
)

private fun PublicKey(javaKey: RSAPublicKey) = RsaPublicKey(
version = 0,
keyLength = RSA_KEY_LENGTH_IN_BITS,
modulus = javaKey.modulus.toBase64(),
publicExponent = RSA_PUBLIC_EXPONENT,
)

private fun hasMac(dataLength: Long): Boolean {
return dataLength % 2 == 1L
}
Expand Down

0 comments on commit c3a0d6a

Please sign in to comment.