我有以下用于加密的 Java 代码片段
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==
有什么想法吗?
最佳答案
encryptdate
方法有一些错误:
sizeof
运算符返回对象或类型的大小(参见 here )。该运算符在代码中经常被错误使用,例如在以下代码片段中: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
运算符使用不当。不排除进一步的错误。
除了提到的错误之外,代码也不必要地复杂,如果可能应该修改。有一个详细的 OpenSSL-C/C++-example here对于可用作蓝图的 CBC 模式下的 AES-256(其中 EVP_aes_256_cbc()
必须替换为 EVP_des_cbc()
,当然还有 IV 和 key ) .顺便说一句,DES 不安全且已过时(参见例如 here )。
关于java - C++ 等价于 Java 加密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55718398/