简体   繁体   English

Java 256 位 AES 加密

[英]Java 256-bit AES Encryption

I need to implement 256 bit AES encryption for cash flow i have c# answer but the answer is not the same,for a newbie, I am not sure if my direction is correct.我需要为现金流实现 256 位 AES 加密我有 c# 答案,但答案不一样,对于新手,我不确定我的方向是否正确。

this is my code这是我的代码

public static void main(String[] args) {
            String key = "12345678901234567890123456789012";
            String hashIv = "1234567890123456";
            String value = "MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest";
            String result = encrypt(key, hashIv, value);
            System.out.println(result);
            System.out.println();

            String sha256 = encrySha256("HashKey=" + key + "&" + result + "&HashIV=" + hashIv);
            System.out.println(sha256.trim());
        }

    public static String encrypt(String hashKey, String hashIv, String text) {

            try {
                SecretKeySpec skeySpec = new SecretKeySpec(hashKey.getBytes("UTF-8"), "AES");
                IvParameterSpec ivParameterSpec = new IvParameterSpec(hashIv.getBytes("UTF-8"));
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
                byte[] encrypted = cipher.doFinal((text.getBytes("UTF-8")));
                String test = bytesToHex(encrypted);

                return test.toLowerCase();          
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
            return null;
        }

        public static String bytesToHex(byte[] bytes) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(bytes[i] & 0xFF);
                if (hex.length() == 1) {
                    hex = '0' + hex;
                }
                sb.append(hex.toUpperCase());
            }
            return sb.toString();

        }

public static String encrySha256(String value) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(value.getBytes());
            byte byteBuffer[] = messageDigest.digest();
            StringBuffer strHexString = new StringBuffer();

            for (int i = 0; i < byteBuffer.length; i++) {
                String hex = Integer.toHexString(0xff & byteBuffer[i]);
                if (hex.length() == 1) {
                    strHexString.append('0');
                }
                strHexString.append(hex);
            }
            return strHexString.toString().toUpperCase();
        } catch (Exception e) {

        }
        return null;
    }

sample encrypt answer :示例加密答案:

ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d
9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9
974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f
984b9d41304ffd879612177c622f75f4214fa

encryptSha256 answer : EA0A6CC37F40C1EA5692E7CBB8AE097653DF3E91365E6A9CD7E91312413C7BB8 encryptSha256 答案: EA0A6CC37F40C1EA5692E7CBB8AE097653DF3E91365E6A9CD7E91312413C7BB8

this is c# code and this is sample data这是 C# 代码,这是示例数据

[MerchantID] => 3430112 [RespondType] => JSON [TimeStamp] => 1485232229 [Version] => 1.4 [MerchantOrderNo] => S_1485232229 [Amt] => 40 [ItemDesc] => UnitTest [MerchantID] => 3430112 [RespondType] => JSON [TimeStamp] => 1485232229 [Version] => 1.4 [MerchantOrderNo] => S_1485232229 [Amt] => 40 [ItemDesc] => UnitTest

    public string EncryptAES256(string source)//加密
    {
    string sSecretKey = "12345678901234567890123456789012";
    string iv = "1234567890123456";
    byte[] sourceBytes =
    AddPKCS7Padding(Encoding.UTF8.GetBytes(source), 32);
    var aes = new RijndaelManaged();
    aes.Key = Encoding.UTF8.GetBytes(sSecretKey);
    aes.IV = Encoding.UTF8.GetBytes(iv);
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.None;
    ICryptoTransform transform = aes.CreateEncryptor();
    return ByteArrayToHex(transform.TransformFinalBlock(sourceBytes, 0,
    sourceBytes.Length)).ToLower();
    }

    private static byte[] AddPKCS7Padding(byte[] data, int iBlockSize)
    {
    int iLength = data.Length;
    byte cPadding = (byte)(iBlockSize - (iLength % iBlockSize));
    var output = new byte[iLength + cPadding];
    Buffer.BlockCopy(data, 0, output, 0, iLength);
    for (var i = iLength; i < output.Length; i++)
    output[i] = (byte)cPadding;
    return output;
    }

    private static string ByteArrayToHex(byte[] barray)
    {
    char[] c = new char[barray.Length * 2];
    byte b;
    for (int i = 0; i < barray.Length; ++i)
    {
    b = ((byte)(barray[i] >> 4));
    c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
    b = ((byte)(barray[i] & 0xF));
    c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
    }
    return new string(c);
    }

The reason for the different encrypted data is that you compare different plain texts .不同加密数据的原因是您比较了不同的纯文本 In your Java code you encrypt the plain text在您的 Java 代码中,您加密纯文本

  MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest

and you compare the encrypted data with your reference data并将加密数据与参考数据进行比较

  ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f984b9d41304ffd879612177c622f75f4214fa

However, these reference data correspond to a different plain text .但是,这些参考数据对应的是不同的纯文本 The latter you can easily derive by decrypting the reference data with the C# DecryptAES256-method which provides后者您可以通过使用 C# DecryptAES256 方法解密参考数据来轻松推导,该方法提供

  MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest

Here, in contrast to the plain text in your Java code, a & -delimiter is used.与 Java 代码中的纯文本相比,这里使用了& -delimiter。

If you use the same plain text the Java encrypt- and the C# EncryptAES256-method provide the same encrypted data (same key, IV and padding supposed; for the latter see EDIT-section).如果您使用相同的纯文本,Java encrypt- 和 C# EncryptAES256-method 提供相同的加密数据(相同的密钥、IV 和填充假设;后者参见编辑部分)。

In the following testcase the plain text from your Java code is used:在以下测试用例中,使用了 Java 代码中的纯文本:

 encrypt("12345678901234567890123456789012", "1234567890123456", "MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest")

and

 EncryptAES256("MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest")

both provide the encrypted data:两者都提供加密数据:

 ff91c8aa01379e4de621a44e5f11f72ef45b7b9f9663d386da51af13f7f3b8f2b1ed4a3b7ac6b7783402193ea1d766e3046b6acf612d62568ccdbc475e5a14d114273735b069464dcc8281f4e5bf8486eb97d31602c3fe79cfe7140d2848413edad9d96fabf54d103f3d7a9b401c83fa5e4f17b10a280df10b3d61f23e69bbb8

which (as expected) differs from your reference data (with the exception of the first block).这(如预期)与您的参考数据不同(第一个块除外)。

EDIT编辑

There is a second issue concerning the padding: Your C# EncryptAES256-method uses a custom padding provided by the C# AddPKCS7Padding-method which pads to a multiple of 32 bytes .关于填充还有第二个问题:您的 C# EncryptAES256 方法使用由 C# AddPKCS7Padding-method 提供的自定义填充,该方法填充为32 bytes的倍数。

In contrast, your Java encrypt-method uses PKCS5Padding which pads to a multiple of 16 bytes .相比之下,您的 Java 加密方法使用 PKCS5Padding 填充到16 bytes的倍数。

Thus, the encrypted data of the Java encrypt- and the C# EncryptAES256-method differ if the length of the plain text is between 16 * n byte and 16 * (n + 1) - 1 byte with even n (0,2,4,...).因此,如果纯文本的长度在 16 * n 字节和 16 * (n + 1) - 1 字节之间,甚至 n (0,2,4 ,...)。

For odd n (1,3,5,...) the encrypted data are identical.对于奇数 n (1,3,5,...),加密数据是相同的。 In the example above the byte array of the plain text has 116 bytes that is n = 7 (112 <= 116 <= 127) and therefore the encrypted data are the same.在上面的示例中,纯文本的字节数组有 116 个字节,即 n = 7 (112 <= 116 <= 127),因此加密数据是相同的。

If the Java encrypt-method should use the same padding as the C# EncryptAES256-method you additionally have to implement an analogous Java-method eg:如果 Java 加密方法应使用与 C# EncryptAES256 方法相同的填充,则您还必须实现类似的 Java 方法,例如:

private static byte[] addPKCS7Padding(byte[] data, int iBlockSize)
{
    int iLength = data.length;
    byte cPadding = (byte)(iBlockSize - (iLength % iBlockSize));
    byte[] output = new byte[iLength + cPadding];
    System.arraycopy(data, 0, output, 0, iLength);
    for (int i = iLength; i < output.length; i++)
        output[i] = (byte)cPadding;
    return output;
}

and in the Java encrypt-method you have to replace:在 Java 加密方法中,您必须替换:

 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

with

 Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");

and also并且

 byte[] encrypted = cipher.doFinal(text.getBytes("UTF-8"));

with

 byte[] encrypted = cipher.doFinal(addPKCS7Padding(text.getBytes("UTF-8"), 32));

before:前:

MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest

After:后:

MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest

I only add "&" with each parameter, it's work!!!!我只为每个参数添加“&”,它的工作!!!! try it!!!尝试一下!!!

(我只加了&就成功拉,你的代碼沒問題,只是參數要加&而已) (我只加了&就成功拉,你的代码没问题,只有参数要加&就成功了)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM