Here's what I could comprehend in C code:
- Generates a key using PBKDF2
- Generates an IV which is MD5 of PBKDF2 key in step #1
- Does AES-256 encryption on customer-id - which is one of the output
- RSA public encryption on PBKDF2 key which is the second output.
Objective Need to send a request map to a third party with encryptedValue of customerId, sessionKey and IDDigest [SHA1 of customerId] and get the response.
The system where the request is sent should be responding with 00 if all the values in the request are correct. At the moment, I am getting null in the response body. To reduce your time & effort - aes_dynakey_encrypt is the method you can start within the C implementation
What am I looking for? I need somebody to validate that java code does enough to perform the steps implemented in the C code. I could see RSA public encrypt calls. I have done the coding after doing my research but would like the experts to validate it since I'm still getting a null in the response. Not sure if I am doing something wrong. Please guide
****************************************************************************/
* Name: generateSessionKey */
* Desc: To generate session key of size = KEY_SIZE bytes. This */
* key will be used as the secret key for AES 256 encryption */
* and decryption functions that follows. */
* Inputs: None */
* */
* Output: key */
* Returns: 0 for success and -1 for failure. */
****************************************************************************/
int generateSessionKey(unsigned char* key)
unsigned char keyData[8];
unsigned char salt[8];
int iterCount = 5;
/* Randomly generate key_data and salt here. */
if(RAND_bytes(keyData, 8) == 0)
{
return -1;
}
if(RAND_bytes(salt, 8) == 0)
{
return -1;
}
if(PKCS5_PBKDF2_HMAC_SHA1(keyData, 8, salt, 8, iterCount, KEY_SIZE, key))
{
return 0;
}
return -1;
****************************************************************************/
* Name: generateIV */
* Desc: To generate the initialization vector for AES encryption. */
* This iv must be the same for encryption and decryption. */
* So iv is generated as MD5 digest of the key generated */
* using generateSessionKey function. The decryption side */
* can then generate the same iv by creating MD5 digest */
* of the key, once it gets the key for decryption. */
* */
* Inputs: key - Generated by generateSessionKey */
* keySize - Size of key in bytes */
* Output: iv */
* Returns: 0 for success and -1 for failure. */
****************************************************************************/
int generateIV(char* key, int keySize, unsigned char* iv)
if(keySize == 0)
{
return -1;
}
if(MD5(key, keySize, iv) == NULL)
{
return -1;
}
return 0;
int aes_encrypt_text(const unsigned char* intxt, int clen, unsigned char* outtxt,
unsigned char* key, unsigned char* iv)
int outlen = 0, tmplen = 0;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv);
if(!EVP_EncryptUpdate(&ctx, outtxt, &outlen, intxt, clen))
{
return 0;
}
/* Buffer passed to EVP_EncryptFinal() must be after data just
* encrypted to avoid overwriting it.
*/
if(!EVP_EncryptFinal_ex(&ctx, outtxt + outlen, &tmplen))
{
return 0;
}
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
return outlen;
int aes_dynakey_encrypt(const char* cid, int len, char* encd, char* skey)
int rc = 0;
unsigned char* aesedId = 0;
unsigned char* encodedId = 0;
unsigned char* encodedKey = NULL;
unsigned char iv[16];
unsigned char sessionKey[32];
unsigned char encryptedKey[100];
char *certFile = NULL;
int rsaSize = 0;
int encodedIdLen = 0, encodedKeyLen = 0;
int aesTxtLen = 0;
int encryptedKeyLen = 0;
//RSA *rsaPriv = NULL;
RSA *rsaPub = NULL;
certFile = (access(CERT_PATH, F_OK|R_OK) == 0) ?CERT_PATH:
(access(CERT_PATH_ACR, F_OK|R_OK) == 0)?CERT_PATH_ACR:NULL;
memset(iv, 0, sizeof(iv));
memset(sessionKey, 0, sizeof(sessionKey));
memset(encryptedKey, 0, sizeof(encryptedKey));
if(generateSessionKey(sessionKey) != 0)
{
log_event(LOGCAT_POS, LL1, _HERE, "session key generation failed.");
return -1;
}
if(generateIV(sessionKey, sizeof(sessionKey), iv) != 0)
{
log_event(LOGCAT_POS, LL1, _HERE, "iv generation failed.");
return -1;
}
/* Encrypting the id. */
aesedId = (unsigned char*)malloc(len + AES_BLOCK_SIZE);
memset(aesedId, 0, len + AES_BLOCK_SIZE);/* Modified for PPM#117496 [cppcheck Error Fix - Phase 1] */
//if(aes256EncryptMsg(cid, encryptedId, sessionKey, iv) != 0)
aesTxtLen = aes_encrypt_text(cid, len, aesedId, sessionKey, iv);
if(aesTxtLen > 0)
{
if(base64Encode(aesedId, aesTxtLen, &encodedId, &encodedIdLen) == 0)
{
if((rsaPub = getRSAPubKeyFromCertificate(certFile, &rsaSize)) != NULL)
{
encryptedKeyLen = RSA_public_encrypt(sizeof(sessionKey), sessionKey, encryptedKey, rsaPub, RSA_PKCS1_PADDING);
if(encryptedKeyLen != -1)
{
if(base64Encode(encryptedKey, encryptedKeyLen, &encodedKey, &encodedKeyLen) == 0)
{
rc = 0;
}
else
{
log_event(LOGCAT_POS, LL1, _HERE, "Key encoding failed.");
rc = -1;
}
}
else
{
log_event(LOGCAT_POS, LL1, _HERE, "Key encryption failed.");
rc = -1;
}
}
else
{
log_event(LOGCAT_POS, LL1, _HERE, "Failed to read RSA public key.");
rc = -1;
}
}
else
{
log_event(LOGCAT_POS, LL1, _HERE, "Id encoding failed.");
rc = -1;
}
}
else
{
log_event(LOGCAT_POS, LL1, _HERE, "Id encryption failed.");
rc = -1;
}
free(aesedId);
RSA_free(rsaPub);
if(rc == 0)
{
strncpy(encd, encodedId, encodedIdLen);
strncpy(skey, encodedKey, encodedKeyLen);
}
free(encodedId);
free(encodedKey);
return rc;
Here is my Java implementation:
// Get the PBKDF2 key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(customerId.toCharArray(), RefundUtil.getSalt(), 5, 256);
SecretKey tmp = factory.generateSecret(spec);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] iv = md.digest(tmp.getEncoded());
IvParameterSpec ivspec = new IvParameterSpec(iv);
// Gets the PBKDF2Key RSA public encrypted
String sessionKey = rsaEncrypt(tmp.getEncoded());
LOGGER.info("Key: {}", sessionKey);
keyMap.put("key", sessionKey);
SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
keyMap.put("encVal", Base64.getEncoder().encodeToString(cipher.doFinal(customerId.getBytes("UTF-8"))));
return keyMap;
Salt function
public static byte[] getSalt() {
byte[] salt = new byte[8];
SecureRandom sr;
try {
sr = SecureRandom.getInstance("SHA1PRNG");
sr.nextBytes(salt);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return salt;
}
//RSAencrypt function
InputStream inStream = null;
try {
inStream = RefundUtil.class.getClassLoader().getResourceAsStream("refund.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
PublicKey pubKey = cert.getPublicKey();
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherText = encryptCipher.doFinal(sessionKey);
inStream.close();
return Base64.getEncoder().encodeToString(cipherText);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}