【发布时间】:2014-07-31 16:41:56
【问题描述】:
我正在用 Java 实现与第三方应用程序的通信。 作为登录过程的一部分,第三方应用程序正在发送我必须解码并发回的加密字符串。 我花了将近 2 天的时间在谷歌上搜索和阅读帖子,但我找不到正确的方法来实现这一点。
我有一个测试用例,其中加密字符串是“c1W2YO1vYQzu6czteEidrG0U4g5gT4h57vAlP7tdjcY=”,使用密码“GAT”解密后必须返回“101714994”。
我的文档说明了这一点: 授权字符串使用以下设置加密:
- 输入数据的填充:PKCS*7
- 密码字节数组的长度为 32 个字节。密码字符串被转换为 UTF-16 编码的字节数组,然后用零填充字节数组,最长为 32 个字节。较长的密码会被截断。
这是如何解密授权字符串的 C# 示例:
/// <summary>
/// Decrypts a string.
/// </summary>
/// <param name="content">The string to decrypt.</param>
/// <param name="password">The password to use.</param>
/// <returns>The decrypted string.</returns>
private static string DecryptString(string content, string password) {
Rijndael aes;
byte[] retVal = null;
byte[] contentBytes;
byte[] passwordBytes;
byte[] ivBytes;
try {
//Get the content as byte[]
contentBytes = Convert.FromBase64String(content);
//Create the password and initial vector bytes
passwordBytes = new byte[32];
ivBytes = new byte[16];
Array.Copy(Encoding.Unicode.GetBytes(password), passwordBytes, Encoding.Unicode.GetBytes(password).Length);
Array.Copy(passwordBytes, ivBytes, 16);
//Create the cryptograpy
object aes = Rijndael.Create();
aes.Key = passwordBytes;
aes.IV = ivBytes;
aes.Padding = PaddingMode.PKCS7;
//Decrypt
retVal = aes.CreateDecryptor().TransformFinalBlock(contentBytes, 0, contentBytes.Length);
}
catch {
}
aes = null;
contentBytes = null;
passwordBytes = null;
ivBytes = null;
return Encoding.Unicode.GetString(retVal)
}
这是我解密字符串的Java程序:
private String decryptAuthorizationString(String authString, String password) {
try {
//Force the test string
authString = "c1W2YO1vYQzu6czteEidrG0U4g5gT4h57vAlP7tdjcY=";
//Force the test password
password = "GAT";
//Create the password and initial vector bytes
byte[] passwordBytes= new byte[32];
byte[] b= password.getBytes("UTF-8");
int len= b.length;
if (len > passwordBytes.length) len = passwordBytes.length;
System.arraycopy(b, 0, passwordBytes, 0, len);
byte[] ivBytes= new byte[16];
System.arraycopy(passwordBytes, 0, ivBytes, 0, 16);
//Get the authString as byte[]
byte[] authBytes = new BASE64Decoder().decodeBuffer(authString);
InputStream inputStream = new ByteArrayInputStream(authBytes);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// If you have Bouncycastle library installed, you can use
// Rijndael/CBC/PKCS7PADDING directly.
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("Rijndael/CBC/PKCS7PADDING", "BC");
// convertedSecureString and initVector must be byte[] with correct length
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(passwordBytes, "AES"), new IvParameterSpec(ivBytes));
CipherInputStream cryptoStream = new CipherInputStream(inputStream, cipher);
byte[] buffer = new byte[1024];
len = cryptoStream.read(buffer, 0, buffer.length);
while (len > 0) {
outputStream.write(buffer, 0, len);
len = cryptoStream.read(buffer, 0, buffer.length);
}
outputStream.flush();
cryptoStream.close();
String resStr = outputStream.toString("UTF-8");
return resStr; //<<--- resStr must be "101714994"
} catch (Throwable t) {
}
return null;
}
程序运行没有任何错误,但结果不是我需要的。 任何帮助将不胜感激。
【问题讨论】:
-
你在 C# 中使用 ECB 模式,在 Java 中使用 CBC 模式吗?
-
不要使用
sun.misc.BASE64Decoder。这是internal and unsupported。 -
@FruitDealer C#中的默认模式是CBC。
-
感谢大家的帮助,下面的答案解决了我的问题。
标签: java c# encryption cryptography rijndael