从 Java 转换为 C# - 使用 PKCS5Padding 解密 CBC-AES-256
Convert from Java to C# - Decrypt CBC-AES-256 with PKCS5Padding
我正在尝试从 ClickBank 解密 'Instant Notifications',他们有多种语言的解码代码示例,但没有 C#,所以我正在尝试翻译 Java 代码:
https://support.clickbank.com/hc/en-us/articles/220376507-Instant-Notification-Service-INS-#Code%20Samples
过去几天我尝试了几种不同的方法,但都不成功!请帮忙,我错过了什么?
Java:
final StringBuilder buffer = new StringBuilder();
final String secretKey = "YOUR SECRET KEY";
String line;
final BufferedReader reader = theRequest.getReader();
while(null != (line = reader.readLine())) {
buffer.append(line);
}
final JSONParser parser = new JSONParser();
final JSONObject obj = (JSONObject) parser.parse(buffer.toString());
final String initializationVector = (String) obj.get("iv");
final String encryptedNotification = (String) obj.get("notification");
final MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
digest.update(secretKey.getBytes("UTF-8"));
final String key = new String(Hex.encodeHex(digest.digest())).substring(0, 32);
final IvParameterSpec iv = new IvParameterSpec(DatatypeConverter.parseBase64Binary(initializationVector));
final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
final JSONObject notification = (JSONObject) parser.parse(
new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(encryptedNotification)),
"ISO-8859-1"));`
C#
const string secretKey = "YOUR SECRET KEY";
string sContent = "";
using (System.IO.Stream receiveStream = Request.InputStream)
{
receiveStream.Position = 0;
using (System.IO.StreamReader readStream =
new System.IO.StreamReader(receiveStream, Encoding.UTF8))
{
sContent = readStream.ReadToEnd();
}
}
dynamic json = System.Web.Helpers.Json.Decode(sContent);
string initializationVector = json.iv;
string encryptedNotification = json.notification;
//turn the key into a fixed length string via SHA-1 hash
SHA1 sha1 = SHA1Managed.Create();
byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(secretKey));
var key = Org.BouncyCastle.Utilities.Encoders.Hex.Encode(hash);
var keyString = Convert.ToBase64String(key).Substring(0, 32);
//var key = BitConverter.ToString(hash).Substring(0, 32);
var iv = Convert.FromBase64String(initializationVector);
byte[] keyspec = Encoding.UTF8.GetBytes(keyString);
using (var rijndaelManaged =
new RijndaelManaged { Key = keyspec, IV = iv, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(encryptedNotification)))
using (var cryptoStream =
new CryptoStream(memoryStream,
rijndaelManaged.CreateDecryptor(keyspec, iv),
CryptoStreamMode.Read))
{
var result = new StreamReader(cryptoStream).ReadToEnd();
}
给出错误 - 'Padding is invalid and cannot be removed.'
所以我猜我一定是创建了错误的密钥,我尝试了不同的散列和十六进制编码方式,但 none 似乎有效。请各位大侠指教!感谢您的宝贵时间
编辑:删除无用的额外代码
哦,亲爱的,一家使用 CBC 发送消息的银行。此 Java 代码示例看起来像 "my first attempt at crypto",并且来自银行,这不是您应该信任的银行。
密钥确实错误,你应该尝试key = Hex.ToHexString()
,然后使用Encoding.ASCII.GetBytes(key)
将结果的子字符串转换为ASCII。 Java 代码中不存在额外的 base 64 或位转换,不应使用。
我正在尝试从 ClickBank 解密 'Instant Notifications',他们有多种语言的解码代码示例,但没有 C#,所以我正在尝试翻译 Java 代码: https://support.clickbank.com/hc/en-us/articles/220376507-Instant-Notification-Service-INS-#Code%20Samples
过去几天我尝试了几种不同的方法,但都不成功!请帮忙,我错过了什么?
Java:
final StringBuilder buffer = new StringBuilder();
final String secretKey = "YOUR SECRET KEY";
String line;
final BufferedReader reader = theRequest.getReader();
while(null != (line = reader.readLine())) {
buffer.append(line);
}
final JSONParser parser = new JSONParser();
final JSONObject obj = (JSONObject) parser.parse(buffer.toString());
final String initializationVector = (String) obj.get("iv");
final String encryptedNotification = (String) obj.get("notification");
final MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
digest.update(secretKey.getBytes("UTF-8"));
final String key = new String(Hex.encodeHex(digest.digest())).substring(0, 32);
final IvParameterSpec iv = new IvParameterSpec(DatatypeConverter.parseBase64Binary(initializationVector));
final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
final JSONObject notification = (JSONObject) parser.parse(
new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(encryptedNotification)),
"ISO-8859-1"));`
C#
const string secretKey = "YOUR SECRET KEY";
string sContent = "";
using (System.IO.Stream receiveStream = Request.InputStream)
{
receiveStream.Position = 0;
using (System.IO.StreamReader readStream =
new System.IO.StreamReader(receiveStream, Encoding.UTF8))
{
sContent = readStream.ReadToEnd();
}
}
dynamic json = System.Web.Helpers.Json.Decode(sContent);
string initializationVector = json.iv;
string encryptedNotification = json.notification;
//turn the key into a fixed length string via SHA-1 hash
SHA1 sha1 = SHA1Managed.Create();
byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(secretKey));
var key = Org.BouncyCastle.Utilities.Encoders.Hex.Encode(hash);
var keyString = Convert.ToBase64String(key).Substring(0, 32);
//var key = BitConverter.ToString(hash).Substring(0, 32);
var iv = Convert.FromBase64String(initializationVector);
byte[] keyspec = Encoding.UTF8.GetBytes(keyString);
using (var rijndaelManaged =
new RijndaelManaged { Key = keyspec, IV = iv, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(encryptedNotification)))
using (var cryptoStream =
new CryptoStream(memoryStream,
rijndaelManaged.CreateDecryptor(keyspec, iv),
CryptoStreamMode.Read))
{
var result = new StreamReader(cryptoStream).ReadToEnd();
}
给出错误 - 'Padding is invalid and cannot be removed.'
所以我猜我一定是创建了错误的密钥,我尝试了不同的散列和十六进制编码方式,但 none 似乎有效。请各位大侠指教!感谢您的宝贵时间
编辑:删除无用的额外代码
哦,亲爱的,一家使用 CBC 发送消息的银行。此 Java 代码示例看起来像 "my first attempt at crypto",并且来自银行,这不是您应该信任的银行。
密钥确实错误,你应该尝试key = Hex.ToHexString()
,然后使用Encoding.ASCII.GetBytes(key)
将结果的子字符串转换为ASCII。 Java 代码中不存在额外的 base 64 或位转换,不应使用。