我们有一个用例,我们希望解密以前使用.NET加密的java中的数据
以下是用于在.NET中加密和解密数据的Crypt类:
https://gist.github.com/epinapala/9400064
我将Decrypt方法分离并执行,它在.NET中工作正常,我希望移植下面的代码:
using System.IO;
using System;
using System.Text;
using System.Security.Cryptography;
class Program
{
static void Main()
{
{
string line = "f5EBWYipPKG1FpyTEP7pyPLLJNpqrvwYJFs8iMw9mOY$";
line = line.Replace('-', '+').Replace('_', '/').Replace('$', '=');
while (line.Length % 4 != 0){
line = line.PadRight(line.Length + (4 - line.Length % 4), '=');
}
Console.WriteLine(line);
byte[] inputBuffer = Convert.FromBase64String(line);
Console.WriteLine(inputBuffer.Length);
byte[] numArray = new byte[16];
byte[] key = new PasswordDeriveBytes("ThisIsMyKey", new byte[13]
{
(byte) 73,
(byte) 118,
(byte) 97,
(byte) 110,
(byte) 32,
(byte) 77,
(byte) 101,
(byte) 100,
(byte) 118,
(byte) 101,
(byte) 100,
(byte) 101,
(byte) 118
}).GetBytes(16);
Rijndael rijndael = GetRijndael(key);
for (int index = 0; index < 16; ++index){
numArray[index] = inputBuffer[index];
}
rijndael.IV = numArray;
string decodedString = Encoding.UTF8.GetString(rijndael.CreateDecryptor().TransformFinalBlock(inputBuffer, 16, inputBuffer.Length - 16));
Console.WriteLine(decodedString);
}
}
private static Rijndael GetRijndael(byte[] key)
{
Rijndael rijndael = Rijndael.Create();
rijndael.Mode = CipherMode.CBC;
rijndael.KeySize = key.Length * 8;
rijndael.Key = key;
rijndael.Padding = PaddingMode.PKCS7;
return rijndael;
}
}
这是我到目前为止所尝试的内容:
public static void main() {
ecnryptedData = "f5EBWYipPKG1FpyTEP7pyPLLJNpqrvwYJFs8iMw9mOY$";
ecnryptedData = ecnryptedData.replace('-', '+')
.replace('_', '/').replace('$', '=');
while (ecnryptedData.length() % 4 != 0) {
ecnryptedData = StringUtils.rightPad(ecnryptedData, ecnryptedData.length() + (4 - ecnryptedData.length() % 4),
"=");
}
System.out.println(Decrypt(ecnryptedData, "ThisIsMyKey"));
}
public static String Decrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length) len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
AlgorithmParameterSpec spec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, spec);
BASE64Decoder decoder = new BASE64Decoder();
byte[] results = cipher.doFinal(decoder.decodeBuffer(text));
return new String(results, "UTF-8");
}
我得到了例外情况:“给定最后一个块没有正确填充”。不知道我做错了什么。我对此问题表示感谢。
[[编辑]]:
我明白了。我失踪的是我使用了错误的盐。我将.NET代码中使用的常量salt(作为字节)解码为其String计数器部分,并在我的Java代码中将其用作Salt。
还要感谢此处的PasswordDerivedBytes类:
private static byte[] decryptData(byte[] data, String password,
String paddingMode, String salt) throws Exception {
if (data == null || data.length == 0)
throw new IllegalArgumentException("data is empty");
if (password == null || password == "")
throw new IllegalArgumentException("password is empty");
if (salt == null || salt == "")
salt = ".";
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] saltBytes = salt.getBytes("UTF8");
byte[] passBytes = password.getBytes("UTF8");
PKCS5S1ParametersGenerator generator = new PasswordDeriveBytes(
new SHA1Digest());
generator.init(passBytes, saltBytes, 100);
byte[] key = ((KeyParameter) generator.generateDerivedParameters(256))
.getKey();
passBytes = new byte[16];
saltBytes = new byte[16];
System.arraycopy(key, 0, passBytes, 0, 16);
System.arraycopy(key, 16, saltBytes, 0, 16);
Cipher cipher = Cipher.getInstance("AES/CBC/" + paddingMode, "BC");
SecretKeySpec keySpec = new SecretKeySpec(passBytes, "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec,
new IvParameterSpec(saltBytes));
byte[] original = cipher.doFinal(data);
return original;
}
答案 0 :(得分:1)
您在C#代码中使用自定义Base64变体:_
和-
作为字符62和63以及$
作为填充。在尝试解码之前,C#代码将这些转换为普通的Base64。
您的java代码将无效数据传递给Base64解码器。这应该在代码甚至到达加密之前抛出IllegalArgumentException
。
另一个问题是你的C#代码使用PBKDF1从密码派生密钥,java代码直接使用密码作为密钥字节。