Currently I have been doing AES with CBC mode encryption but as backend change in requirement we have to change to to GCM mode with random IV generation .
currently I have this code :
static func encryptsData(parameters: parameters?) - (String, String) {
var jsonStr = DefaultValues.empty
do {
if let str = String(data: try JSONSerialization.data(withJSONObject: parameters ?? [:], options: .prettyPrinted), encoding: .utf8) {
jsonStr = str
}
} catch {
debugPrint(error.localizedDescription)
}
// Get Secrete key, iv of 128 bits
let iv = [UInt8](repeating: 0, count: 16)
let randomStr = randomString(length: 16)
let key: ArrayUInt8 = Array(randomStr.utf8)
// Encrypt Request Data with Secrete Key (AES)
let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs5)
let encrypted = try? aes.encrypt(Array(jsonStr.utf8))
if let encryptedMsg = encrypted {
let encryptedData = Data(bytes: encryptedMsg, count: Int(encryptedMsg.count))
let encryptedBase64 = encryptedData.base64EncodedString()
//Encrypt Secrete Key using Server Public key (RSA)
let keyData = Data(bytes: key, count: key.count)
let encryptedSceKey = encryptSecKeyWithPublickKey(key: String(data: keyData, encoding: .utf8) ?? "")
return (encryptedBase64, encryptedSceKey)
}
return (DefaultValues.empty, DefaultValues.empty)
}
Now , have changed the code for GCM Mode in the following lines :
let iv = AES.randomIV(AES.blockSize) //[UInt8](repeating: 0, count: 16)
var bytes = [Int8](repeating: 0, count: 16)
let randomStr = randomString(length:16)
let key: ArrayUInt8 = Array(randomStr.utf8)
// Encrypt Request Data with Secrete Key (AES)
let aes = try! AES(key: key, blockMode: GCM(iv: iv), padding: .noPadding)
else , remaining the same..But could get success through this as our encryption has to be in sync with the android/java side.
On Android end this is the encryption code :
lpackage com.jio.ngo.datalayer.network.encryption
import android.util.Base64
import android.util.Log
import com.jio.ngo.datalayer.BuildConfig
import java.nio.charset.Charset
import java.security.*
import java.security.spec.InvalidKeySpecException
import java.security.spec.X509EncodedKeySpec
import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
object Encryption
{
val TAG = "Encryption"
private const val GCM_IV_LENGTH = 12
fun encrypt(message: String): EncryptedRequest
{
val encryptedRequest = EncryptedRequest()
try
{
// 1. generate secret key using AES
val keyGenerator = KeyGenerator.getInstance("AES")
keyGenerator.init(256)
// AES is currently available in three key sizes: 128, 192 and 256 bits.The
// design and strength of all key lengths of the AES algorithm are sufficient to
// protect classified information up to the SECRET level
val secretKey = keyGenerator.generateKey()
// 2. get string which needs to be encrypted
// 3. encrypt string using secret key
val raw = secretKey.encoded
val skeySpec = SecretKeySpec(raw, "AES")
// val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val iv = ByteArray(GCM_IV_LENGTH)
SecureRandom().nextBytes(iv)
val parameterSpec = GCMParameterSpec(128, iv) //128
// val parameterSpec: GCMParameterSpec = cipher.parameters.getParameterSpec(GCMParameterSpec::class.java)
// cipher.init(Cipher.ENCRYPT_MODE, skeySpec, IvParameterSpec(ByteArray(16)))
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, parameterSpec)
val encryptedMessageBytes: ByteArray = cipher.doFinal(message.toByteArray(Charset.forName("UTF-8")))
val encrypted = ByteArray(iv.size + encryptedMessageBytes.size)
System.arraycopy(iv, 0, encrypted, 0, iv.size)
System.arraycopy(encryptedMessageBytes, 0, encrypted, iv.size, encryptedMessageBytes.size)
val cipherTextString = Base64.encodeToString(encrypted, Base64.DEFAULT)
Log.d(TAG, "cipherTextString : $cipherTextString")
Log.d(TAG, "cipherTextString 1: ${Base64.encodeToString(skeySpec.encoded, Base64.DEFAULT)}")
// 4. get public key
val publicSpec = X509EncodedKeySpec(Base64.decode(BuildConfig.apikey, Base64.DEFAULT))
val keyFactory = KeyFactory.getInstance("RSA")
val publicKey = keyFactory.generatePublic(publicSpec)
// 6. encrypt secret key using public key
val cipher2 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding")
cipher2.init(Cipher.ENCRYPT_MODE, publicKey)
val encryptedSecretKey = Base64.encodeToString(cipher2.doFinal(secretKey.encoded), Base64.DEFAULT)
//System.out.println(encryptedSecretKey);
Log.d(TAG, "encryptedSecretKey : $encryptedSecretKey")
// 7. pass cipherTextString (encypted sensitive data) and encryptedSecretKey to
// your server via your preferred way.
// Tips:
// You may use JSON to combine both the strings under 1 object.
// You may use a volley call to send this data to your server.
encryptedRequest.encryptedText = cipherTextString
encryptedRequest.encryptedSecretKeyString = encryptedSecretKey
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
} catch (e: InvalidKeyException) {
e.printStackTrace()
} catch (e: NoSuchPaddingException) {
e.printStackTrace()
} catch (e: IllegalBlockSizeException) {
e.printStackTrace()
} catch (e: BadPaddingException) {
e.printStackTrace()
} catch (e: InvalidKeySpecException) {
e.printStackTrace()
} catch (e: InvalidAlgorithmParameterException) {
e.printStackTrace()
}
catch (e: Exception)
{
e.printStackTrace()
}
return encryptedRequest
}
}
So, have to find way around like what Java end encryption is happening , not able to get what is the issue at our end.
failing decrypting in backend when using above iOS encryption code :
javax.crypto.AEADBadTagException: Tag mismatch!
Please help ....
Thanks !!
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi All,
I have issue with doing AES encryption with GCM Mode earlier using CBC which have to change to now GCM as change in backend system,
getting error "javax.crypto.AEADBadTagException: Tag mismatch!"
Code have used with AES/CBC encryption is :
static func encryptsData(parameters: parameters?) - (String, String) {
// Convert Parameters in Json string
var jsonStr = DefaultValues.empty
do {
if let str = String(data: try JSONSerialization.data(withJSONObject: parameters ?? [:], options: .prettyPrinted), encoding: .utf8) {
jsonStr = str
}
} catch {
debugPrint(error.localizedDescription)
}
// Get Secrete key, iv of 128 bits
let iv = [UInt8](repeating: 0, count: 16)
let randomStr = randomString(length: 16)
let key: ArrayUInt8 = Array(randomStr.utf8)
// Encrypt Request Data with Secrete Key (AES)
let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs5)
let encrypted = try? aes.encrypt(Array(jsonStr.utf8))
if let encryptedMsg = encrypted {
let encryptedData = Data(bytes: encryptedMsg, count: Int(encryptedMsg.count))
let encryptedBase64 = encryptedData.base64EncodedString()
//Encrypt Secrete Key using Server Public key (RSA)
let keyData = Data(bytes: key, count: key.count)
let encryptedSceKey = encryptSecKeyWithPublickKey(key: String(data: keyData, encoding: .utf8) ?? "")
return (encryptedBase64, encryptedSceKey)
}
return (DefaultValues.empty, DefaultValues.empty)
}
Please Help!!
Hope have made my point Clear!!
Thanks In Advance !!