Ken
Ken

Reputation: 11

C++ equivalent of Java encryption

I have this following snippet from Java code that is used for encryption

public class DESUtil {

    private final static String ALGORITHM = "DES";
    private static final byte[] EncryptionIV = "12344321".getBytes();
    private static String key="1234%^&*";

    public static String encrypt(String text) {
        try {
            IvParameterSpec spec = new IvParameterSpec(EncryptionIV);
            DESKeySpec dks = new DESKeySpec(key.getBytes());    
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(dks);

            Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
            c.init(Cipher.ENCRYPT_MODE, securekey, spec);
            byte[] data = c.doFinal(text.getBytes("UTF-8"));
            return new String(Base64.encode(data));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decrypt(String text) throws Exception{
        try {
            DESKeySpec dks = new DESKeySpec(key.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");

            Key secretKey = keyFactory.generateSecret(dks);
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(EncryptionIV);
            AlgorithmParameterSpec paramSpec = iv;
            cipher.init(Cipher.DECRYPT_MODE, secretKey,paramSpec);
            byte[] data = cipher.doFinal(Base64.decode(text.getBytes()));
            return new String(data,"utf-8");
        } catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}

what s the equivalent of the Java encryption in C++?

This is related to Java encryption. But not sure what is the equivalent. essentially i would like the same output as Java code generates.the I tried to use Openssl to encrypt and decrypt,however it doesn't work,I'm have seen a bunch of examples of Openssl,I still didn't know what wrong I have done yet, the code was trying to do a DES/CBC/PKCS5padding encryption

int encryptdate(string plaindatas, string & encryptedatas)
{
   string EncryptionIVstr = "12344321";
   string keystr = "1234%^&*";

   const char* ivcstyle = EncryptionIVstr.c_str();
   unsigned char iv[sizeof(ivcstyle)];
   std::copy(ivcstyle, ivcstyle + sizeof(ivcstyle), iv);

   const char * keycstyle = keystr.c_str();
   unsigned char key[sizeof(keycstyle)];
   std::copy(keycstyle, keycstyle + sizeof(keycstyle), key);

   const char * incstyle = plaindatas.c_str();
   unsigned char in[sizeof(incstyle)];

   std::copy(incstyle, incstyle + sizeof(incstyle), in);

   int written = 0, temp;
   unsigned char * outbuf = new unsigned char[1024 + EVP_MAX_BLOCK_LENGTH];

   EVP_CIPHER_CTX * ctx;
   ctx = EVP_CIPHER_CTX_new();
   EVP_EncryptInit_ex(ctx, EVP_des_cbc(), NULL, key, iv);


   EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_PKCS7);

   if (!EVP_EncryptUpdate(ctx, &outbuf[written], &temp, in, sizeof(in)))
   {
       EVP_CIPHER_CTX_cleanup(ctx);
       return -1;
   }

   written += temp;

   if (!EVP_EncryptFinal_ex(ctx, outbuf, &written))
   { 
       EVP_CIPHER_CTX_cleanup(ctx);
       return -1;
   }


   EVP_CIPHER_CTX_cleanup(ctx);

   encryptedatas = base64_encode(outbuf, sizeof(outbuf));
   return 0;
}


int decryptdate(string encryptdatas, string & decryptdatas)
{
    string EncryptionIVstr = "12344321";
    string keystr = "1234%^&*";

    const char* ivcstyle = EncryptionIVstr.c_str();
    unsigned char iv[sizeof(ivcstyle)];
    std::copy(ivcstyle, ivcstyle + sizeof(ivcstyle), iv);

    const char * keycstyle = keystr.c_str();
    unsigned char key[sizeof(keycstyle)];
    std::copy(keycstyle, keycstyle + sizeof(keycstyle), key);

    EVP_CIPHER_CTX * ctx;
    ctx = EVP_CIPHER_CTX_new();
    EVP_DecryptInit_ex(ctx, EVP_des_cbc(), NULL, key, iv);

    std::string decodestr = base64_decode(encryptdatas);
    const char * ciphertextcstyle = decodestr.c_str();
    unsigned char ciphertext[sizeof(ciphertextcstyle)];

    std::copy(ciphertextcstyle, ciphertextcstyle + sizeof(ciphertextcstyle), ciphertext);

    int len;

    int plaintext_len;

    unsigned char * plaintext = new unsigned char[1024 + EVP_MAX_BLOCK_LENGTH];

    EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_PKCS7);

    if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, sizeof(ciphertext)))
   {
        EVP_CIPHER_CTX_cleanup(ctx);
        return -1;
    }

    plaintext_len = len;

    if (!EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
    {
        EVP_CIPHER_CTX_cleanup(ctx);
        return -1;
    }


    EVP_CIPHER_CTX_cleanup(ctx);

    decryptdatas = reinterpret_cast<char*>(plaintext);
    return 0;
}

the consequences of Java code which DES/cbc/pkcs5padding was

08yw6mx6giw/tzhQk3ivwQ==

while the consequences of C++ code was

e4CsOw==

any idea?

Upvotes: 1

Views: 1010

Answers (1)

Topaco
Topaco

Reputation: 49390

There are some errors in the encryptdate-method:

  • The sizeof-operator returns the size of an object or type (see here). This operator is often used incorrectly in the code, e.g. in the following code-snippet:

    const char* incstyle = plaindatas.c_str();              // 1)
    unsigned char in[sizeof(incstyle)];                     // 2)               
    std::copy(incstyle, incstyle + sizeof(incstyle), in);   // 3)
    

    Here you try to copy the content of plaindatas (which contains the plaintext) into the array in. In 1) incstyle is a pointer (char*) and therefore has a size of 4 bytes or 8 bytes (depending on whether 32-bit- or 64-bit-OS). sizeof(incstyle) returns this size and not the length of the string. Therefore, in 2) an array is defined which is generally too small and thus, in 3) only a part of the content of plaindatas is copied into this array.

    The array in is correctly filled with e.g. the following code:

    const char* incstyle = plaindatas.c_str();
    int in_len = plaindatas.length(); // Number of characters (without terminating 0)
    unsigned char *in = new unsigned char[in_len + 1];
    std::copy(incstyle, incstyle + in_len + 1, in);
    
  • When calling EVP_EncryptUpdate the plain text length is also determined wrong with the sizeof-operator (because the length of the array in has already been determined incorrectly before):

    EVP_EncryptUpdate(ctx, &outbuf[written], &temp, in, sizeof(in)) 
    

    Rather, it should be as follows:

    EVP_EncryptUpdate(ctx, outbuf, &temp, in, in_len)
    
  • There are further errors in the call of VP_EncryptFinal_ex

    if (!EVP_EncryptFinal_ex(ctx, outbuf, &written)) {...}
    

    which must actually be as follows:

    if (!EVP_EncryptFinal_ex(ctx, outbuf + temp, &temp)){...}
    written += temp;
    delete in;
    

    Here you have to pay attention to the update of the ciphertext length (written) at the end. In addition, the allocated memory for in can be released here so that no memory leak occurs.

  • For the-Base64 encoding the length of the ciphertext is determined incorrectly again with the sizeof-operator:

    encryptedatas = base64_encode(outbuf, sizeof(outbuf));
    

    Instead, it has to be:

    encryptedatas = base64_encode(outbuf, written); 
    delete outbuf;
    

    Here, the allocated memory for outbuf can be released so that no memory leak occurs.

  • With these changes, the following plain text:

    The quick brown fox jumps over the lazy dog 
    

    provides the following ciphertext:

    lXrmm21mt/5nd+bFm13mmXs+Kca4/wH1ZkbHXNe5/dPkIil7Vr7VuwQ8SeaLvMEh
    

    in accordance with the Java code, if the same key and IV are used. Btw for the testing I used the Base64-encoding from base64 decode snippet in c++.

I only briefly skimmed over the decryptdate-method. Also here the sizeof-operator is used incorrectly. Further errors not excluded.

Besides the mentioned bugs the code is also unnecessarily complicated and should be revised if possible. There is a detailed OpenSSL-C/C++-example here for AES-256 in CBC-mode that can be used as a blueprint (where EVP_aes_256_cbc() has to be replaced by EVP_des_cbc(), and of course IV and key). Btw DES is insecure and outdated (see e.g. here).

Upvotes: 1

Related Questions