Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
加密Java然后用HMACSHA256解密C#AES256加密,填充无效_Java_C#_Encryption - Fatal编程技术网

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

加密Java然后用HMACSHA256解密C#AES256加密,填充无效,java,c#,encryption,Java,C#,Encryption,我目前遇到了一个问题,我们C#站点的解密部分在使用java加密字符串填充时遇到了问题。.Net代码抛出此错误“填充无效,无法删除”。_signKey和_encKey都是64字节 public String encryptString(String plainText) { byte[] ciphertext; byte[] iv = new byte[16]; byte[] plainBytes = plainText.getBytes(Stand

我目前遇到了一个问题,我们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));
                }
            }
        }
    }
公共静态字符串解密字符串(字符串密文)
{
使用(HMACSHA256 sha256=新的HMACSHA256(Encoding.UTF8.GetBytes(_signKey)))
{
//将消息转换为字节
byte[]encBytes=Convert.FromBase64String(密文);
//获取用于比较HMAC标记的数组
byte[]sentTag=新字节[sha256.HashSize/8];
byte[]calcTag=sha256.ComputeHash(encBytes,0,(encBytes.Length-sentTag.Length));
//如果消息长度太小,则返回null
if(encBytes.Length

如果有任何突出的地方,请给予答复

参考四个java代码和DotNet代码:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Java
csp.Padding = PaddingMode.PKCS7; //.Net
您实际上使用了不同的填充,这可能是错误的来源;但是,还有另一个视图,并且

Deafolt Oracle JVM实现支持的密码套件


如果您注意到它没有“AES/CBC/PKCS7Padding”,那么在sun.security包中可以使用PKCS#7 padding实现,否则您可以使用包。建议使用Bouncy Castle,因为com.sun软件包通常被认为是不受支持的。

我没有阅读您的所有代码,但Java中的这一行:

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

没有做任何有用或明智的事情。“+”运算符进行字符串连接,但
iv
字节[]
,而不是字符串。因此java使用
iv.toString()
,它只返回一个包含
[B@1188e820
在本文中没有意义。

PKCS#7和PKCS#5填充在实践中是相同的,只是定义不同。请特别参阅:“PKCS#5填充与PKCS#7填充相同,不同之处在于它仅为使用64位(8字节)块大小的块密码定义。在实践中,这两者可以互换使用。"。许多实现只是在添加AES时懒得包含n PKCS#7定义,只是决定使用PKCS#5定义来添加这样的混淆。@Zaph感谢您的回答您完全正确。我不久前就意识到了这一点。上面提供的答案并不正确通常是一个不正确的填充错误,真的只有我一个人ans解密失败,密钥、加密数据、IV等不正确和/或编码与实现不匹配。这让我很困惑。我们在上面进行了比较,以确保标记正确。我将向量与我们从Java发送的向量进行了比较,它们是相同的。这就是我挂断的原因。我感谢您的输入。好的,谢谢您!我对java相当陌生,所以我会边走边想办法。在.Net部分中,我们使用的是//派生会话密钥字节[]会话密钥字节=sha256.ComputeHash(Encoding.UTF8.GetBytes(_encKey+iv));我正试图从我们的.NET方面模仿这一点。如果这有帮助的话。关于如何在Java中完成同样的事情,有什么想法吗?顺便说一下,我明白了。我非常感谢你的帮助。实际上,我必须在最后添加System.Byte[]以使其正常工作。我们的.NET方面没有像人们想象的那样正常工作。