簡體   English   中英

C#對使用AES的Java加密/解密的好奇行為

[英]Curious behavior by C# to Java encryption/decryption using AES

通過使用AES算法的字符串解密,我有一個非常奇怪的問題。 我的C#應用​​程序將加密數據(字符串)發送到Java應用程序。 即使我使用相同的密鑰字符串,解密也會導致異常:

javax.crypto.BadPaddingException:給定的最后一個塊沒有在com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:810)中正確填充

但是只有當要加密的普通輸入文本的長度(在C#側)超過1393個字符時......但如果長度等於1393個字符,或者小於1393個字符,則它可以正常工作。

這是加密的C#代碼:

    private static string Encrypt(string textToEncrypt, string key)
    {
        try
        {
            RijndaelManaged rijndaelCipher = new RijndaelManaged();
            rijndaelCipher.Mode = CipherMode.CBC;
            rijndaelCipher.Padding = PaddingMode.PKCS7;

            rijndaelCipher.KeySize = 0x80; // 256bit key
            rijndaelCipher.BlockSize = 0x80;
            byte[] pwdBytes = Encoding.UTF8.GetBytes(key);
            byte[] keyBytes = new byte[0x10];
            int len = pwdBytes.Length;
            if (len > keyBytes.Length)
            {
                len = keyBytes.Length;
            }
            Array.Copy(pwdBytes, keyBytes, len);
            rijndaelCipher.Key = keyBytes;
            rijndaelCipher.IV = keyBytes;
            ICryptoTransform transform = rijndaelCipher.CreateEncryptor();
            byte[] plainText = Encoding.UTF8.GetBytes(textToEncrypt);
            return Convert.ToBase64String(transform.TransformFinalBlock(plainText, 0, plainText.Length));
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

以及用於解密的Java代碼:

public static String Decrypt(String text, String key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] keyBytes = new byte[16];
    byte[] b = key.getBytes("UTF-8");
    int len = b.length;
    if (len > keyBytes.length) {
        len = keyBytes.length;
    }
    System.arraycopy(b, 0, keyBytes, 0, len);

    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

    BASE64Decoder decoder = new BASE64Decoder();
    byte[] results = cipher.doFinal(decoder.decodeBuffer(text));
    return new String(results, "UTF-8");
}

我已經嘗試將BASE64Decoder替換為來自apache的Base64編解碼器,但結果是一樣的......我將不勝感激任何建議或想法。 謝謝。

如果您通過網絡傳輸密文,則應使用消息驗證代碼確保其完整性。 在嘗試解密密文之前,應驗證MAC。 這將防止意外破壞和惡意篡改線路上的消息。 在這種情況下,它應該可以幫助您確保傳輸的密文與您接收的密文完全相同。

我重寫了java解密端進行MAC驗證。 它假定MAC是使用HMACSHA1算法生成的,該算法使用與AES密碼相同的密鑰材料進行初始化(注意:這僅是一個示例,加密密鑰和HMAC密鑰在實際系統中應該是不同的)並且預先附加到密文。 消息的前20個字節應該是MAC,然后是緊隨其后的密文。

public static String Decrypt(String message, String key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] keyBytes = new byte[16];
    byte[] b = key.getBytes("UTF-8");
    int len = b.length;
    if (len > keyBytes.length) {
        len = keyBytes.length;
    }
    System.arraycopy(b, 0, keyBytes, 0, len);

    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);

    byte[] messageBytes =  DatatypeConverter.parseBase64Binary(message);
    byte[] macBytes = new byte[20];
    byte[] ciphertext = new byte[messageBytes.length - 20];

    System.arraycopy(messageBytes, 0, macBytes, 0, macBytes.length);
    System.arraycopy(messageBytes, 20, ciphertext, 0, ciphertext.length);

    Mac mac = Mac.getInstance("HMACSHA1");
    mac.init(keySpec);

    verifyMac(mac.doFinal(ciphertext), macBytes);

    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

    byte[] results = cipher.doFinal(ciphertext);
    return new String(results, "UTF-8");
}

private static void verifyMac(byte[] mac1, byte[] mac2) throws Exception {
    MessageDigest sha = MessageDigest.getInstance("SHA1");
    byte[] mac1_hash = sha.digest(mac1);
    sha.reset();
    byte[] mac2_hash = sha.digest(mac2);

    if(!Arrays.equals(mac1_hash, mac2_hash)){
        throw new RuntimeException("Invalid MAC");
    }

}

關於安全實踐的一些注意事項。 使用輸入密碼的UTF-8字節不會在您的密鑰中提供足夠的熵。 如果您要使用密碼作為加密密鑰,則應使用密鑰拉伸算法對其進行處理。 PBKDF2是一個受歡迎的選擇。 AES密碼的IV應該是隨機生成的(使用加密安全的隨機源),並使用密文以明文形式傳輸。 用於初始化AES密碼的密鑰應該與用於MAC的密鑰不同。 您可以使用PBKDF2根據您提供的密碼創建密鑰的兩倍,並將前半部分用於AES,將后半部分用於HMAC-SHA1。 最后要注意的是,在驗證MAC時,您應該直接驗證MAC的散列而不是MAC(如上面的verifyMac方法中所示)。 驗證MA直接暴露可能的定時攻擊向量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM