簡體   English   中英

加密Java,然后使用HMACSHA256解密C#AES256加密,填充無效

[英]Encrypting Java then Decrypting C# AES256 Encryption with HMACSHA256, Padding is invalid

我目前遇到一個問題,即C#站點的解密部分在填充來自Java的加密字符串時遇到了麻煩。 .Net代碼引發此錯誤“填充無效,無法刪除”。 _signKey和_encKey均為64個字節。

public String encryptString(String plainText) {
        byte[] ciphertext;
        byte[] iv = new byte[16];
        byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
        String _signKey = "****************************************************************";
        String _encKey = "****************************************************************";



        try {
            Mac sha256 = Mac.getInstance("HmacSHA256");
            SecretKeySpec shaKS = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256.init(shaKS);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
            iv = new byte[cipher.getBlockSize()];
            randomSecureRandom.nextBytes(iv);
            IvParameterSpec ivParams = new IvParameterSpec(iv);
            byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8));
            // Perform Encryption
            SecretKeySpec eks = new SecretKeySpec(sessionKey, "AES");
            cipher.init(Cipher.ENCRYPT_MODE, eks, ivParams);

            ciphertext = cipher.doFinal(plainBytes);
            System.out.println("ciphertext= " + new String(ciphertext));
            // Perform HMAC using SHA-256 on ciphertext
            SecretKeySpec hks = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(hks);

            ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
            outputStream2.write(iv);
            outputStream2.write(ciphertext);
            outputStream2.flush();
            outputStream2.write(mac.doFinal(outputStream2.toByteArray()));
            return Base64.encodeBase64String(outputStream2.toByteArray());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return plainText;
    }

據我所知,確實對字符串進行了正確加密。 我們無法在.Net端更改任何代碼來對此解密,因為今天已在使用它。

public static string DecryptString(string ciphertext)
    {
        using (HMACSHA256 sha256 = new HMACSHA256(Encoding.UTF8.GetBytes(_signKey)))
        {
            // Convert message to bytes
            byte[] encBytes = Convert.FromBase64String(ciphertext);

            // Get arrays for comparing HMAC tags
            byte[] sentTag = new byte[sha256.HashSize / 8];
            byte[] calcTag = sha256.ComputeHash(encBytes, 0, (encBytes.Length - sentTag.Length));

            // If message length is too small return null
            if (encBytes.Length < sentTag.Length + _ivLength) { return null; }

            // Copy tag from end of encrypted message
            Array.Copy(encBytes, (encBytes.Length - sentTag.Length), sentTag, 0, sentTag.Length);

            // Compare tags with constant time comparison, return null if no match
            int compare = 0;
            for (int i = 0; i < sentTag.Length; i++) { compare |= sentTag[i] ^ calcTag[i]; }
            if (compare != 0) { return null; }

            using (AesCryptoServiceProvider csp = new AesCryptoServiceProvider())
            {
                // Set parameters
                csp.BlockSize = _blockBits;
                csp.KeySize = _keyBits;
                csp.Mode = CipherMode.CBC;
                csp.Padding = PaddingMode.PKCS7;

                // Copy init vector from message
                var iv = new byte[_ivLength];
                Array.Copy(encBytes, 0, iv, 0, iv.Length);

                // Derive session key
                byte[] sessionKey = sha256.ComputeHash(Encoding.UTF8.GetBytes(_encKey + iv));

                // Decrypt message
                using (ICryptoTransform decrypt = csp.CreateDecryptor(sessionKey, iv))
                {
                    return Encoding.UTF8.GetString(decrypt.TransformFinalBlock(encBytes, iv.Length, encBytes.Length - iv.Length - sentTag.Length));
                }
            }
        }
    }

如果有任何遺漏,我們將不勝感激。

我沒有閱讀您所有的代碼,但是在Java中這行代碼:

byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8));

沒有任何用處或明智之處。 “ +”運算符進行字符串連接,但是ivbyte[]而不是字符串。 因此,java使用iv.toString() ,它僅返回包含[B@1188e820類的字符串,在此上下文中這是沒有意義的。

請參考四個Java代碼和DotNet代碼:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Java
csp.Padding = PaddingMode.PKCS7; //.Net

本質上,您使用的是不同的填充,這可能是錯誤的來源。 但是,還有另一種觀點, 請參閱這篇出色的文章,了解有關填充的一般基礎知識

默認的Oracle JVM實現支持的密碼套件在這里

如果您發現它沒有'AES / CBC / PKCS7Padding',則sun.security軟件包中提供了PKCS#7填充實現, 請參考 ,否則可以使用Bouncy Castle軟件包。 建議使用Bouncy Castle,因為通常認為com.sun軟件包不受支持。

暫無
暫無

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

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