将Java加密算法移植到C ++ OpenSSL

时间:2015-05-27 09:13:26

标签: java c++ encryption openssl

尝试通过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加密算法相同的结果。提前谢谢。

1 个答案:

答案 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实现输出。