尝试通过OpenSSL在C ++中实现Java加密方法时遇到问题。
package des;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.xml.bind.DatatypeConverter;
public final class Des
{
private static final byte[] IV = {(byte) 0xA6, (byte) 0x8A, 0x11, 0x63, (byte) 0x94, 0x4D, (byte) 0x8E, (byte) 0xA3};
private static final byte[] DES_KEY = {(byte) 0x81, 0x33, 0x66, (byte) 0xD8, 0x5F, (byte) 0xD3, 0x17, 0x21, 0x5C, 0x7F};
public static byte [] encrypt(String data)
{
byte result[] = null;
try
{
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
DESKeySpec desKeySpec = new DESKeySpec(DES_KEY);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
IvParameterSpec iv = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
result = cipher.doFinal(data.getBytes(CHARSET));
}
catch(Exception e)
{
e.printStackTrace();
}
return result;
}
}
测试:
import des.Des;
class DesCrypt
{
public static void main(String args[])
{
byte array[] = Des.encrypt("my secret string");
for(byte b : array)
{
System.out.printf("%02X ", b);
}
}
}
加密的结果是:
0B AE 3C 47 B5 CE 57 03 01 25 F7 1B 1B 1D F4 C1 50 66 90 1F 7E B3 89 FD
我没有密码学经验,于是我决定使用DES_cbc_encrypt()
在C ++中实现'DES / CBC / PKCS5Padding'加密。
#include <vcl.h>
#pragma hdrstop
#include <tchar.h>
#include <string>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <stdio.h>
#include <openssl/des.h>
#pragma argsused
class Des
{
public:
typedef std::vector<unsigned char> Bytes;
static Bytes encrypt(const std::string& message)
{
const unsigned char IV[] = {0xA6, 0x8A, 0x11, 0x63, 0x94, 0x4D, 0x8E, 0xA3};
const unsigned char key[] = {0x81, 0x33, 0x66, 0xD8, 0x5F, 0xD3, 0x17, 0x21, 0x5C, 0x7F};
const Bytes in(message.begin(), message.end());
DES_cblock desKey = {0};
DES_cblock iv = {0};
std::copy(key, key + 8, desKey);
std::copy(IV, IV + 8, iv);
DES_key_schedule keysched;
Bytes result(in.size());
DES_set_odd_parity(&desKey);
if(DES_set_key_checked((C_Block *)desKey, &keysched))
{
throw std::runtime_error("ERROR: Unable to set key schedule");
}
DES_cbc_encrypt(&in[0], &result[0], in.size(), &keysched, &iv, DES_ENCRYPT);
return result;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
const Des::Bytes encr = Des::encrypt("my secret string");
size_t size = encr.size();
for(Des::Bytes::const_iterator byte = encr.begin(); byte != encr.end(); ++byte)
{
printf("%02X ", *byte);
}
return 0;
}
结果是:
0B AE 3C 47 B5 CE 57 03 01 25 F7 1B 1B 1D F4 C1
Java输出最后有8个额外字节。请帮助选择合适的OpenSSL函数,以便在C ++中实现与Java DES / CBC / PKCS5Padding加密算法相同的结果。提前谢谢。
答案 0 :(得分:2)
由于@Artjom B.建议我根据规范实施PKCS#5填充
6.1.1 Encryption Operation
...
4. Concatenate M and a padding string PS to form an encoded
message EM:
EM = M || PS ,
where the padding string PS consists of 8-(||M|| mod 8) octets
each with value 8-(||M|| mod 8). The padding string PS will
satisfy one of the following statements:
PS = 01, if ||M|| mod 8 = 7 ;
PS = 02 02, if ||M|| mod 8 = 6 ;
...
PS = 08 08 08 08 08 08 08 08, if ||M|| mod 8 = 0.
代码:
class Des
{
public:
typedef std::vector<unsigned char> Bytes;
static Bytes encrypt(const std::string& message)
{
const unsigned char IV[] = {0xA6, 0x8A, 0x11, 0x63, 0x94, 0x4D, 0x8E, 0xA3};
const unsigned char key[] = {0x81, 0x33, 0x66, 0xD8, 0x5F, 0xD3, 0x17, 0x21, 0x5C, 0x7F};
Bytes in(message.begin(), message.end());
DES_cblock desKey = {0};
DES_cblock iv = {0};
std::copy(key, key + 8, desKey);
std::copy(IV, IV + 8, iv);
DES_key_schedule keysched;
const size_t paddingLength = (8 - in.size() % 8);
const Bytes padding(paddingLength, 8 - in.size() % 8);
std::copy(padding.begin(), padding.end(), back_inserter(in));
Bytes result(in.size());
DES_set_odd_parity(&desKey);
if(DES_set_key_checked((C_Block *)desKey, &keysched))
{
throw std::runtime_error("ERROR: Unable to set key schedule");
}
DES_cbc_encrypt(&in[0], &result[0], in.size(), &keysched, &iv, DES_ENCRYPT);
return result;
}
};
现在输出等同于Java实现输出。