Java加密和c#解密问题
本文关键字:解密 问题 加密 Java | 更新日期: 2023-09-27 18:11:03
我在c#中有一个加密和解密字符串文本的DLL(一些基本的东西),但现在我需要在Java中实现相同的加密方法,以便一些应用程序可以加密数据并将其发送到库。
我不能修改c#代码,因为它已经在生产中了,但是Java不能,所以请,任何建议都必须在Java端完成。
基本上,我正在尝试在Java中实现相同的c#加密方法。以下是我的c#代码:
: passsphrase, salt等值显然只是参考。
const string PassPhrase = "IhDyHz6bgQyS0Ff1/1s=";
const string SaltValue = "0A0Qvv09OXd3GsYHVrA=";
const string HashAlgorithm = "SHA1";
const int PasswordIterations = 3;
const string InitVector = "GjrlRZ6INgNckBqv";
const int KeySize = 256;
public static string Encrypt(string plainText)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
PasswordDeriveBytes password = new PasswordDeriveBytes(
PassPhrase,
saltValueBytes,
HashAlgorithm,
PasswordIterations);
byte[] keyBytes = password.GetBytes(KeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
keyBytes,
initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream,
encryptor,
CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string cipherText = Convert.ToBase64String(cipherTextBytes);
return cipherText;
}
public static string Decrypt(string cipherText)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
PasswordDeriveBytes password = new PasswordDeriveBytes(
PassPhrase,
saltValueBytes,
HashAlgorithm,
PasswordIterations);
byte[] keyBytes = password.GetBytes(KeySize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
keyBytes,
initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream,
decryptor,
CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes,
0,
plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
string plainText = Encoding.UTF8.GetString(plainTextBytes,
0,
decryptedByteCount);
return plainText;
}
这是我的java代码,它加密数据,但不像c#加密代码一样,所以当我尝试使用c#库解密它时,它会抛出异常:"要解密的数据长度无效"
static final String PassPhrase = "IhDyHz6bgQyS0Ff1/1s=";
static final String SaltValue = "0A0Qvv09OXd3GsYHVrA=";
static final String HashAlgorithm = "SHA1";
static final int PasswordIterations = 3;
static final String InitVector = "GjrlRZ6INgNckBqv";
static final int KeySize = 256;
public static String encrypt(String plainText)
{
char[] password = PassPhrase.toCharArray();
byte[] salt = SaltValue.getBytes();
byte[] iv = InitVector.getBytes();
byte[] ciphertext = new byte[0];
SecretKeyFactory factory;
try {
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, PasswordIterations, 256);
SecretKey tmp;
tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
//iv = params.getParameterSpec(IvParameterSpec.class).getIV();
ciphertext = cipher.doFinal(plainText.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//catch (InvalidParameterSpecException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
//}
catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Base64.encode(new String(ciphertext));
}
EDIT 1:按照Jon Skeet的建议,我在Java代码中将最后的字节数组转换为String。
这是错误的,在Java代码中:
return Base64.encode(ciphertext.toString());
你在字节数组上调用toString()
,这将总是给出一个字符串,如[B@3e25a5
。
编辑:哦,刚刚注意到你可以更改Java端。万岁。
基本上,你需要使用一个Base64 API,它允许:
return Base64.encode(ciphertext);
我总是对Base64 api感到失望,其中允许您"编码"字符串,说实话…Base64基本上将二进制数据编码为文本,并将文本数据解码为二进制。哦…无论如何,使用这个API (encodeBytes
方法),如果你需要一个允许你传入字节数组。
using
语句:)
这是一个c#的例子,你需要IterationCount和PaddingMode。没有一个
protected void Page_Load(object sender, EventArgs e)
{
string value = "";
string password = "";
string salt = "";
string iv = "";
byte[] vectorBytes = Convert.FromBase64String(Server.UrlDecode(iv));
byte[] cipherText = Convert.FromBase64String(Server.UrlDecode(value));
Rfc2898DeriveBytes key1 = new Rfc2898DeriveBytes(password, StringToByteArray(salt)); //same as PBKDF2WithHmacSHA1
key1.IterationCount = 32;
byte[] keyBytes = key1.GetBytes(16);
string Answer = DecryptDataAES(cipherText, keyBytes, vectorBytes); //vectorBytes is good
//litAnswer.Text = Answer;
}
public static string DecryptDataAES(byte[] cipherText, byte[] key, byte[] iv)
{
string plaintext = null;
using (Rijndael rijndael = Rijndael.Create())
{
rijndael.Key = key;
rijndael.IV = iv;
rijndael.Padding = PaddingMode.None;
ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length / 2;
byte[] bytes = new byte[NumberChars];
using (var sr = new StringReader(hex))
{
for (int i = 0; i < NumberChars; i++)
bytes[i] =
Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
}
return bytes;
}