在Java中重现加密方法

时间:2017-02-15 14:42:58

标签: javascript java c# encryption aes

我已经编写了两个函数来解密和加密C#和Javascript中的消息,但我也需要它用Java,我不能像以前那样工作。

JS加密方法:

this.aesEncrypt = function (encryptedMessage) {
    var key = CryptoJS.enc.Utf8.parse("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    var initialVector = CryptoJS.enc.Utf8.parse("xxxxxxxxxxxxxxxx");
    var encryptedText = CryptoJS.AES.encrypt(encryptedMessage, key,
    {
        iv: initialVector,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return encryptedText.toString().hexEncode();
}
String.prototype.hexEncode = function () {
    var hex, i;

    var result = "";
    for (i = 0; i < this.length; i++) {
        hex = this.charCodeAt(i).toString(16);
        result += ("0" + hex).slice(-2);
    }

    return result;
}

C#解密方法:

private static string AesDecrypt(string encryptedMessage)
{
    try
    {
        var temp = FromHex(encryptedMessage);
        var encryptedBytes = Convert.FromBase64String(Encoding.ASCII.GetString(temp));
        var aes = new AesCryptoServiceProvider
        {
            BlockSize = 128,
            KeySize = 256,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
            Key = Encoding.UTF8.GetBytes("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
            IV = Encoding.UTF8.GetBytes("xxxxxxxxxxxxxxxx")
        };
        var crypto = aes.CreateDecryptor(aes.Key, aes.IV);
        var secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
        crypto.Dispose();
        return Encoding.ASCII.GetString(secret);
    }
    catch (Exception)
    {
        return null;
    }
}

public static byte[] FromHex(string hex)
{
    hex = hex.Replace("-", "");
    var raw = new byte[hex.Length / 2];
    for (var i = 0; i < raw.Length; i++)
    {
        raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
    }
    return raw;
}

Java加密方法:

public static String toHex(String arg) {
    return String.format("%x", new BigInteger(1, arg.getBytes()));
}
public static String AesEncrypt(String encryptedMessage){
    try {
        IvParameterSpec initialVector = new IvParameterSpec("xxxxxxxxxxxxxxxx".getBytes("UTF-8"));
        SecretKeySpec secretKeySpec = new SecretKeySpec("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".getBytes("UTF-8"), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, initialVector);

        byte[] encrypted = cipher.doFinal(encryptedMessage.getBytes());
        StringBuilder encryptedSb = new StringBuilder(encrypted.length);
        for (byte i : encrypted){
            encryptedSb.append(i);
        }
        return toHex(encryptedSb.toString());
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}

Java在加密后返回80个六位数,JS返回48个六位数。 AFAIK Java PKCS5填充与C#PKCS7填充相同。

我也尝试使用
使用结果的base64编码 http://commons.apache.org/proper/commons-codec/download_codec.cgi
,但它仍然没有。

public static String AesEncrypt(String encryptedMessage){
    try {
        IvParameterSpec initialVector = new IvParameterSpec("xxxxxxxxxxxxxxxx".getBytes("UTF-8"));
        SecretKeySpec secretKeySpec = new SecretKeySpec("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".getBytes("UTF-8"), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, initialVector);

        byte[] encrypted = cipher.doFinal(encryptedMessage.getBytes());

        byte[] base64 = Base64.encodeBase64(encrypted);

        StringBuilder encryptedSb = new StringBuilder(base64.length);
        for (byte i : base64){
            encryptedSb.append(i);
        }
        return toHex(encryptedSb.toString());
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}

2 个答案:

答案 0 :(得分:2)

无论其他参数如何,AES都以16字节块运行。 Java AES中的PCKS#5填充将解析为PCKS#7。使用PCKS#7,您将填充到块边界;即填充最近的16个字节。

你的UTF-8输入“ABC”是3个字节。 16个字节将需要(16-3)= 13 字节的填充。因此,密文将是16个字节,或32个十六进制字符。

总而言之,我相信您的StringBuildertoHex()逻辑之间的编码转换有问题。尝试使用DatatypeConverter.printHexBinary(byte[] val)byte[] encrypted转换回十六进制。

答案 1 :(得分:-1)

我忘记了编码到Base64。我在最近的问题编辑中几乎就在那里。我只是忘记了Base64.encodeBase64String哪些实际上没有用,但我看了Base64类中这个函数的实现,我发现如何更明确地实现它。

public static String AesEncrypt(String encryptedMessage){
    try {
        IvParameterSpec initialVector = new IvParameterSpec("xxxxxxxxxxxxxxxx".getBytes("UTF-8"));
        SecretKeySpec secretKeySpec = new SecretKeySpec("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".getBytes("UTF-8"), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, initialVector);

        byte[] encrypted = cipher.doFinal(encryptedMessage.getBytes());
        String base64 = StringUtils.newStringUtf8(Base64.encodeBase64(encrypted, false));

        return toHex(base64);
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}