Update kotlin specific code
This commit is contained in:
parent
4d84a938ac
commit
11d43fe64c
@ -25,7 +25,7 @@ apply plugin: 'com.android.library'
|
|||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 29
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
101
android/src/main/kotlin/fr/pointcheval/native_crypto/Cipher.kt
Normal file
101
android/src/main/kotlin/fr/pointcheval/native_crypto/Cipher.kt
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import java.lang.Exception
|
||||||
|
import javax.crypto.Cipher
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
import javax.crypto.spec.IvParameterSpec
|
||||||
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
enum class CipherAlgorithm(val spec: String) {
|
||||||
|
AES("AES"),
|
||||||
|
BlowFish("BLOWFISH")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class BlockCipherMode(val instance: String) {
|
||||||
|
ECB("ECB"),
|
||||||
|
CBC("CBC"),
|
||||||
|
CFB("CFB"),
|
||||||
|
GCM("GCM"),
|
||||||
|
CGM("CGM"),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Padding(val instance: String) {
|
||||||
|
PKCS5("PKCS5Padding"),
|
||||||
|
None("NoPadding")
|
||||||
|
}
|
||||||
|
|
||||||
|
class CipherParameters(private val mode: BlockCipherMode, private val padding: Padding) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return mode.instance + "/" + padding.instance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Cipher {
|
||||||
|
|
||||||
|
fun getCipherAlgorithm(dartAlgorithm: String) : CipherAlgorithm {
|
||||||
|
return when (dartAlgorithm) {
|
||||||
|
"aes" -> CipherAlgorithm.AES
|
||||||
|
"blowfish" -> CipherAlgorithm.BlowFish
|
||||||
|
else -> CipherAlgorithm.AES
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getInstance(mode : String, padding : String) : CipherParameters {
|
||||||
|
val m = when (mode) {
|
||||||
|
"ecb" -> BlockCipherMode.ECB
|
||||||
|
"cbc" -> BlockCipherMode.CBC
|
||||||
|
"cfb" -> BlockCipherMode.CFB
|
||||||
|
"gcm" -> BlockCipherMode.GCM
|
||||||
|
"cgm" -> BlockCipherMode.CGM
|
||||||
|
else -> throw Exception()
|
||||||
|
}
|
||||||
|
val p = when (padding) {
|
||||||
|
"pkcs5" -> Padding.PKCS5
|
||||||
|
else -> Padding.None
|
||||||
|
}
|
||||||
|
return CipherParameters(m,p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun encrypt(data: ByteArray, key: ByteArray, algorithm: String, mode: String, padding: String) : List<ByteArray> {
|
||||||
|
val algo = getCipherAlgorithm(algorithm)
|
||||||
|
val params = getInstance(mode, padding)
|
||||||
|
|
||||||
|
val keySpecification = algo.spec + "/" + params.toString()
|
||||||
|
|
||||||
|
val mac = Hash().digest(key + data)
|
||||||
|
val sk: SecretKey = SecretKeySpec(key, algo.spec)
|
||||||
|
|
||||||
|
val cipher = Cipher.getInstance(keySpecification)
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, sk)
|
||||||
|
|
||||||
|
val encryptedBytes = cipher.doFinal(mac + data)
|
||||||
|
val iv = cipher.iv
|
||||||
|
|
||||||
|
return listOf(encryptedBytes, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decrypt(payload: Collection<ByteArray>, key: ByteArray, algorithm: String, mode: String, padding: String) : ByteArray? {
|
||||||
|
val algo = getCipherAlgorithm(algorithm)
|
||||||
|
val params = getInstance(mode, padding)
|
||||||
|
|
||||||
|
val keySpecification = algo.spec + "/" + params.toString()
|
||||||
|
|
||||||
|
val sk: SecretKey = SecretKeySpec(key, algo.spec)
|
||||||
|
val cipher = Cipher.getInstance(keySpecification);
|
||||||
|
val iv = payload.last();
|
||||||
|
val ivSpec = IvParameterSpec(iv)
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, sk, ivSpec);
|
||||||
|
|
||||||
|
val decryptedBytes = cipher.doFinal(payload.first());
|
||||||
|
|
||||||
|
val mac = decryptedBytes.copyOfRange(0, 32)
|
||||||
|
val decryptedContent : ByteArray = decryptedBytes.copyOfRange(32, decryptedBytes.size)
|
||||||
|
val verificationMac = Hash().digest(key + decryptedContent)
|
||||||
|
|
||||||
|
return if (mac.contentEquals(verificationMac)) {
|
||||||
|
decryptedContent
|
||||||
|
} else {
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
|
enum class HashAlgorithm(val length : Int) {
|
||||||
|
SHA1(160),
|
||||||
|
SHA128(128),
|
||||||
|
SHA256(256),
|
||||||
|
SHA512(512);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Hash() {
|
||||||
|
fun digest(data: ByteArray?, algorithm: HashAlgorithm): ByteArray {
|
||||||
|
val func : String = when (algorithm) {
|
||||||
|
HashAlgorithm.SHA1 -> "SHA-1"
|
||||||
|
HashAlgorithm.SHA128 -> "SHA-128"
|
||||||
|
HashAlgorithm.SHA256 -> "SHA-256"
|
||||||
|
HashAlgorithm.SHA512 -> "SHA-512"
|
||||||
|
}
|
||||||
|
val md = MessageDigest.getInstance(func)
|
||||||
|
return md.digest(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun digest(data: ByteArray?, algorithm: String): ByteArray {
|
||||||
|
val func : HashAlgorithm = when (algorithm) {
|
||||||
|
"sha1" -> HashAlgorithm.SHA1
|
||||||
|
"sha128" -> HashAlgorithm.SHA128
|
||||||
|
"sha256" -> HashAlgorithm.SHA256
|
||||||
|
"sha512" -> HashAlgorithm.SHA512
|
||||||
|
else -> HashAlgorithm.SHA256
|
||||||
|
}
|
||||||
|
return digest(data, func)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun digest(data: ByteArray?): ByteArray {
|
||||||
|
return digest(data, HashAlgorithm.SHA256)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
import javax.crypto.SecretKeyFactory
|
||||||
|
import javax.crypto.spec.PBEKeySpec
|
||||||
|
|
||||||
|
class KeyDerivation {
|
||||||
|
fun pbkdf2(password: String, salt: String, keyLength: Int, iteration: Int, algorithm: String): ByteArray {
|
||||||
|
val chars: CharArray = password.toCharArray()
|
||||||
|
val availableHashAlgorithm: Map<String, String> = mapOf(
|
||||||
|
"sha1" to "PBKDF2withHmacSHA1",
|
||||||
|
"sha224" to "PBKDF2withHmacSHA224",
|
||||||
|
"sha256" to "PBKDF2WithHmacSHA256",
|
||||||
|
"sha284" to "PBKDF2withHmacSHA384",
|
||||||
|
"sha512" to "PBKDF2withHmacSHA512"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
// SHA-1 and SHA-2 implemented
|
||||||
|
val spec = PBEKeySpec(chars, salt.toByteArray(), iteration, keyLength * 8)
|
||||||
|
val skf: SecretKeyFactory = SecretKeyFactory.getInstance(availableHashAlgorithm[algorithm]);
|
||||||
|
return skf.generateSecret(spec).encoded
|
||||||
|
} else if (Build.VERSION.SDK_INT >= 10) {
|
||||||
|
// Only SHA-1 is implemented
|
||||||
|
if (!algorithm.equals("sha1")) {
|
||||||
|
throw PlatformVersionException("Only SHA1 is implemented on this SDK version!")
|
||||||
|
}
|
||||||
|
val spec = PBEKeySpec(chars, salt.toByteArray(), iteration, keyLength * 8)
|
||||||
|
val skf: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1");
|
||||||
|
return skf.generateSecret(spec).encoded
|
||||||
|
}
|
||||||
|
throw PlatformVersionException("Invalid SDK version!")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import java.security.KeyPairGenerator
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import javax.crypto.KeyGenerator
|
||||||
|
|
||||||
|
class KeyGeneration {
|
||||||
|
fun keygen(size : Int) : ByteArray {
|
||||||
|
val secureRandom = SecureRandom()
|
||||||
|
val keyGenerator = if (size in listOf<Int>(128,192,256)) {
|
||||||
|
KeyGenerator.getInstance("AES")
|
||||||
|
} else {
|
||||||
|
KeyGenerator.getInstance("BLOWFISH")
|
||||||
|
}
|
||||||
|
|
||||||
|
keyGenerator.init(size, secureRandom)
|
||||||
|
val sk = keyGenerator.generateKey()
|
||||||
|
|
||||||
|
return sk!!.encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rsaKeypairGen(size : Int) : List<ByteArray> {
|
||||||
|
val secureRandom = SecureRandom()
|
||||||
|
val keyGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
|
|
||||||
|
keyGenerator.initialize(size, secureRandom)
|
||||||
|
val keypair = keyGenerator.genKeyPair()
|
||||||
|
val res : List<ByteArray> = listOf(keypair.public.encoded, keypair.private.encoded)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
@ -11,162 +11,132 @@ import io.flutter.plugin.common.MethodChannel
|
|||||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||||
import io.flutter.plugin.common.MethodChannel.Result
|
import io.flutter.plugin.common.MethodChannel.Result
|
||||||
import io.flutter.plugin.common.PluginRegistry.Registrar
|
import io.flutter.plugin.common.PluginRegistry.Registrar
|
||||||
import java.security.MessageDigest
|
|
||||||
import java.security.SecureRandom
|
|
||||||
import javax.crypto.Cipher
|
|
||||||
import javax.crypto.KeyGenerator
|
|
||||||
import javax.crypto.SecretKey
|
|
||||||
import javax.crypto.SecretKeyFactory
|
|
||||||
import javax.crypto.spec.IvParameterSpec
|
|
||||||
import javax.crypto.spec.PBEKeySpec
|
|
||||||
import javax.crypto.spec.SecretKeySpec
|
|
||||||
|
|
||||||
|
|
||||||
/** NativeCryptoPlugin */
|
/** NativeCryptoPlugin */
|
||||||
public class NativeCryptoPlugin : FlutterPlugin, MethodCallHandler {
|
class NativeCryptoPlugin : FlutterPlugin, MethodCallHandler {
|
||||||
// CRYPTO CONSTS
|
|
||||||
private val HASH_FUNC = "SHA-256"
|
|
||||||
private val SYM_CRYPTO_METHOD = "AES"
|
|
||||||
private val SYM_CRYPTO_PADDING = "AES/CBC/PKCS5PADDING"
|
|
||||||
|
|
||||||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
val channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "native.crypto.helper")
|
val channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "native.crypto")
|
||||||
channel.setMethodCallHandler(NativeCryptoPlugin());
|
channel.setMethodCallHandler(NativeCryptoPlugin());
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun registerWith(registrar: Registrar) {
|
fun registerWith(registrar: Registrar) {
|
||||||
val channel = MethodChannel(registrar.messenger(), "native.crypto.helper")
|
val channel = MethodChannel(registrar.messenger(), "native.crypto")
|
||||||
channel.setMethodCallHandler(NativeCryptoPlugin())
|
channel.setMethodCallHandler(NativeCryptoPlugin())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
|
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
|
||||||
if (call.method == "pbkdf2") {
|
|
||||||
|
|
||||||
|
when (call.method) {
|
||||||
|
"digest" -> {
|
||||||
|
val message = call.argument<ByteArray>("message")
|
||||||
|
val algorithm = call.argument<String>("algorithm")
|
||||||
|
|
||||||
|
try {
|
||||||
|
val d = Hash().digest(message, algorithm!!)
|
||||||
|
if (d.isNotEmpty()) {
|
||||||
|
result.success(d)
|
||||||
|
} else {
|
||||||
|
result.error("DIGESTERROR", "DIGEST IS NULL.", null)
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
result.error("DIGESTEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"pbkdf2" -> {
|
||||||
val password = call.argument<String>("password")
|
val password = call.argument<String>("password")
|
||||||
val salt = call.argument<String>("salt")
|
val salt = call.argument<String>("salt")
|
||||||
val keyLength = call.argument<Int>("keyLength")
|
val keyLength = call.argument<Int>("keyLength")
|
||||||
val iteration = call.argument<Int>("iteration")
|
val iteration = call.argument<Int>("iteration")
|
||||||
val algorithm = call.argument<String>("algorithm")
|
val algorithm = call.argument<String>("algorithm")
|
||||||
|
|
||||||
val key = pbkdf2(password!!, salt!!, keyLength!!, iteration!!, algorithm!!)
|
try {
|
||||||
|
val key = KeyDerivation().pbkdf2(password!!, salt!!, keyLength!!, iteration!!, algorithm!!)
|
||||||
if (key.isNotEmpty()) {
|
if (key.isNotEmpty()) {
|
||||||
result.success(key)
|
result.success(key)
|
||||||
} else {
|
} else {
|
||||||
result.error("PBKDF2ERROR", "PBKDF2 KEY IS NULL.", null)
|
result.error("PBKDF2ERROR", "PBKDF2 KEY IS NULL.", null)
|
||||||
}
|
}
|
||||||
} else if (call.method == "symKeygen") {
|
} catch (e : Exception) {
|
||||||
val keySize = call.argument<Int>("size") // 128, 192, 256
|
result.error("PBKDF2EXCEPTION", e.message, null)
|
||||||
|
|
||||||
val aesKey = symKeygen(keySize!!) // Collection<ByteArray>
|
|
||||||
|
|
||||||
if (aesKey.isNotEmpty()) {
|
|
||||||
result.success(aesKey)
|
|
||||||
} else {
|
|
||||||
result.error("SYMKEYGENERROR", "GENERATED KEY IS NULL.", null)
|
|
||||||
}
|
}
|
||||||
} else if (call.method == "symEncrypt") {
|
|
||||||
val payload = call.argument<ByteArray>("payload") // ByteArray
|
|
||||||
val aesKey = call.argument<ByteArray>("aesKey") // ByteArray
|
|
||||||
|
|
||||||
val encryptedPayload = symEncrypt(payload!!, aesKey!!) // Collection<ByteArray>
|
|
||||||
|
|
||||||
if (encryptedPayload.isNotEmpty()) {
|
|
||||||
result.success(encryptedPayload)
|
|
||||||
} else {
|
|
||||||
result.error("ENCRYPTIONERROR", "ENCRYPTED PAYLOAD IS NULL.", null)
|
|
||||||
}
|
}
|
||||||
} else if (call.method == "symDecrypt") {
|
"keygen" -> {
|
||||||
|
val size = call.argument<Int>("size") // 128, 192, 256
|
||||||
|
try {
|
||||||
|
val key = KeyGeneration().keygen(size!!)
|
||||||
|
|
||||||
|
if (key.isNotEmpty()) {
|
||||||
|
result.success(key)
|
||||||
|
} else {
|
||||||
|
result.error("KEYGENERROR", "GENERATED KEY IS NULL.", null)
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
result.error("KEYGENEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"rsaKeypairGen" -> {
|
||||||
|
val size = call.argument<Int>("size")
|
||||||
|
try {
|
||||||
|
val keypair = KeyGeneration().rsaKeypairGen(size!!)
|
||||||
|
|
||||||
|
if (keypair.isNotEmpty()) {
|
||||||
|
result.success(keypair)
|
||||||
|
} else {
|
||||||
|
result.error("KEYPAIRGENERROR", "GENERATED KEYPAIR IS EMPTY.", null)
|
||||||
|
}
|
||||||
|
} catch (e : Exception) {
|
||||||
|
result.error("KEYPAIRGENEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"encrypt" -> {
|
||||||
|
val data = call.argument<ByteArray>("data")
|
||||||
|
val key = call.argument<ByteArray>("key")
|
||||||
|
val algorithm = call.argument<String>("algorithm")
|
||||||
|
val mode = call.argument<String>("mode")
|
||||||
|
val padding = call.argument<String>("padding")
|
||||||
|
|
||||||
|
try {
|
||||||
|
val payload = Cipher().encrypt(data!!, key!!, algorithm!!, mode!!, padding!!)
|
||||||
|
|
||||||
|
if (payload.isNotEmpty()) {
|
||||||
|
result.success(payload)
|
||||||
|
} else {
|
||||||
|
result.error("ENCRYPTIONERROR", "ENCRYPTED PAYLOAD IS EMPTY.", null)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
result.error("ENCRYPTIONEXCEPTION", e.message, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
"decrypt" -> {
|
||||||
val payload = call.argument<Collection<ByteArray>>("payload") // Collection<ByteArray>
|
val payload = call.argument<Collection<ByteArray>>("payload") // Collection<ByteArray>
|
||||||
val aesKey = call.argument<ByteArray>("aesKey") // ByteArray
|
|
||||||
|
val key = call.argument<ByteArray>("key")
|
||||||
|
val algorithm = call.argument<String>("algorithm")
|
||||||
|
val mode = call.argument<String>("mode")
|
||||||
|
val padding = call.argument<String>("padding")
|
||||||
|
|
||||||
var decryptedPayload : ByteArray? = null
|
var decryptedPayload : ByteArray? = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
decryptedPayload = symDecrypt(payload!!, aesKey!!)
|
decryptedPayload = Cipher().decrypt(payload!!, key!!, algorithm!!, mode!!, padding!!)
|
||||||
if (decryptedPayload != null && decryptedPayload.isNotEmpty()) {
|
if (decryptedPayload != null && decryptedPayload.isNotEmpty()) {
|
||||||
result.success(decryptedPayload)
|
result.success(decryptedPayload)
|
||||||
} else {
|
} else {
|
||||||
result.error("DECRYPTIONERROR", "DECRYPTED PAYLOAD IS NULL. MAYBE VERIFICATION MAC IS UNVALID.", null)
|
result.error("DECRYPTIONERROR", "DECRYPTED PAYLOAD IS NULL. MAYBE VERIFICATION MAC IS UNVALID.", null)
|
||||||
}
|
}
|
||||||
} catch (e : Exception) {
|
} catch (e : Exception) {
|
||||||
result.error("DECRYPTIONERROR", "AN ERROR OCCURED WHILE DECRYPTING.", null)
|
result.error("DECRYPTIONEXCEPTION", e.message, null)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
else -> result.notImplemented()
|
||||||
result.notImplemented()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
|
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CRYPTO NATIVE FUNCTIONS
|
|
||||||
|
|
||||||
private fun digest(obj: ByteArray?): ByteArray {
|
|
||||||
val md = MessageDigest.getInstance(HASH_FUNC)
|
|
||||||
return md.digest(obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pbkdf2(password : String, salt : String, keyLength : Int, iteration : Int, algorithm : String) : ByteArray {
|
|
||||||
val chars: CharArray = password.toCharArray()
|
|
||||||
|
|
||||||
val spec = PBEKeySpec(chars, salt.toByteArray(), iteration, keyLength * 8)
|
|
||||||
val skf: SecretKeyFactory = if (algorithm == "sha1") {
|
|
||||||
SecretKeyFactory.getInstance("PBKDF2withHmacSHA1")
|
|
||||||
} else if (algorithm == "sha256") {
|
|
||||||
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
|
||||||
} else {
|
|
||||||
SecretKeyFactory.getInstance("PBKDF2withHmacSHA512")
|
|
||||||
}
|
|
||||||
return skf.generateSecret(spec).encoded
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun symKeygen(keySize : Int): ByteArray {
|
|
||||||
|
|
||||||
val SYM_CRYPTO_BITS = keySize
|
|
||||||
|
|
||||||
val secureRandom = SecureRandom()
|
|
||||||
val keyGenerator = KeyGenerator.getInstance(SYM_CRYPTO_METHOD)
|
|
||||||
keyGenerator?.init(SYM_CRYPTO_BITS, secureRandom)
|
|
||||||
val skey = keyGenerator?.generateKey()
|
|
||||||
|
|
||||||
return skey!!.encoded
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun symEncrypt(payload: ByteArray, aesKey: ByteArray): Collection<ByteArray> {
|
|
||||||
|
|
||||||
val mac = digest(aesKey + payload)
|
|
||||||
val key: SecretKey = SecretKeySpec(aesKey, SYM_CRYPTO_METHOD)
|
|
||||||
|
|
||||||
val cipher = Cipher.getInstance(SYM_CRYPTO_PADDING)
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key)
|
|
||||||
|
|
||||||
val encryptedBytes = cipher.doFinal(mac + payload)
|
|
||||||
val iv = cipher.iv
|
|
||||||
|
|
||||||
return listOf(encryptedBytes, iv);
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun symDecrypt(payload: Collection<ByteArray>, aesKey: ByteArray): ByteArray? {
|
|
||||||
|
|
||||||
val key: SecretKey = SecretKeySpec(aesKey, SYM_CRYPTO_METHOD)
|
|
||||||
val cipher = Cipher.getInstance(SYM_CRYPTO_PADDING);
|
|
||||||
val iv = payload.last();
|
|
||||||
val ivSpec = IvParameterSpec(iv)
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
|
|
||||||
|
|
||||||
val decryptedBytes = cipher.doFinal(payload.first());
|
|
||||||
|
|
||||||
val mac = decryptedBytes.copyOfRange(0, 32)
|
|
||||||
val decryptedContent = decryptedBytes.copyOfRange(32, decryptedBytes.size)
|
|
||||||
val verificationMac = digest(aesKey + decryptedContent)
|
|
||||||
|
|
||||||
if (mac.contentEquals(verificationMac)) return decryptedContent
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package fr.pointcheval.native_crypto
|
||||||
|
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
class PlatformVersionException(message : String) : Exception(message)
|
Loading…
x
Reference in New Issue
Block a user