【问题标题】:C++ equivalent of Java encryptionC++ 等效于 Java 加密
【发布时间】:2019-09-07 03:50:38
【问题描述】:

我有这个来自用于加密的 Java 代码的以下 sn-p

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;
        }
    }
}

C++ 中 Java 加密的等价物是什么?

这与 Java 加密有关。但不确定什么是等价的。本质上我想要与 Java 代码生成相同的输出。我尝试使用 Openssl 来加密和解密,但是它不起作用,我已经看到了一堆 Openssl 的示例,我仍然不知道出了什么问题我已经做了, 该代码试图进行 DES/CBC/PKCS5padding 加密

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;
}

DES/cbc/pkcs5padding 是Java代码的后果

08yw6mx6giw/tzhQk3ivwQ==

而 C++ 代码的后果是

e4CsOw==

有什么想法吗?

【问题讨论】:

标签: java c++ encryption visual-c++ openssl


【解决方案1】:

encryptdate-方法有一些错误:

  • sizeof-运算符返回对象或类型的大小(请参阅here)。该运算符在代码中经常被错误地使用,例如在以下代码-sn-p:

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

    在这里您尝试将plaindatas 的内容(包含明文)复制到数组in 中。在1) 中,incstyle 是一个指针 (char*),因此大小为 4 字节或 8 字节(取决于 32 位操作系统还是 64 位操作系统)。 sizeof(incstyle) 返回这个大小而不是字符串的长度。因此,在2) 中定义了一个通常太小的数组,因此在3) 中只有plaindatas 的一部分内容被复制到该数组中。

    数组in 被正确填充,例如以下代码:

    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);
    
  • 在调用EVP_EncryptUpdate时,sizeof-运算符也确定了纯文本长度错误(因为之前已经确定了数组in的长度错误):

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

    应该是这样的:

    EVP_EncryptUpdate(ctx, outbuf, &temp, in, in_len)
    
  • VP_EncryptFinal_ex的调用还有进一步的错误

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

    实际上必须如下:

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

    这里要注意最后密文长度(written)的更新。另外,为in分配的内存可以在这里释放,不会发生内存泄漏。

  • 对于-Base64编码,密文长度再次用sizeof-操作符确定错误:

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

    相反,它必须是:

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

    这里可以释放为outbuf分配的内存,这样就不会发生内存泄漏。

  • 通过这些更改,以下纯文本:

    The quick brown fox jumps over the lazy dog 
    

    提供以下密文:

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

    按照Java代码,如果使用相同的key和IV。顺便说一句,我使用 base64 decode snippet in c++ 的 Base64 编码进行测试。

我只是简要浏览了decryptdate-方法。同样在这里,sizeof-operator 使用不正确。未排除更多错误。

除了提到的错误之外,代码也不必要地复杂,如果可能的话应该修改。有一个详细的 OpenSSL-C/C++-example here 用于 CBC 模式下的 AES-256,可以用作蓝图(其中 EVP_aes_256_cbc() 必须替换为 EVP_des_cbc(),当然还有 IV 和密钥) .顺便说一句,DES 不安全且过时(参见例如here)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-06
    • 2016-03-15
    • 2015-12-07
    • 2014-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    相关资源
    最近更新 更多