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 !!
I have an Event name: n_api_failure
Event Parameters:
1) api_status_code
2) api_end_point
3) api_error_message
On Firebase Console under Events, we are getting each parameter value in separate section. which is making us difficult to determine the linking between these parameter as for which status code we are getting the the error message and for which screen.
For example: for n_api_failure event
api_status_code: "100"
For above status code, respective api_endpoint: "myDashboard"
For above status code and endpoint, respective api_error_message: "Something went wrong."
but in Firebase console these parameters showing in 3 different sections with parameters values in a list with the count and user count column.
So in the logged long list of these parameter values how will be able to determine the link between with each other. i.e I could see "Something went wrong" error message in errormessage parameter section but not able to determine for which errorcode and for which apiendpoint(i.e controller) this has been logged.
I actually do not know how to add screenshot with firebase console in the post if that is allowed or not to make things easily understandable.
Thanks for Help!!