[英]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));
没有任何用处或明智之处。 “ +”运算符进行字符串连接,但是iv
是byte[]
而不是字符串。 因此,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.