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)
Related
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 ?
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
The Android docs give the following snippet for how to encrypt a message in AES:
val plaintext: ByteArray = ...
val keygen = KeyGenerator.getInstance("AES")
keygen.init(256)
val key: SecretKey = keygen.generateKey()
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, key)
val ciphertext: ByteArray = cipher.doFinal(plaintext)
val iv: ByteArray = cipher.iv
I get this error when implementing this method:
Unresolved reference: Cipher
So it appears the 'Cipher' object isn't native, however I have no way of knowing how to import it by following the Android docs. How do I set up my project to be able to use 'Cipher'?
javax.crypto.Cipher is part of the JCE and should be available. Does an import javax.crypto.Cipher not work? Then maybe something is wrong with your environment.
I'm not sure if using that Cipher is necessary, and if the solution I'm providing is the best approach, but I was able to use AES for encryption and decryption using the following code for a text input, means a String:
ENCRYPTION
// text
val aesEncrypt: AESEncrypt = AESEncrypt()
val encryptedByteArray = aesEncrypt.encrypt(text)
val baos_text = ByteArrayOutputStream()
val oosText = ObjectOutputStream(baos_text)
oosText.writeObject(encryptedByteArray)
val encryptedText = String(android.util.Base64.encode(baos_text.toByteArray(), android.util.Base64.DEFAULT))
// key
val key = aesEncrypt.mySecretKey
val baos = ByteArrayOutputStream()
val oos = ObjectOutputStream(baos)
oos.writeObject(key)
val keyAsString = String(android.util.Base64.encode(baos.toByteArray(), android.util.Base64.DEFAULT))
// initialisation vector
val iv = aesEncrypt.myInitializationVector
val baosIV = ByteArrayOutputStream()
val oosIV = ObjectOutputStream(baosIV)
oosIV.writeObject(iv)
val initialisationVector = String(android.util.Base64.encode(baosIV.toByteArray(), android.util.Base64.DEFAULT))
DECRYPTION
You must save the key, initialisation vector, and the encrypted text in order to decrypt it back.
val initialisationVector = ... // get from wherever you saved it, local db, firebase...
val bytesIV = android.util.Base64.decode(iv, android.util.Base64.DEFAULT)
val oisIV = ObjectInputStream(ByteArrayInputStream(bytesIV))
val initializationVectorIV = oisIV.readObject() as ByteArray
val encryptedText = ... // get
val bytesText = android.util.Base64.decode(encryptedText, android.util.Base64.DEFAULT)
val oisText = ObjectInputStream(ByteArrayInputStream(bytesText))
val textByteArray = oisText.readObject() as ByteArray
val key = ... // get your key
val bytesKey = android.util.Base64.decode(key, android.util.Base64.DEFAULT)
val oisKey = ObjectInputStream(ByteArrayInputStream(bytesKey))
val secretKeyObj = oisKey.readObject() as SecretKey
val aesDecrypt = AESDecrypt(secretKeyObj,initializationVectorIV)
val decryptedByteArray = aesDecrypt.decrypt(textByteArray)
val textAfterDecryption = decryptedByteArray.toString(charset("UTF-8"))
EDIT
AES helper class:
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
class AESEncrypt {
var mySecretKey: SecretKey? = null
var myInitializationVector: ByteArray? = null
fun encrypt(strToEncrypt: String): ByteArray {
val plainText = strToEncrypt.toByteArray(Charsets.UTF_8)
val keygen = KeyGenerator.getInstance("AES")
keygen.init(256)
val key = keygen.generateKey()
mySecretKey = key
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, key)
val cipherText = cipher.doFinal(plainText)
myInitializationVector = cipher.iv
return cipherText
}
}
AES decrypt helper
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
class AESDecrypt(private val mySecretKey: SecretKey?, private val initializationVector: ByteArray?) {
fun decrypt(dataToDecrypt: ByteArray): ByteArray {
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
val ivSpec = IvParameterSpec(initializationVector)
cipher.init(Cipher.DECRYPT_MODE, mySecretKey, ivSpec)
val cipherText = cipher.doFinal(dataToDecrypt)
return cipherText
}
}
Do tell if you still need any help :)
I had this problem when trying to decrypt an encrypted string. I had read a lot and also search for answers from Stack Overflow, but nothing works. You can see code I attach, it's not complex but the problem makes me confused. I'm using Kotlin, and yes, it's for Android.
private fun generateKeyPair() {
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE)
keyStore.load(null)
if (keyStore.containsAlias(keyAlias)) return
val keyGenerator =
KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE)
val builder = KeyGenParameterSpec.Builder(
keyAlias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setKeySize(4096)
.setDigests(KeyProperties.DIGEST_SHA256)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.setRandomizedEncryptionRequired(true)
.setUserAuthenticationRequired(false)
keyGenerator.initialize(builder.build(), SecureRandom())
keyGenerator.generateKeyPair()
}
fun encryptApplicationKey(
data: String
) {
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey())
val encryptResult = cipher.doFinal(data.toByteArray())
val encryptResultString = Base64.encodeToString(encryptResult, Base64.DEFAULT)
text_view_info.text = encryptResultString
}
fun decryptApplicationKey(data: String) {
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey()) //it throw Caused by: android.security.KeyStoreException: Incompatible padding mode
val encryptedData = Base64.decode(data, Base64.DEFAULT)
val decryptResult = cipher.doFinal(encryptedData)
val decryptResultString = String(decryptResult)
text_view_info.text = decryptResultString
}
fun getPublicKey(): PublicKey {
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE)
keyStore.load(null)
val publicKey = keyStore.getCertificate(keyAlias).publicKey
val unrestrictedPublicKey: PublicKey =
KeyFactory.getInstance(publicKey.algorithm).generatePublic(
X509EncodedKeySpec(publicKey.encoded)
)
return unrestrictedPublicKey
}
fun getPrivateKey(): PrivateKey {
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE)
keyStore.load(null)
return keyStore.getKey(keyAlias, null) as PrivateKey
}
When I debugged the getPrivateKey() function, it's return AndroidKeyStoreRSAPrivateKey object. I don't know if the problem related to the usage of PKCS1Padding, but when I'm using OAEP padding, there's no crash when run it.
Does the device affect the result? I have commented where the crash happens.
I'm facing with BadPaddingException while I'm trying to decode InputStream. I was able to encode/decode OutputStream/InputStream while I'm using jackson but when I tried to do with Okio it throws BadPaddingException.
getEncodeStream() and getDecodeStream() methods was working fine with Jackson but it seems that its working different with Okio.
Output of encoded file = FxGOXOwOWzBGMa7+u+E3TvNTOjFv/vKKsSt+Q1+QsedtluVa6sULFhOImRO+pYQp43h/HsrssNm0
UpxcC2cvbM4+ix9nH5YUfCK0NJjzT2iR9tJG8tXTrLSCz/B/6WEQ
#Test
fun main() {
val password = "password"
val file1 = File("src/test/resources/okioTest")
if(!file1.exists())
file1.createNewFile()
//create output stream
val outputStream = FileOutputStream(file1)
val encodeStream = getEncodeStream(password, outputStream)
val sink = Okio.buffer(Okio.sink(encodeStream))
sink.write("something to test something to test something to test something to test something to test something to test".toByteArray())
sink.emit()
val inputStream = FileInputStream(file1)
val decodeStream = getDecodeStream(password, inputStream)
val source = Okio.buffer(Okio.source(decodeStream))
val result = source.readUtf8()
Timber.d(result)
}
fun getEncodeStream(keyString: String, stream: OutputStream): OutputStream {
val keySpec = getKey(keyString)
// IMPORTANT TO GET SAME RESULTS ON iOS and ANDROID
val iv = ByteArray(16)
Arrays.fill(iv, 0x00.toByte())
val ivParameterSpec = IvParameterSpec(iv)
// Cipher is not thread safe
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec)
val base64stream = Base64OutputStream(stream, Base64.DEFAULT)
// Log.d("jacek", "Encrypted: $stringToEncode -> $encrypedValue")
return CipherOutputStream(base64stream, cipher)
}
fun getDecodeStream(password: String, stream: InputStream): InputStream {
val key = getKey(password)
val iv = ByteArray(16)
Arrays.fill(iv, 0x00.toByte())
val ivParameterSpec = IvParameterSpec(iv)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec)
val base64stream = Base64InputStream(stream, Base64.DEFAULT)
return CipherInputStream(base64stream, cipher)
}
#Throws(UnsupportedEncodingException::class)
fun getKey(password: String): SecretKeySpec {
// You can change it to 128 if you wish
val keyLength = 256
val keyBytes = ByteArray(keyLength / 8)
// explicitly fill with zeros
Arrays.fill(keyBytes, 0x0.toByte())
// if password is shorter then key length, it will be zero-padded
// to key length
val passwordBytes = password.toByteArray(charset("UTF-8"))
val length = if (passwordBytes.size < keyBytes.size) passwordBytes.size else keyBytes.size
System.arraycopy(passwordBytes, 0, keyBytes, 0, length)
return SecretKeySpec(keyBytes, "AES")
}