有人可以帮我让我的 AES 加密在 Java、Javascript 和 C# 之间工作吗?
Can someone help me get my AES encryption working between Java, Javascript and C#?
我已经让它在 Java 和 Java 脚本之间工作,但 C# 代码的工作方式不同。也就是说,给定一个要加密的特定字符串,Java 和 Java 脚本代码将生成相同的结果,但 C# 代码生成不同的结果。
这里是 Java脚本代码(使用 CryptoJS):
AesUtil.prototype.encrypt = function(salt, iv, passPhrase, plainText) {
var key = this.generateKey(salt, passPhrase);
var encrypted = CryptoJS.AES.encrypt(
plainText,
key,
{ iv: CryptoJS.enc.Hex.parse(iv) });
return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}
此代码会将 "guest" 加密为 "WsH/YEUqqrWDxD15zxsUPg=="。
这里是 Java 代码:
public String encrypt(String plainText, String salt, String passphrase, String iv) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
byte[] plainTextbytes = plainText.getBytes(characterEncoding);
//byte[] keyBytes = getKeyBytes(salt);
SecretKey key = generateKey(salt, passphrase);
byte[] ivBytes = hex(iv);
return Base64.getEncoder().encodeToString(encrypt(plainTextbytes,key, ivBytes));//, Base64.DEFAULT);
}
private static SecretKey generateKey(String salt, String passphrase) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new javax.crypto.spec.PBEKeySpec(passphrase.toCharArray(), hex(salt), 10000, 128);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "Rijndael");
return key;
}
catch (NoSuchAlgorithmException e) {
throw fail(e);
}
catch (InvalidKeySpecException e) {
throw fail(e);
}
}
public static String hex(byte[] bytes) {
return Hex.encodeHexString(bytes);
}
此代码还将 "guest" 加密为 "WsH/YEUqqrWDxD15zxsUPg=="。
这是我的 C# 代码:
public String Encrypt(String plainText, String passphrase, String salt, String iv, int iterations) {
var plainBytes = Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(Encrypt(plainBytes, GetSymmetricAlgorithm(passphrase, salt, iv, iterations)));
}
public byte[] Encrypt(byte[] plainBytes, SymmetricAlgorithm sa) {
return sa.CreateEncryptor().TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
public SymmetricAlgorithm GetSymmetricAlgorithm(String passphrase, String salt, String iv, int iterations) {
var saltBytes = new byte[16];
var ivBytes = new byte[16];
Rfc2898DeriveBytes rfcdb = new System.Security.Cryptography.Rfc2898DeriveBytes(passphrase, Encoding.UTF8.GetBytes(salt), iterations);
saltBytes = rfcdb.GetBytes(16);
var tempBytes = Encoding.UTF8.GetBytes(iv);
Array.Copy(tempBytes, ivBytes, Math.Min(ivBytes.Length, tempBytes.Length));
var rij = new RijndaelManaged(); //SymmetricAlgorithm.Create();
rij.Mode = CipherMode.CBC;
rij.Padding = PaddingMode.PKCS7;
rij.FeedbackSize = 128;
rij.KeySize = 128;
rij.BlockSize = 128;
rij.Key = saltBytes;
rij.IV = ivBytes;
return rij;
}
public byte[] Encrypt(byte[] plainBytes, SymmetricAlgorithm sa) {
return sa.CreateEncryptor().TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
此代码将 "guest" 加密为 "F8t0D0vA2rxU3Ez1O5artA=="。请注意,结果值是相同的长度,但它不是相同的值,并且不能用 Java 代码解密(我没有在此处提供 - 我主要关心将所有三种加密一样)。
有人能帮忙吗?提前致谢。
您在 JS 和 Java 中从十六进制解码 IV,但在 C# 中您有 var tempBytes = Encoding.UTF8.GetBytes(iv);
。您需要在 C# 中执行相同的十六进制解码。
我已经让它在 Java 和 Java 脚本之间工作,但 C# 代码的工作方式不同。也就是说,给定一个要加密的特定字符串,Java 和 Java 脚本代码将生成相同的结果,但 C# 代码生成不同的结果。
这里是 Java脚本代码(使用 CryptoJS):
AesUtil.prototype.encrypt = function(salt, iv, passPhrase, plainText) {
var key = this.generateKey(salt, passPhrase);
var encrypted = CryptoJS.AES.encrypt(
plainText,
key,
{ iv: CryptoJS.enc.Hex.parse(iv) });
return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}
此代码会将 "guest" 加密为 "WsH/YEUqqrWDxD15zxsUPg=="。
这里是 Java 代码:
public String encrypt(String plainText, String salt, String passphrase, String iv) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
byte[] plainTextbytes = plainText.getBytes(characterEncoding);
//byte[] keyBytes = getKeyBytes(salt);
SecretKey key = generateKey(salt, passphrase);
byte[] ivBytes = hex(iv);
return Base64.getEncoder().encodeToString(encrypt(plainTextbytes,key, ivBytes));//, Base64.DEFAULT);
}
private static SecretKey generateKey(String salt, String passphrase) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new javax.crypto.spec.PBEKeySpec(passphrase.toCharArray(), hex(salt), 10000, 128);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "Rijndael");
return key;
}
catch (NoSuchAlgorithmException e) {
throw fail(e);
}
catch (InvalidKeySpecException e) {
throw fail(e);
}
}
public static String hex(byte[] bytes) {
return Hex.encodeHexString(bytes);
}
此代码还将 "guest" 加密为 "WsH/YEUqqrWDxD15zxsUPg=="。
这是我的 C# 代码:
public String Encrypt(String plainText, String passphrase, String salt, String iv, int iterations) {
var plainBytes = Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(Encrypt(plainBytes, GetSymmetricAlgorithm(passphrase, salt, iv, iterations)));
}
public byte[] Encrypt(byte[] plainBytes, SymmetricAlgorithm sa) {
return sa.CreateEncryptor().TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
public SymmetricAlgorithm GetSymmetricAlgorithm(String passphrase, String salt, String iv, int iterations) {
var saltBytes = new byte[16];
var ivBytes = new byte[16];
Rfc2898DeriveBytes rfcdb = new System.Security.Cryptography.Rfc2898DeriveBytes(passphrase, Encoding.UTF8.GetBytes(salt), iterations);
saltBytes = rfcdb.GetBytes(16);
var tempBytes = Encoding.UTF8.GetBytes(iv);
Array.Copy(tempBytes, ivBytes, Math.Min(ivBytes.Length, tempBytes.Length));
var rij = new RijndaelManaged(); //SymmetricAlgorithm.Create();
rij.Mode = CipherMode.CBC;
rij.Padding = PaddingMode.PKCS7;
rij.FeedbackSize = 128;
rij.KeySize = 128;
rij.BlockSize = 128;
rij.Key = saltBytes;
rij.IV = ivBytes;
return rij;
}
public byte[] Encrypt(byte[] plainBytes, SymmetricAlgorithm sa) {
return sa.CreateEncryptor().TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
此代码将 "guest" 加密为 "F8t0D0vA2rxU3Ez1O5artA=="。请注意,结果值是相同的长度,但它不是相同的值,并且不能用 Java 代码解密(我没有在此处提供 - 我主要关心将所有三种加密一样)。
有人能帮忙吗?提前致谢。
您在 JS 和 Java 中从十六进制解码 IV,但在 C# 中您有 var tempBytes = Encoding.UTF8.GetBytes(iv);
。您需要在 C# 中执行相同的十六进制解码。