0
\$\begingroup\$

Here's what I could comprehend in C code:

  1. Generates a key using PBKDF2
  2. Generates an IV which is MD5 of PBKDF2 key in step #1
  3. Does AES-256 encryption on customer-id - which is one of the output
  4. 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());
    }
\$\endgroup\$
  • 2
    \$\begingroup\$ Code review questions should normally be considered off-topic on stackoverflow. The main goal of SO is to be an archive of solved problems that programmers are likely to encounter. Most code review questions are only useful to the original asker, and will likely never be useful to anyone else. \$\endgroup\$ – President James Moveon Polk Nov 20 '19 at 14:50
1
\$\begingroup\$

You should move the first piece of Java code into its own method if it isn't already, as that would make calling and testing it easier.

Also, your getSalt() method's catch block only prints the stack trace in case of exception, but still returns the value, is this intended?

\$\endgroup\$
  • \$\begingroup\$ The first piece of Java code is copied from its function. I am not worried about such things at the moment. Rather I would like to know if I have done enough to replicate the steps performed in the C code or if I'm missing out anything. I could see a RSA encryption in the C code where it gets a cert file, read its key and does RSA public encryption. Is that possible in Java too? I mean to use a stored key and use it for RSA public encryption? If yes, could someone share any inputs as to how to get it done? \$\endgroup\$ – stack123 Nov 24 '19 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.