how to encrypt using a private key - android

I have a Private key file that looks like this
-----BEGIN PRIVATE KEY-----
[content]
-----END PRIVATE KEY-----
i want to encrypt String data using this key
i am trying like this :
fun encryptData(txt: String, pk: String): String {
var encoded = ""
var encrypted: ByteArray? = null
try {
val publicBytes: ByteArray = Base64.decode(pk, Base64.DEFAULT)
val keySpec = X509EncodedKeySpec(publicBytes)
val keyFactory: KeyFactory = KeyFactory.getInstance("RSA")
val pubKey: PrivateKey = keyFactory.generatePrivate(keySpec)
val cipher: Cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING")
cipher.init(Cipher.ENCRYPT_MODE, pubKey)
encrypted = cipher.doFinal(txt.toByteArray())
encoded = Base64.encodeToString(encrypted, Base64.DEFAULT)
} catch (e: Exception) {
e.printStackTrace()
}
return encoded
}
i am getting a InvalidKeySpecException everytime i try to encode
can someone help ?

Related

RSA Decrytion Fail in Android

I am facing some problem in decryption RSA in android Using Kotlin
I dont know what is going wrong , Need some Help
Error Reads As input should be less than 128bytes and its occurring in decryption Function
Code -
val keyGen = KeyPairGenerator.getInstance("RSA")
keyGen.initialize(1024)
val keyPair = keyGen.generateKeyPair()
val privateKey = keyPair.private
val publicKey = keyPair.public
val encoder: java.util.Base64.Encoder = java.util.Base64.getEncoder()
val m = encoder.encodeToString(privateKey.encoded)
val l = encoder.encodeToString(publicKey.encoded)
Log.d("keys","$m andddddddddddddd $l")
val xyz = "abcdefgh"
fun encryption(data: String): String {
var encoded = ""
var encrypted: ByteArray? = null
val publicBytes: ByteArray? = Base64.decode(l, Base64.DEFAULT)
val keySpec: java.security.spec.X509EncodedKeySpec = java.security.spec.X509EncodedKeySpec(publicBytes)
val keyFactory = KeyFactory.getInstance("RSA")
val pubKey = keyFactory.generatePublic(keySpec)
val cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING")
cipher.init(Cipher.ENCRYPT_MODE, pubKey)
encrypted = cipher.doFinal(data.toByteArray())
Log.d("test","$encrypted")
encoded = Base64.encodeToString(encrypted, Base64.DEFAULT)
Log.d("final", encoded)
return encoded
}
val o = encryption(xyz)
val nom = o.length
Log.d("leng","$nom")
fun decryption(data: String) : String{
var decoded = ""
var decrypted: ByteArray? = null
val privateBytes: ByteArray? = Base64.decode(m, Base64.DEFAULT)
val keySpec:PKCS8EncodedKeySpec = PKCS8EncodedKeySpec(privateBytes)
val keyFactory = KeyFactory.getInstance("RSA")
val prvKey = keyFactory.generatePrivate(keySpec)
val cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING")
cipher.init(Cipher.DECRYPT_MODE, prvKey)
decrypted = cipher.doFinal(o.toByteArray())
decoded = Base64.encodeToString(decrypted, Base64.DEFAULT)
Log.d("finald", "$decoded")
return decoded
}
decryption(o)

AES Encrypt/Decrypt SQL DB issue on decryption with Initialization Vector

I am trying to store encrypted data in a SQL database using AES with Initialization Vector (IV). I am able to do this with the following class:
class Encrypted (wordE : String) {
val keyGenerator: KeyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,"AndroidKeyStore")
val keyGenParameterSpec = KeyGenParameterSpec.Builder("MyKeyAlias",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
fun genKey(){
keyGenerator.init(keyGenParameterSpec)
keyGenerator.generateKey()
}
fun getKey(): SecretKey {
genKey()
val keystore = KeyStore.getInstance("AndroidKeyStore")
keystore.load(null)
val secretKeyEntry = keystore.getEntry("MyKeyAlias", null) as KeyStore.SecretKeyEntry
return secretKeyEntry.secretKey
}
fun encryptData(data: String): Pair<ByteArray, ByteArray> {
val cipher = Cipher.getInstance("AES/CBC/NoPadding")
var temp = data
while (temp.toByteArray(Charsets.UTF_8).size % 16 != 0)
temp += "\u0020"
cipher.init(Cipher.ENCRYPT_MODE, getKey())
val ivBytes = cipher.iv
val encryptedBytes = cipher.doFinal(temp.toByteArray(Charsets.UTF_8))
return Pair(ivBytes, encryptedBytes)
}
val pair = encryptData(wordE)
val encrypted = pair.second.toString(Charsets.UTF_8)
val iv = pair.first
}
but I have some problems to decrypt the data from the database.
For decryption I have implemented another class:
class Decrypted (dataD: String, ivD :String) {
fun getKey(): SecretKey {
val keystore = KeyStore.getInstance("AndroidKeyStore")
keystore.load(null)
val secretKeyEntry = keystore.getEntry("MyKeyAlias", null) as KeyStore.SecretKeyEntry
return secretKeyEntry.secretKey
}
fun decryptData(data: String, iv : String) : String {
val spec = IvParameterSpec(iv.toByteArray())
val decipher = Cipher.getInstance("AES/CBC/NoPadding")
decipher.init(Cipher.DECRYPT_MODE, getKey(), spec)
val encryptedData: ByteArray = data.toByteArray()
return decipher.doFinal(encryptedData).toString().trim()
}
val decryptedData = decryptData(dataD, ivD)
}
I understood that IV must be the same as the one generated during encryption, so I also stored IV in the database as .
From my logcat I get an "InvocationTargetException" to "Invalid IV" message.
I can see that when I call the Decrypted class enter for decryption:
dataEncrypted: /�,#�j3�RqLrY�
iv_stored: [B#5a36422

Encrypting in NodeJs and Decrypting in Android

i am working on symmetric encryption, i have a nodeJs/express https server where i do my aes-256-cbc encryption with the following
const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
exports.encrypt = (text,key,iv) => {
let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') };
}
for development and testing purpose i send results as the following :
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
router.get('/xhtml', function(req, res) {
res.setHeader('Content-Type', 'application/json');
let xml_string =
fs.readFileSync("BookRessources/TheSilverChair/"+req.query.param1,"utf8");
let encryptedData =encryptionSystem.encrypt(xml_string,key,iv)
let keyString =Buffer.from(key, "base64").toString("hex")
res.end(JSON.stringify({xml_string:
encryptedData.encryptedData,iv:encryptedData.iv,key:keyString}));
res.end()
});
In the client side on Andoird using Kotlin, i decrypt using :
// converting Hex String to ByteArray
fun String.decodeHex(): ByteArray {
require(length % 2 == 0) { "Must have an even length" }
return chunked(2)
.map { it.toInt(16).toByte() }
.toByteArray()
}
// Getting the Key from a String
private fun setKey(myKey: String):SecretKeySpec {
var sha: MessageDigest? = null
try {
var key = myKey.toByteArray(charset("UTF-8"))
sha = MessageDigest.getInstance("SHA-1")
key = sha.digest(key)
key = Arrays.copyOf(key, 32)
var secretKey = SecretKeySpec(key, "AES")
return secretKey
} catch (e: java.lang.Exception) {
throw e
}
}
// Finally decrypting
fun decrypt(cipherText: String, key: String, IV: String): String? {
try {
val cipher = Cipher.getInstance("AES/CBC/NoPadding")
val keySpec = setKey(key)
val iv = IV.decodeHex()
val ivSpec = IvParameterSpec(iv)
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
val text = cipherText.decodeHex()
val decryptedText = cipher.doFinal(text)
return String(decryptedText)
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
return null
}
Here is snippets for the key, iv and the encrypted data :
"xml_string": "b558282838947a21ea53595057ecf09e9697f91c41e9217a1672d17f5e2b26c55b833234ce55a1691b2d8d5f58097785550d9378331bc161f09c3fd4044643cdf7df8d778dbae2d593ccca830d5d8abf48431947cfc67cfa009aecb4326cc85772bb29a37d6fd19a9f7099185fcdf6879f1aea97f6b27552ed03399e45381f4122671f94b196ae2444ddb3ad812bc50bad3babdb47343555614db4ca68da7f9ae2b9b9c0dcfec51392a9d261ce6353b1cf78cd14b4688ce199c615b10ddae2da6f27de85fc74752c9437922eadbb6d712eee62fc9dc2fc491155d6a85dcf5a3e556ead1993c108864e6b5b4c5750977744c6d07ed13ce85522f05634e3f579474034b57ce9590e1c617bcedd9a06767ca2d7945dd3b26ce9e901aa8b4b8424ed4cabe93f3273fe4801ab0d499acbc7deb869b909df9e280c7b0bd0df522833eae16ebdea470b531d8fa354e09373078ee351526b585c8450937632e3c77a50543e006891b86282f5ed2bb6cf77ddf68f5470361ec3b99a6ef7a49e103afb370052922cc7f403cddc8b5995f87fc57533ee5d1d66acd5aceec071c21dc3a9e2ad3eda740c9f53712f3857ef4f28d40260949770ee65e25e6468ffe64f0cb7a4a21db4062aed8ceb23d1b2dd96b6182efbe23987567fc88f5992e84d89a269f3a945255e96e0b63f73d036890f341726926775c48ec3409692449f94e6beb4e2136551ab1e199912696c1287d047ad17e2744bcbc0a0b58dc402bfce85668e8095939bba1a722fbb38c8f192e243afcbb7983d4c359050a42861c823e46eb69ad65d99afefa568de8b9a7d0ce5efa3743030a354be5d61add4cc2872cd8cbabc3ab32caf3997ac89c84c454adc751c576d4dba339a7c00947ecdb40ad4dd0dd8009a24070fc9543a4812d2461dc1b010a2545647cafacd71c25beddfa67c59fd7172a4dc8a53011cd47a061db7fa6ab0b3094ff628a4bb6c5e5a6fea2341ab0d89d1cf9bfdc42bcee85ede9db9dcf0225447866645dccfa41e90ba242ceaf2ba709aeef14f59527170ce38ebe859ca835c7b920c275378dcb443ad2660b8652c72b0b4e80771811c1caf61a452226b579a33a417e0bee5aeadabef5de69a545c7e2b3f7d5f8ce0617c76bf98ca0d13cb669fe4e557bb8b76e19f5b56592d394468d8a1f86d09d3823b67ef8fde12740cff026cd612dced07cd4e06ba96ddc9cf9d3ee4ab74080bec144dc915fe61fae7bba78d6d4f6b63fc37c1dbaa542d71e55aee1896da978292449ff12d6393458def3e183ecceb50441bc7deb7106e44b58551175671b5c6535926cf7a4b41cbd3f3ec65a960c50b0cc20eb39a52ed9d189b35f3ea900d25168e4aa48c809e65576d6cb630789d17f36f80bb90acf5f5a7e06f2d5ba7a1897adfe972c7569cd12708556520471ad28b540ff8c1fb3b0b4d903c57b290e98d5a22236172c225737f37aef75789529954dc674208a7e67c9d7c64f0d1a73b8f8db5596a46370c90bc0532e3930d6ef3ca47d71926bcb5453a17774997807ccf68bdd7224176c2a19701ac5e2a6d31c43555f4daf1ce56b09c4d19d0ac8b2932dc9c6fb41a75278646300790a4fb9578925218e98463b8c8d7cd499246c55770b7ac3de5c19950b1b04111e9234ceb40527ac487f7910d6b9bb32fdc7347e02d69382fa81b6d62707af367858d6b116706f2fe632e4b16b49c9d0402ee8ac54b80b44c2ce2988269a0536063940c8ef38180f9b891b611002d7cb717e9ad9ca29caf6b259ee9da252275ef4cab23c64d2e7d52e67f6f5addd20b5079cbd7bf5dacb5f977bf4cb503ee3a1ce32053d588a2fe317e4ed833efade3a14c2e4c6b70175414f4eece4a15c51e34a55fa65d4e51909672b1335a25e6b3484b07085509ed5cf14294205ffec70ad04d9458ddc161b59c439debadc186470d5e76d5b00e5aebb1f4727321568a00618c5b875f74fcbafecbb77b589dab31ff7dab7165cb38d9e32e33a1d3177f259c609277ead087df44463daad729a37068101860aab44a80ca51eb22678a9197439e52b2ac2ca97dec15bc994664574fc560c49b33c32597f63ed96000589b264994096fc8d3fc40369e8c7624c423a307538f770adf589f89e84bf145b2e14d333176adaa4d71d04e5508ed2da8c2b20a22890f55885e93212172facff3812270ccb10cfb2b8789ad367ab23e6ec970e1bdfde32b6989567e078a913b09936e8fea92adfc77841141d53658397f9287498f23e19ffa11005544a7d46adaba0cf09f38767098a08736928013771e64f452c2e630af22d228ebf5d4c1d656773ea699644e3982563c0cfccd6241cb28d9f281b1935e780b13967d7c0e8cc786ecac03b0530e1f7eadb460a3e8e8a4af9f02ba5119e2e18278196857cac056315f0389697d102cb2177394bebbf947eaf0395f5274a3fae7e9b183961ae107d5750630bff9f79057e56657151ef1ab593d88104ef829c68e910fee5cf4e6335f82a94b65863f42f7a5a337206b09482c76937410ed3f87600e71448c6277c4cf546c70beedb3236c0c8c0b85294b4f3f838079bf879b6caf1cfff3faf60f7d27f7911f9c0dff026f2b39793711cc102948b6e64852786fba53216a344010470df5b2b121cd53bd35cbba4dd6d1192bffc7fe926b58e7125f4d3480475c5be34317d2cc98990de8804fc99812891a8f508873a56619c699028b5ab3efa7cb1e50d8ed321db4f7ad38cce53d99f133dbf01ebe496ac0cbaa8446b1329ad365ccbd822b01ae51d7ac1e9118bc24df0fa9aafd34b5999a66648b987ac1ce58ebb5bcb8fdb08b7d551a9e7018e9712e8047e57736545a64647c4748dee8927889448e65230144718418caa1aa063f0b1e75075f32dd0411dba1b2c0e0812f4234ba4bb6ba350042e70780f697be5e2421c6847abb19fc2db0b9b29414554e44e877f2975065e5b0f4759781bb95c9e12717d53fd68b5ba583071a3ad360de16f079ff7986e92412406bb58cbfdb604ffa35c919df1c847203ed16e0497d3a004af71d0c08e818b52260b7355e7b4b30506f47abc69fffce914f43983a8c34d3204cf77e864f1162b85986eda26fb53e6f74ddae922f5426febd627657d713fb9feb038dcf37031c0cba4addd1fbee228bc80192a88996ffd7d7a5cd05004f899a28044436526cf9ca49487e7cb2133f167cf09968a3d922511e241d993b2dd790137fe6dfd2717de73c3fb9d5666e393c6f656c537e398a21f67af3f5a3441651fea7ab1df1e87aba21303ebb5ec75b07e95dd1360e3452a9b166dd4477a5a0903dc890e65b8b64b1c6c49132b1fe5711695bf18263daed2232f2295f0eaed48ef2e2b3cd50dcddf95c5bb42564983336e31d9814c77a1ae05f4916816c791725b3128718740b835f016aa4ac3a716d279cbd712a6c6ff9d6eabfd7576641852f033ffc67b98e3c1761d8b1eaa89bee21cf918c8d102994d2b4c1bb9012ff0859166736c2809ccb1271a273f436f0d8c89c703f9c176dbafdd5b822312977051ff8e50eac9705f0ffda9f14585635242b295930d027833130cb3dcbebf4a7327e257d2c761d087d6e7a23efc76bba954ff9116f9f878257a534ee79b02dc75864d2dd616a2730653c783617734a73952b82a5804e9aa558a027fa4ec612ddbb48e54e95af273203e263570b02d0534b661d0cb366900afb7c173cb8c21b5fa34a8ed60c97c578b486f619deda7ac6c969cfc1633979b8c655270f1af3b97bf6d11f5f6b5a70b1109db7d1ce752bc26d87bb9779fa7961b7f4e35bc78a7b83bda8772f829d1d01bb0e523aafddd2b351676550388997fb9ee8a3ada1b27d0b786e41eb624215366d10f247d07433690373a10f61779d3c5819844f11d9abce4085b168d4063e4a21315586be8ff62c51046f3bd3394e68541977fd3728a5488bee1c8dec461d310c4b6cfb54841c310b9a6cf988fd63941ac21ee672a773fea2e9b8727aa709523898f5611c26dec9fdd30e3a80485e1c0fd7aa67456914e914aefa985005a9166cfd89dd1cc70d99bb0a1ce2f1603eb86905a0ac88256178f1c1f9db83677b1e023dbe5a667bf1a9d715f89b94b9b10fa4edf441f6f09523a3021eef23c56ba76f1840796da6889f886d57efc41a9e8e8d081c82d4252a02cf70afe00ebaa900c21271ae575acdebf130bef5635b3950cd1b72e1abc356431409d5bfa444ff451a314757a380f3acac15bf0fb1643ed5897ff0d1b872e8c503d274d7d9132441f2cbdd2e3f57ab9e5bbf0b9a944f9879bdd99b751cee48534f8c63abcf030194d22658902d968931422718697b696843e6ff343c895379fa0be3cb86598517c4e29f18450b8daf5d1f098061546244eba816b89c8d3f8e29c5baf3cce53f65fa406633e3fd47e11ec850e55f664975f53b9870a39b2716137e6340a61583f34067e7377804fe2b431a3f5dfcbc0a28ec3227679404226477846df5846ea1e9364bf857064e8eb036618ee6cd328d9876251d84ce45808b4bb9dcd8f030fb9bb7d6047360a5cad8d587a755cfbe03cae4c25e86024d315b7ad6c25a739123ea5852a1eb4636e1393dae7360953c62dce2ae0368a58287fd5857642f7e83db50415027a4ad93915db77b9b8eee8e67226a4dcea8d801b1356a42c92421d6864aac7208b75326e39096cab337891b81fb5963be3859796facf65b817ecd498c0fe39963a42e369bcd691ca940a490467acaadcc35dfd670df6db912a467ec9072d2e5044cd40b1ea7a49b938fbdd6f86474072b8351cf77c8fb1761fd3c477d0f2258953ff48000f44f7c326b4a7cc13591822315de5e02262678a59af5aacd326b4ee530132ff3b944b179c41f3417dcdc05c1c999553467594bf7282a5aed5af86d543ba69c1c2048aeda5f17221c4de12c0187c6ba58d8de7ff82d3b025b1ea35d63329056c8b16c44414ba57e84fdaae8594740bcad40d50294a6da760cb283c2224281e38dd8a58ada2e6bca94d655c8504a9aabea153b5d6088851081d33a06a0037b830b900cc4756625b4f55018f34674c00317070b07fe548c2f624a43fdf2c5ec071862871693e32a067dd3ffe8b6be0e9aa9b46e2f5314760679868a667afabc0284cef16637c3550649c027851f3e8bb495c1cd7d387e26834523bf974263a5eccfe334907e6bba48dcb4e6f68c0834ba52e3bc1e3c382cdb994452ea6d3d6ec2232f896d33959490aa2d0083ff7857b56b9d29e94cbf730e4775f022931d936dd478539f95ebee46760a8822cf0a38cb91f1dbfc991cad1305d1c507c89e45ed28ff375d4b6341c991f9ea0e4a5626e2229c4d4677744065fcb7044b5ac5e801571845975959ab162f7f3abf51d62a7421b707595372ea5b2ba387d1ca6aadabf4a630af2a002ededec51b7778c5cd88e1e7808d6063e461ff4623c73dc673ff1055432ccfb3f805ad37a139d022b3f6fa7dd6d6ac621ce2b94a9bfadecf8a1ed9ba12b2804b5beccb5d75cc71ec18f4ee0a69ec0e2eb110df4a46938c28a84cfd4a0dff6d8c14f1936eb750571140fa83fbc71b36d7df9f9789bb1b0684a6cf56eb5fc2195d4b028fd45726f33cd35ec1422d51d35a04ef9c4ead9827b6b067aa15f308a87b65dc7590b952dc447a05a82fc84033f28c713726263b3a1f40ef853393dcb970c4636689ee14cc90c30dbc180f1405507063245465dcdaf92d21411dcaa68b8a676b8da500e8f03581801585347529c1559952da61343c491a0bcf1ecf9d74b0bf001e2dd416bc741b380e668eda4ffb5067eeb8fa2f40bea06e7a64358e74fff8d047e2d78a21a7c6a2ee13c24a71b57444a767503dc8616bcd6bbce07c3b509c10301da8ba9001974434179945960cdbc77de4f8995a072989dfafc04489f72404a53730398aa73775fb62c70f164e671584a0d1c0a4d24c03e9233cb23b5b00d7f51eb13a6ecf0fd15d6ec9db401416eb9b31b8927c1960889f2e3b7c0c60c4ba4b39b4f1ab7dc68f366afd2f0a32c43ea7e22fc7bf48df076c3e2c006306b146c1f0785402602ede9ebba07d924e719ac05a138771b87367b45f3fdce04b0e4c77141dff2b367207afe5693c8840a1d5d08df2c2d464e2fdf60c0cb9d7ba2144c96a26aa72cf06f4cfd148481a153c4cd7f199818275755b59b46ea9bff6ef3a4443267272bd22269c1395784ead16b96074016180216a586c5b3fa19c6923e6df8c11436e84a4bdd5668aa9c5353ff0ceef9b1bdbb5de9ae3b1e066f3d3e2ef077ad8c44057097f175e26ed2353bb2b38dece3b08b602256b2cc06a3a8add3d5450fc0e035e695956097ed431fed6dc61f4df638cbea5c8351bb147a3659d1e96fc42469e09492c93ba5c3cf22474b34b2f8e70b46eef0851e5eb08d91d105f7585034660c11170254aeb38f95c0fa6b57b8269705e823ae0fd45fe31879816ae3ff671e53e82340d91533cf748d7c584533e164457fa34723bdfe658750a2cf697a6c45a6b39e25c87d1a72b9051e6b74539b74a353b0f4fdb1e9985205458ec400f710e531ded94cc565301abfd13810b290132d439e8438c5d936ae7d2a654270a35d76e9ebd8d2fcc28bfb7e81232e5425b87399dd96d581127140854e292de72d3b082db418c55bffa58ac633137e2a37bc2ce06083452ef6157af55dcb43ca90ed4b88c6f03ff812cbb66421c993cfd19e58c7b76398c3bdb86b46dacdc83e1582c4f66fea1f33e51e896d975bce9195cc1c74700d2bc15acb2eeb45e2602b22ef2ed34d685c4e5fb61b92292d51c0531a8f1d5a0ee00c9eec7703e280fe94353bdf1e206e119fe0afa5a528b2839b223408e45acc3f631ab9d49d8711cde4a2b5c9b4e7c3cefef8a101dfec433fa77ddd5183598f42dc9e96256b455e7aa2c1df07fb3d1ae7cb4b8418e2f65da69f076f90284db1fad3182abda21ac43f4ce6890c7cbb68f2aefe9f3928123ff2c20b1c08ec1c0a4fd3f548235fbe85e81f966938eb61926d5296549ca264e7b113986ee90f9c7a35d61f80d0331bd5ffff8543271f534702b25f08937135329e8ccd01b830456e2979f0471fd8df1f8574d4fc61983f433af2e3bf0cc944d418c45d3c68b01873370b63b7d817b10f0c455fc369d912168fef986430ff2a39c8f21851eca8ea77dee24dbaec44125fa5a78d1139a6ba02325c5fae4864b63da6fad75381f87eaef8655d923445877f6a9d87d80287ecde5e28e99e9ad70d951633055e66dbbb5451437f71b646243a9863fc7c5f6f45d319c46f2bca026a82ae9d30029a7630c4c95ad850bfd6a3f569d99a8fb332a8d68ff07648a895e0a454df38be6c9bfc680245334facd2897b1f01a326548c6397829afa979676434254185766372879f6baf29f9e7abee97402510f51ee5cfce98b9c8ee565533b96ae8f1e7f6a2898d8a97cca6a3a00b74023a91195e476a35e2d64b81b9f89512cbb2cc84088e48f8e754407b9c25b2b378a00a13195df9443a5f3ad0a379e436a712a8bfffc3dec824516062819f84edf3ddd3de4f1413567c72229ec9570d507a3dbbc870f1f9ca0df39170dea6f7665fa6aba58ec95f9b3f9a5f43755378ccf07d0a3b5938174e166a5cdaa02d5a43991d035423c628ba9bf509b5baff896f940af8bca1b82eaf2f196dc9e626ec31748de1285b77e4548cd25a48e4ef8e5694855e1ee529f7969b074840a54c3bbcb188bbba9950306974560f462c4e939c5b8d7684a8ac5ca641910682c455e5733c2d46b8c466aa31edcb1d1e0ec39e8324f2faf238828ec3a883fe45d13bb2272a67dd0f83eddad30be032bbc2b1a96bd26b8f9bd8a7e932a3d4665d8cd6b7e0ad9a78bf8ed4e6d2b530fa950b71807bbdde2508b1373879b972fb31732bfdd2d28459c4f76a84ade85dc2bcc84d29e9880aeed4654ec1fcb7200121c8786828dcb7efc26626d6bd52493600f8be8c02cdf6e23f7ef91860573d3c62e638112761d2988af90985d6b18b32742fefef47b46c452b0354a99a3c692f16961dfc5674bd8f975c8991b93684ed335cd034f0f039e98da6632dcd0c3eef4b7082756fcb76832ecdf242e80332df5aad9f4ef6b6ec58cade495710c7c6f1aeedf0cd66426cc2bed3e85eeaad60da1a83de5269f2aa31101bc9c5e820aca2ac2bdcc6baec9b5ea02aa175a767ded8752752b5b57fa955ce364f4454988be873d1f1432f9981d67a7c4da81da54fed4052e68081fda4748513041b274adc99db81ca95128c712ae484391a46e1139c32f5fa6c4211576aa2faf1d937068567a4c915fe75b405b5bf6b1f21ae007a7755a6f6edbd1d871b87a16ccbafa26397f346daa092b7359cb9573a1c3ee839207f298818cb0a27aaee7db16350c6bc8a2108f884fb1b3d62a8df7e03ae11f910cf6e53fc7c1f9c22145165afdd86bd1846abd0e6bb46b4a0f1b6af9bf953da77c6ec383a36269b213131e7e906723e6c8a2de23c2b01d82fe30f3f932c14b29bbc3f3bcd9b725981ee24cc5a04e519083f72ae47698f54cd5a915740a18b8119e86b4a1db92795d526a86c284de06160087a247f361db04bc370486ddad06f641e60b67c6a2ad6b2bbad58f9921c82622c716ec2ab55c2d77998382bba3b69464e47228763302d86a2b9274412ab5b6a99dadf04c7e1615916cd9e30457c69780b6aaae520119832142c79005101bc1471b52bba6d3b5112effe02e5b140210f57133bb7808c5f44d07987817ee4edfb14d8785179f3acf2430f8e8033bd5056b98e3aa75910cda3c54368d2d36f45224bfb40658ad878fe9b0b225e3ba646ce8c86ab807e074644ffb22c34373ee29d46b9c0deadfba426e41b10ea018d06aaf0c5446472551bcdf8780252783b0aff190d3cbbe7f108b8eb6aba331b0482ae9f018b37e1ce137acfdc15aca77af61e1644d73549de905ef903edff2fdb67218f74df09550a41a97ab7fe2fa5ffeb463e9bd0cbb3ef961714cf5a3cf081db82fa152db73fbf1aeb7095a06c2cf7ee4a625396dbae8864b7a63aca9c5b2e5d132633d9e681b7cb2f93b7f2e2b42e5e5f347cb14bc48265f5595e7e20855bb4318785f6bc5be93e42b99cfbf3dd0b1fcfa716f9f07da275599f319ebabb907de4942461c676fb15ac3c0054a97ab37234b928e0651c980671530a80e21c4fecd92ac4378a7958a0cb8cd9f6fb8d79993527ce7791671ff05b1b4fd63182b77adf49e2c205e2d5fc6b8dd5163dbbbfbc5aff4f150d6066ecc59a22162f67ad98c8deaff53ba53039f647bd07f4460c71b601ac6f54bdece7be34befba57119197a0aa0fc167e14fc753e0c350a671bfd469542ee419654ff966523438ee28f8b2d09744a088550078e5be63d529b44a4995bc8ab03b39d6cdf476c36dc4a4f969c3d125f27146a446a5d2cc12dbcdb62ff30415eba05cdaf2865bb67eaa9b9061b0468fbdddcbe9aa227e23ea8c45eab131e69ef1f00880696bd5e40bca4693d1ee1bb864e393cf28de49fc3b45e8393d156c03da0b9f2360f27f8a9963a4602a09f5d55107fb2e0b062142e992f92ddee870293bf0faf3a4ddcdfbee653a0cf2d53a53f66f46130b341f8afab5d615710b5b5d8128269a4eec3d30aee252ffbbc2052ea1ff6ce60f79f8194d295fc79d4fabae62485716475b10f0495ec3b8c639d560ce8b99b29005940b0477ecf3d15a67e4b1458dfd99d6cf673a3584aad2d2930c13b3fc48a0528098d751dbb2cafe5cd63d709a59e342480102fd4d5d4e026834b961d6f8baf317e00eec31136f38ee7cfa4601816773288ac3506d0f4d7b301a9cf2d5ae7f4ab114f34a721894f8860701b6f046f42d4e0cf24be79f09a1c2dcd430e8d4f7a87411c8f25e54b6fa8ff0087bf873c8f63aa134ea3b42e9a90c5b3103d423c564216a4b9d7f0d8024d0c53be35289304cde6c40f3d2871dfb852eb0cf9f04792e38620462419d6a2cafba2a12dd6b10a06cdf0b321c1f233489881121aeff4a6dedc06e8cec26e35d4e1585b05b7b5af371766596057ea31b5303d9c90fd25739224b6025be938e475c6d56f31f1d391e21b0127bd4b023f633fb25e3431f50a0963f1a9e3499c607d2825495cccec8767d6090890a8cf4c7752fb9d8e25961de95d68a1f548bc628c2b3a761d351f162f4cc99fc3c4bc58688daef804787ad45b8fff2a7975c76f28b57003220ed237d3d2a43ebe72d5bbd914a4452ccbff1a4f3c97ab8ff63e69983acea9da31c5c1dd25866fa533d390af9c7d3e5d5084c7e0b359508d2fce6bbbfc9e36f8be49c66e4bf86a79053aa224b8178d59eefc714bf5eeb423aa0645a0eb0c859c4a0a289ebd4773b46367cbc0c829f998c8f4b89db29a3454c97a438d591a9b5fd87fc126fbf279a0f41fe491920ae895bf04b447ee0d8397ad08b3e7e31c8bf31ffa05e396aa41ac63c03b6e4e5acf0cde5f53ca6ec116f5114305283975eb222bee93bd8aa173d346a1f827b798afd8f7df8609090ccacacb81b9cd351a017d988ecda59d503b216edaabb5ec895941707ee300de6311e1d62c8cfe9ce6f5276a521908c604470ffc0c7548a79ebedd315f8772eef87e0cb154f5c82c99c584ea28039a0cebaeb1318ef99b3d086c9ea69fdc398cecc346a0f000858f19fe18afbd232c6753c0430e51cfc65681724c1ea3ac80c93636e644b996594f4a98b5eb596e3d69e5ccd87d25cd287f3f55f0e12b9a38340db62cad4fa3e8ddcd940868576270137f96d3884837bcd8e2246046d64e35a2ee9c0fca0b7ade9e0b0c6f5cc1e31e9f38b1993882f8c8263b834f51e5a64da820f08baf324b661714425f26febe2bf53e3738707fc9c38a91b77acfecc7779c7744ae072ce34ba2ac8cc7399454cc7ebb279d0b952f5aad516011831774c4803f608329aae63349a59c19475b540f3e41156d56bcb1eb6afaeab1e062a68151708599ca6b9d076de284c8175a945f43b0a748d3a4220482befd2a688a5f8d278f176a800fcf82488c31b1ddee28af207ad18c188d169177b111a49280e9811cc52f07f9864e658c3abb0e3df463b44a262bfd21c75029a73b643194acfa2abaa5085b68e99a06a4fb71682f29755e8f9d91af12b150dfb7d9bc71ea01a94d72f664a756d1540025462a156618a71fa58cc256c2bcf0fa9954be618bb456ea9ad9bcfc09ed6a383aa5677a7f9b2e81669271e979bc6584330ed49f0eeb0a6169d17a0588e5e79ab463bde03539a3897a462cdfd8cdf56b41d3747f0d8ecb407e506b73860c60ef8b6b678984b79cf9189c28ab1e66cfa77b7021195d22fe4263e725a80b5578574951841ea855b5f8cfa04b434ea5b83b136715271f57645cb442d0f4ff2c3881037f63778debab67234d677e435ddfd390592a474eaa95fe06a721808619f2db3cd1616d8785c3b3cf3dc1c52be073a241ef0f3b8a3ccba624bb22ee92b75e2056f212658b4537891724f5828362eb6a47c5ff23d969bda71ea1999ebdf12ec440f9c8e02a61c8a60521a3677f4de1526913de8e266a83457f76bcd600c9c315186745c0b61ece77dece104178ad1686a42f4b5639d59840708ae064cf4d993fca2e092957b6f03a116bb01ac9e403e185308d2566012669cea2017bf3996971c05d26b561995ab57abaeebfe16169f6e4212780377b165c113a3a453f092260577bd9c61bf11d57b3a2c049b05ae37a03d4eed5a8c258d30b5affc36e88bf68bb89cb46a4ca57180279f745b4fde9be5728c559e0f6d2a25945b310655263fba0d3ba723c45a9607f2daac915de3d493cc51ef3f10352a32d753b57d89bf7089f8bd5015446bee237f0e0fb33b9278e27b65fbbd6f95be5f29c0d6dc0261b34f775dac394d5fcf12c4ed9fbfd8ac24220388e2e2aa91b394fe33e15c54fe71276d40a75ec7f696903931c2f41e4df6799c0cb4d3854e1acac3d65e45ecf6e43152cd369ba0913e07ac83b5dd6846a6feeafc1467793908f47b248dc4f3dd6d7e641941d26f50edd1eaf7a1f6f8eef0cf3afacb8c27228ad2de55bb50b018c4a616418a74cb3a768dc4423e9de1131dfd32d6bddc0f4a5d388dd335e149b8026f4026bdb976bd2886df421e2c5c1638d3219fb5ee767b950480752b63d4e6e6d3dad1388fb8c2f2458ffc09b1290dd76af4fd84a3c8e993060569f3c0c18d16271818ab155117e14ae35eea3c1801e5267e248d328a6999942926b8d10751c0d413f2a02894b154027494340c60d2bd84aa41e8a6e2224504b53127c6131c4c5babcbe8cbe28f55aa7374ddd397ab72dce3f8dac5d387af286909f915cd9544ba3a1dfcc0cea980aef0c340be2fc95f5e3163a598707947dc24bfabc62f44ffa2fe475d402d065ab8b21f94543f1f45ef49ebb5b2a2a186f12945b373de95d4034cd63eda0662e4405c50159f4fe3b0f97e72abbe18e710d7a34b6e8b8a0a2ffd861cc62032239b69abb4243b48f8d9f03aecc1713a5cc603157f77baf1fc7c0a17b639fa7ac09fc4780fd99dce54222c4243b438b2df4c6571fb028559f8dda2e85b451a0842a9b76e074b8805e0bfb18164b18f6999b9212160c013349b3b7df2eaf9d7e4e57c053f097b66455e941951d4437e3591185d81f69ee26af88a6f4c87f71aef01394813b35f59f23733abf858c24cf8dcc6ca1653dc759b691c65b5b1017d1424e014879977e2407963632e7c016a5c1eadd64430370d4e1e519b94b4801e0465f9452774e1cebd842cd965d3ea6f60b09f3349870405e6b1b18b5abccb04f95c75ef0b3915010a2ae1d7be4c9d14b73ee987cd06f283464291c5cad6450c4d0325ede71edf7c5b6a59b89d6f6f6722e7c72704e7dc817d9ba5c5319d49a0e9cad1e16172b3e34d0801a91c644698aec0d0232df7c1c3a0ef08ffdde0e9c9285c93fae69b6dce801195e4288ca2f040efb3634ee6c49e379a3e492b453bacb84328f8cac21fb59dd0e946e54c0ac25fe883e9b1412e330f580e9d425bda2ef94cca8154cc28323bfbae2450c31868f3ea114f95c544788270714fe8d954fb00e2e2ed97d2400ecb681823e68f8226366ec0648a96cbb696a3c248b1eb4d6b98ccf9484d2b180cf4ac2a4051ed33f2d0b6dc2a80efc73eea7ec28a97f9470994076f0e322288e6842c3ad44b160d5aa1d1f266f406d5b477c26a53f55f3d81ada919b181ef1e5645974d971c0c225262b27a1ead1558843957c662eceaaf0f1e5d9dccff188ea6228636284cddf17dc14d2b9bf9d9d52de357ae6521055b45f9b845245ca9166b66f5d197cf5f17310ad15d9bb03249dc17c184b6e6b6a96b158850809535ac6ec730ea788afa3d21d16e358d9d5b494b2710e8b9c239759943fcc6855f28267b0945a9f74829f9c73074572f94d96c3363cd241b65568c2a5107c9f0fbf45676509a365d2580aac33827f03239b91526d785830e794afef8c50c45f3a5b08446264bd652ba9384142127793fd3304cd918323e97e328c35318dc45666bff5268d0c89fcf83de830f9e75ba4374d772bf5163afc76258386c37621a49f9427b4de1b1bbc33c76b0702929236ce27406ae5d0908dd23612cbd5ef2a58532bdc69fe3a932857d7662a737ca4f341ae45685e3df55e1f71be743222f5f882201dd27b9fdbc198508c7719fce60f582c34f16487f68fbce5b9fe33bedb86fdb7b233de7934d1f81a4041de830c3ca8dfcfbf2251539f21d48386ddcc1d2de34a5ed4e80ecd2799d14468c4460807c07e9f9edf200f98c55523b63338dc9c4a1cc6d01bdf1cfe1a07e4315adf34f95d9110d70a984a937a0e9861d0f73418c0eba88df5605a54879382858e55cd4df995f6333659722f46ec8266baa65b20eb5eeaf0bd0fd7bb26c1ffd6850d0e2aa40462677d829e798b29a83de87ee4c90655ceb7c249c237e02a3fb1444d25a9403b75f5003f6ce4d9b9b39880744dbcafbb410922d47f8981057ddb48cc7791ef11e87cea39297b8057ac230c8fc433611b8975556432d46a534bff9eacff6b42a0eb17d933f76d1c069150dbb5a33d6e4aef414c824fb0f06a8f7abfde2e3400972064b3cb7ccebec5b7a6545fcdc62ad07f0fea11d59da1418e0c07b0d9fb111e058330fc91cad9ac1a3911f0308dcc6a7238b91de66a25680bebc23ccf7f92286f75ef005276f159ae4c21a1a7f6347b94f714b37fa673d78849c0b42853a8dc562fbd68cb73eb0dff62e74dabe06f7b44b64ec77baeb9a364a4f42e7b36179c266e621e8f9982e22e9645a4eebd1fa3c4ba5edccd949782bd67bd4aa6b2fb45b9d20e0ac5d0343cbbcf9f532b86dd0d2002dd2a397d3e067f537411703085fff3d25f850b802ddb7c82a8741c530ec3680b2e3d40eca2e0cfd0d0913c978e3d1136ea2ec3d2615431281c0ff81fcd000fc6aa3675ace0a773ed2010b2ab20fabcdabad124102b6f6b58cd92d264e7b1f410298948fed4200fd8d4f846bad5a6869e07660ceb1c357b68f6cba96d34e1c501fbb4ea9cd764e0ecbcff20e4dff51ef87cdf2bb636257a8dbe6e243a06f71ed8e048608f2bf536eb2094990b12b7facd5268c8c78e99abd5100314e413315d19e1b5c3cd914a4c1e07f474f3a759a892530d12f33737c60c35a6a7ff05b85e1122a6496d1d144bdb2e0f656bcd9b52c373f3aa91d1cb06f4f22853da7d4244ba7361f6a88a50ea1bb1de17cb7e4dab451f6065d78516de9056af535248381825d1ed119319ea305668f8ea73b3a162c4532d0dec8e2e6a185e5ca08bb61ee6975d06b8283a02a2472cb44f67e8c7bb18ec5317677fecf6731c6498192dd28105f4b0a21287d81e6f823d3ecc737688a6bce5c5fbba93adbf3a49928a4cc5724b98fc0c79ef5de5e994f6171e977e3d6d43a66712afa1b46375b0689be1e974f1e3a7e4696879e9c7a6e5db5c7c44ad4319f88e12e49727082d8a3ed25c5ae5b27fc9267fcee3733bb301b7b8728f9ce5f5ba91b1bcebd65157d6970f8a07850c78a940466a51ae31a1e9521f4aa26669af14be91b3c6c78d4fb0d89388cbbeb225a757778ff043edebb4d378cbf435f7bcbaee28fd63e1b96e8d454c71c9602982e3dccedaa3f2e4855de688850e36afef0882def68e9c6a518a4d2a43d77ad3a778c1d6f051be2889441fabce6f60c6076745ee74b2a827670078f33506112b0700b707a16d32c1cbea3d5ab3021ad8379703984224241f5b61b9221cf4c35361c1dc5d7e0ed504dce0ebe04bc7a899b79e06f6584e0f1f6e40a535d7b33aad620d6ebe517122a01c7e69fe6cc8f0c203516bc5761cfb57516a37f66b894f64438903540f7808994d5f2b3814826f185d96b8b12df134d313457bb02889622e0d0ed75cf0cbc7ee62dd1a24e8fae18b30bd4309a1c06191139e2bf8490f1287a521df945df19e5f48ddf440f0d99159177e784af1ce4208a93afe307cb7ad58cf671050d4b8324781869795205759e9210897d9185eeaf55e07ddcb1b5d3a279a77a1f2fc7a47efdec9063ba9951277d5e8bf9e6d26de5bf41be350c32c43860209f6daa92847a4288e60eed029728fac833577b5af905e78dc6c4a449b07c7a2a3937f5c305250d35cf94b8175f0acf286959088f88daaa978be8e974345027a0b0908be397ea945374f177b580260828542ccb78328024f6afca6cbc5ff0c89e2a13d06c93ebceb5b173aeb5d59f2d2cebea3e8572c6743fdef96eb056ddfe57f3550e2add365e6e223ddb40b147018bcd582d585cdb136b02bde41b258044fe2332a7898cc1b44444eebf2cec76fe494d2a96275a950b8dca42568bd9b54d3385877d9ecf1d4ae978c05ba1db802be3ee64c8c34cf940d0629118220abe3d1a3ca189ae4eb44a080f81d564336c71a365134bf64932eda38ac624b8f3234b61bd995fd3998f937304e9b4753e7c9bfd643c890b0359cbbfb497e5cbe291010d75d32e170ba676740aca0b2bdbb298c0707924f1ca93a2ddcc66d41f4f283ecb2953ec7e784a17d66e329869cff3f6604aa00e38211af1ef2cd98c88175dcc78e1cc43c4b1a02775000641b723d0f42e8f10e47eac75bb856049beb70bc5d7563bceb7dfc4806eaf95c483990181bb43a67d9175749e139413dc446977377d4345cd469f7903dba4befb4786fa2d4cc2f882f40f4cdf3570f32b72fff170b3852460a7e71ecc37182ab98c5dcaf4cd3aa0ddcc986abd8d0dd7f08db90a7ad4f497f484bf6ed7288dc2b929aeb4cae910a448638f1670908fba915d4ece079421e6a8d39a2a43873dbcc577bd257c2488344ab19de7b0f37f3662b2e65ae685b201c01753880559611448191041b6ccae985ed58fa0c1b5df4bddd62b9ae97bb6f15b6d77cc4ac95ccdb8bd648202164e63e549d067e28313a103e53a762ca52b3b55fcbbad1da1a4a00520de9931dff4a7750b507f31deb1fa0e528d85fde3c2f6c35aa888b0fc52f24f028a7ada347b97c3df0820caf039e45f3f3e01816caeb2187914fa08e75314a74f2e8bca93dce7a0b833ce4b5d047291054d54c00ef44e3c8a9b2ac26be217ab86f9cf5e2889af24c4761c5aa2a203bc37b41da24e18b9ffdc2cad0e3ec9c5a2d6c7525633aca5818d482b6378568e791d67301280fc7befa609425166a8917de88c5712f23967601219559d0b1748514c0bf3abeb6583b05a44676f8f3d584bde5e452a7eafe4ff56bb3815fd9b68ce2e4bd8dea419569b98924bfa9bdb16114d0b5a0c92741e6b2cf9ec1fc97b97640b5b40090f77e795feab78c15d0d0cdeff736c6fd1f9b83e3eef3b96eb476eba2c872782a4af6ee8477a5ffd7ed99245fb5b936ea5168d9e3d4e9d327e3b97f3a26587f1329f73ec3f59a7b6a22e116641d26e5e5299dec6d8dd7fc673f88754cd042c0e3cad8349e9dc3f1861eefd425f9206772d38e66a28056541da48e5f930d053358fe8921ce13a7b1725d65ed7b642ec7d8366ee9cf210e43d6e104afca934393f3d18e41a94c4707abd38673065628a0467a2bfd201a1c4f2c7ea8a61ce0882856a50e1a6be7dfd3925221f71029d8f3297dbecc7929a8515fc75cddd8fa067d8c5e60920fb9a18c841813f2c12d60401cb28325f960ac87b6d8cf189fbbfa6ebcd74750e71d8cf19c020fb40a51b5672c1292664f3a31abb4bae8cdc8ea5b8ae586be3d961b30e4b2c5bb4d52ae8903133db96d264ae6db03f2acb81f5e87fec04a42d8000d43c1d087227e5db6dfd351b3ca90e3292801c3f3058c70d536df6935be143009b5a559acf163eb3f5d86e870098cdb395d00c247fb7b0cf757142f6aa6ed54302e9c9ee088f35a40be49fe754695e30fd470e19b61cf25b4fa3e7ed4fde7d84c8199707accd7fd2a8ece077c26b2a1bb96595199827521a775618d7ef86ef0a8b70b55c44984eca2f96f7386d5898002ac95d019048ae2f1a9b0debbb9732514c121d2099d440bee55e945cd74cf085154fda6aa65d760a673315123a0d2a72b3777d8ebfce4608b6b4b812a04520abeae5a18a7cfa1055c0852435e6646e5f827fc7e3a7cd3c99f9d7e8baadf573428b9780ce0fcd709ea4e9e1406f1785bc10b984b80a0d8e46b1c55d1bf37987fe49f7dae4a9ca2e4c2186b1d31f4b869e29e6251b8ef743ab3b3ec2934584b95690bc76a839e5a1f324daaedaa3866a44ff8eea51214c66c5f6b8e281805535df924e241c8c05a209c6543c187cb00a9989963ab46a83ce0f7d3be888837153843dd709b39f515e5fb97ba3c9784bcbed9f9e0bfa3f799ce910d7b0ad07b6ffaaeabb34becaf00ab00b1854400193953b74c228664eee7fc6712aaf0ff927168565faff3628d0abf324ff40c7ec39085f76122175d74e38e5d07b04b1dba30d3dca315130f5b5700df5116e13c76ee65e4912e7559b53e07b8dda6b1ec6cf9373fb14cc50ffb648c81d776acd03b028e6161abe227ca9b41e65dfde2ed75ed82cf1ef439d6fefd210a6de2dc29083227932e0531fa150db0e434da413a43142ed244afc1e6e26eb271d54326d1c736538d68363a9782d8e3f16a0b36e0a7c107eb0e233eb1db54ce54a55cd97cc4742e64b95fdabd34f6c53758f672787943e50a95d7738dae260d04c06fb21752f9e6bf2b16ee3f3a9cab13026141021f8008cf389d5425fe86e7d93ad45c736043577f97636d827810f93bd2c5ff77b96c22ab4b4c335d80fab8e40fe85693057414e8e8a1f5b893c2ae5154550840a904a134c9cd77b8501bc59fa79c2fc19ddd3d",
"iv": "bce8e1e081ee4def6001ddaccd3afecc",
"key": "8e1e7e7cc9ff2457deda3fb012b1ec65a042cd08e1264f83a706bc5fdf12a562"
The decrypted text is not clear, it gives me something like this
���\��n%�Вl��v+\"�I���l�+��R�_�}��`}��g���ӄ�_Pr�������D���A�[�*�
thanks for helping, mention me if something is unclear.
the problem was the conversion of hex String to bytes, the iv string, the encrypted CipherText as well as the key string weren't converted properly to bytes.
In addition to the PKCS5Padding that must be applied in the Kotlin code.
here is the functions used to get the original key and iv of encryption :
fun toByte(hexString: String): ByteArray? {
val len = hexString.length / 2
val result = ByteArray(len)
for (i in 0 until len) result[i] =
Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).toByte()
return result
}
fun setKey(myKey: String):SecretKeySpec {
try {
var key = toByte(myKey)
key = Arrays.copyOf(key, 32)
var secretKey = SecretKeySpec(key, "AES")
return secretKey
} catch (e: java.lang.Exception) {
throw e
}
}
//finally Decryption
fun decrypt(cipherText: String, key: String, IV: String): String? {
try {
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
val keySpec = setKey(key)
val iv = toByte(IV)
val ivSpec = IvParameterSpec(iv)
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
val text = toByte(cipherText)
val decryptedText = cipher.doFinal(text)
return String(decryptedText)
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
return null
}
For the NodeJs server, everything stay the same.

Android Keystore multipurpose key generation

I'm trying to generate a RSA key pair for this pruposes:
val purposes = PURPOSE_DECRYPT or PURPOSE_ENCRYPT or PURPOSE_SIGN or PURPOSE_VERIFY
And this is my key generation code:
val generator = KeyPairGenerator.getInstance(
KEY_ALGORITHM,
ANDROID_KEY_STORE
)
generator?.initialize(
KeyGenParameterSpec.Builder(
alias,
purposes
)
.setDigests(KeyProperties.DIGEST_SHA256)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.build()
)
generator?.generateKeyPair()
However when I use this purposes the decrypt does not work and throws an exception:
InvalidKeyException: "keystore operation failed. Incompatible purpose."
But when I try just encryption and decryption, keystore does encrypt and also decrypt perfectly. this is the purposes that I use for:
val purposes = PURPOSE_DECRYPT or PURPOSE_ENCRYPT
These are the methods for encryption and decryption:
private fun decrypt(cipherText: String, alias: String): String? {
return try {
val privateKeyEntry = getGeneratedPrivateKey(alias)
val output = Cipher.getInstance(
"$KEY_ALGORITHM_RSA/$BLOCK_MODE_ECB/$ENCRYPTION_PADDING_RSA_PKCS1"
// ANDROID_OPEN_SSL
)
output.init(Cipher.DECRYPT_MODE, privateKeyEntry?.privateKey)
val inputStream = ByteArrayInputStream(
android.util.Base64.decode(
cipherText,
android.util.Base64.NO_WRAP
)
)
val res = String(CipherInputStream(inputStream, output).readBytes(), Charsets.UTF_8)
res
} catch (e: Exception) {
e.printStackTrace()
null
}
}
private fun encrypt(plainText: String, alias: String): String? {
return try {
val publicKey = getGeneratedPublicKey(alias) ?: setupKeyPair(
alias,
PURPOSE_ENCRYPT or PURPOSE_DECRYPT
)?.public
val cipher = Cipher.getInstance(
"$KEY_ALGORITHM_RSA/$BLOCK_MODE_ECB/$ENCRYPTION_PADDING_RSA_PKCS1"
// ANDROID_OPEN_SSL
)
cipher.init(Cipher.ENCRYPT_MODE, publicKey)
val outputStream = ByteArrayOutputStream()
val cipherOutputStream = CipherOutputStream(outputStream, cipher)
cipherOutputStream.write(plainText.toByteArray(charset("UTF-8")))
cipherOutputStream.close()
val encryptedText = outputStream.toByteArray()
outputStream.close()
val res = android.util.Base64.encodeToString(encryptedText, android.util.Base64.NO_WRAP)
res
} catch (e: Exception) {
e.printStackTrace()
null
}
}
So what is the problem? How can I make a multipurpose keypair in Android keystore?
Probably you have your own custom variables for purpose keys
You should use KeyProperties in this line:
val purposes = PURPOSE_DECRYPT or PURPOSE_ENCRYPT or PURPOSE_SIGN or PURPOSE_VERIFY
like this:
val purposes = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY

KeyStoreException: Signature/MAC verification failed when trying to decrypt

I am trying to create a simple Kotlin object that wraps access to the app's shared preferences by encrypting content before saving it.
Encrypting seems to work OK but when I try to decrypt, I get an javax.crypto.AEADBadTagException which stems from an android.security.KeyStoreException with a message of "Signature/MAC verification failed".
I have tried debugging to see what's the underlying issue but I can't find anything. No search has given me any clue. I seem to follow a few guides to the letter without success.
private val context: Context?
get() = this.application?.applicationContext
private var application: Application? = null
private val transformation = "AES/GCM/NoPadding"
private val androidKeyStore = "AndroidKeyStore"
private val ivPrefix = "_iv"
private val keyStore by lazy { this.createKeyStore() }
private fun createKeyStore(): KeyStore {
val keyStore = KeyStore.getInstance(this.androidKeyStore)
keyStore.load(null)
return keyStore
}
private fun createSecretKey(alias: String): SecretKey {
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, this.androidKeyStore)
keyGenerator.init(
KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
)
return keyGenerator.generateKey()
}
private fun getSecretKey(alias: String): SecretKey {
return if (this.keyStore.containsAlias(alias)) {
(this.keyStore.getEntry(alias, null) as KeyStore.SecretKeyEntry).secretKey
} else {
this.createSecretKey(alias)
}
}
private fun removeSecretKey(alias: String) {
this.keyStore.deleteEntry(alias)
}
private fun encryptText(alias: String, textToEncrypt: String): String {
val cipher = Cipher.getInstance(this.transformation)
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(alias))
val ivString = Base64.encodeToString(cipher.iv, Base64.DEFAULT)
this.storeInSharedPrefs(alias + this.ivPrefix, ivString)
val byteArray = cipher.doFinal(textToEncrypt.toByteArray(charset("UTF-8")))
return String(byteArray)
}
private fun decryptText(alias: String, textToDecrypt: String): String? {
val ivString = this.retrieveFromSharedPrefs(alias + this.ivPrefix) ?: return null
val iv = Base64.decode(ivString, Base64.DEFAULT)
val spec = GCMParameterSpec(iv.count() * 8, iv)
val cipher = Cipher.getInstance(this.transformation)
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(alias), spec)
try {
val byteArray = cipher.doFinal(textToDecrypt.toByteArray(charset("UTF-8")))
return String(byteArray)
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
private fun storeInSharedPrefs(key: String, value: String) {
this.context?.let {
PreferenceManager.getDefaultSharedPreferences(it).edit()?.putString(key, value)?.apply()
}
}
private fun retrieveFromSharedPrefs(key: String): String? {
val validContext = this.context ?: return null
return PreferenceManager.getDefaultSharedPreferences(validContext).getString(key, null)
}
Can anyone point me in the right direction ?
I had similar issue. It was all about android:allowBackup="true".
Issue
This issue will occur while uninstalling the app and then re-installing it again. KeyStore will get cleared on uninstall but the preferences not getting removed, so will end up trying to decrypt with a new key thus exception thrown.
Solution
Try disabling android:allowBackup as follows:
<application android:allowBackup="false" ... >
I encountered the same exception/issue 'android.security.KeyStoreException: Signature/MAC verification failed' on Cipher encryption 'AES/GCM/NoPadding'.
On my end, what helped to resolve this issue is to create a byte array holder first, with size that is obtained by calling Cipher.getOutputSize(int inputLen), then calling the doFinal overload Cipher.doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) to set the ciphertext in your byte array holder.
private var iv: ByteArray? = null
fun doEncryptionOperation() {
val keyStore = KeyStore.getInstance(PROVIDER_ANDROID_KEYSTORE).apply {
load(null)
}
// Assumption: key with alias 'secret_key' has already been stored
val entry = keyStore.getEntry("secret_key", null)
val secretKeyEntry = entry as KeyStore.SecretKeyEntry
val key secretKeyEntry.secretKey
val plainText = "Sample plain text"
val cipherText = encryptSymmetric(key, plainText.toByteArray())
val decrypted = decryptSymmetric(key, cipherText)
val decryptedStr = String(decrypted)
val same = decryptedStr == plainText
Log.d("SampleTag", "Is plaintext same from decrypted text? $same")
}
fun encryptSymmetric(key: SecretKey, plainText: ByteArray): ByteArray? {
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, key)
iv = cipher.iv
val len = plainText.size
val outLen = cipher.getOutputSize(len) // get expected cipher output size
val result = ByteArray(outLen) // create byte array with outLen
cipher.doFinal(plainText, 0, len, result,0) // doFinal passing plaintext data and result array
return result
}
fun decryptSymmetric(key: SecretKey, cipherText: ByteArray): ByteArray? {
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val tagLen = 128 // default GCM tag length
cipher.init(Cipher.DECRYPT_MODE, key, GCMParameterSpec(tagLen,iv))
cipher.update(input.data)
val result = cipher.doFinal()
return result
}
Additionally, using AEAD, don't forget to call Cipher.updateAAD() in ENCRYPT_MODE, and set the same AEAD tag in the DECRYPT_MODE. Otherwise, you will encounter the same javax.crypto.AEADBadTagException.
When you change your authentiation tag length from iv.count() to 128 it will work.
I had a similar problem. I had an application where the admin and an ordinary user could log in and both of them had a remember me option. So, when the user previously pressed the remember me option, the program needs to fetch the encrypted password, decrypt it, and put it in the input field.
I was storing both encrypted passwords with their initialization vectors in the SharedPreferences file but when I was trying to decrypt them via Cipher (The secret key was stored in the AndroidKeyStore with the same alias for the secret key) it was decrypting one password but was giving me the same error as yours when I was decrypting another password.
Then, I used 2 different aliases for these 2 passwords when I was encrypting and decrypting them and the error is gone.
Github gist: Code example

Categories

Resources