我正在开发一项功能,该功能需要 Aes 加密(AES/CBC/PKCS5padding)密文从客户端发送到后端有 ASP.Net 的服务器。
我在服务器端有一个解密功能,如下所示:
public static string Decrypt(string inputBase64, string passphrase = null)
{
byte[] key, iv = new byte[0];
byte[] base64data = Convert.FromBase64String(inputBase64);
byte[] passphrasedata = RawBytesFromString(passphrase);
byte[] currentHash = new byte[0];
SHA256Managed hash = new SHA256Managed();
currentHash = hash.ComputeHash(passphrasedata);
return DecryptStringFromBytes(base64data, currentHash, null);
}
static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
//if (IV == null || IV.Length <= 0)
// throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (var cipher = new RijndaelManaged())
{
cipher.Key = Key;
cipher.IV = new byte[16];
//cipher.Mode = CipherMode.CBC;
//cipher.Padding = PaddingMode.PKCS7;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = cipher.CreateDecryptor(Key, cipher.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
var bytes = default(byte[]);
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
bytes = srDecrypt.CurrentEncoding.GetBytes(srDecrypt.ReadToEnd());
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
//aintext = srDecrypt.ReadToEnd();
}
plaintext = ASCIIEncoding.UTF8.GetString(bytes, 0, bytes.Count());
}
}
}
return plaintext;
}
Run Code Online (Sandbox Code Playgroud)
我想实现以下 android 代码的 angularjs 替代方案:
public static String Encrypt(String input, String passphrase)
{
if (input.equalsIgnoreCase("") || passphrase.equalsIgnoreCase(""))
return "";
else
{
byte[] key, iv;
byte[] passphrasedata = null;
try
{
passphrasedata = passphrase.getBytes("UTF-8");
}
catch (UnsupportedEncodingException e1)
{
e1.printStackTrace();
}
byte[] currentHash = new byte[0];
MessageDigest md = null;
try
{
md = MessageDigest.getInstance("SHA-256");
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
currentHash = md.digest(passphrasedata);
iv = new byte[16];
return Base64.encodeToString(EncryptStringToBytes(input, currentHash, iv), Base64.NO_WRAP);
}
}
static byte[] EncryptStringToBytes(String plainText, byte[] Key, byte[] IV)
{
if (plainText == null || plainText.length() <= 0)
{
Log.e("error", "plain text empty");
}
if (Key == null || Key.length <= 0)
{
Log.e("error", "key is empty");
}
if (IV == null || IV.length <= 0)
{
Log.e("error", "IV key empty");
}
byte[] encrypted;
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(Key, "AES");
IvParameterSpec IVKey = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, myKey, IVKey);
encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
return encrypted;
}
catch (InvalidKeyException e)
{
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace();
}
catch (InvalidAlgorithmParameterException e)
{
e.printStackTrace();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace();
}
catch (BadPaddingException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
上面的 Android 代码运行良好。我想在 AngularJs 上实现相同的加密逻辑。
我已经包含了用于 SHA-256 和 AES 密码计算的 CryptoJS 库。这是我实现的代码。
var password = '12345678';
var passwordHash = CryptoJS.SHA256(password).toString(CryptoJS.enc.Latin1);
var iv = CryptoJS.enc.Hex.parse('0000000000000000');
var cipher = CryptoJS.AES.encrypt(plaintext,passwordHash,{
iv: iv,
mode: CryptoJS.mode.CBC,
keySize: 256/32,
padding: CryptoJS.pad.Pkcs7
});
cipherText = cipher.ciphertext.toString(CryptoJS.enc.Base64);
Run Code Online (Sandbox Code Playgroud)
问题在于,编码后的字符串无法解密回其先前的形式。我认为客户端的加密逻辑和服务器端的解密逻辑存在一些不匹配。
当我将 CryptoJS 加密密码传递给 java 解密函数时,它显示错误:
javax.crypto.IllegalBlockSizeException:使用填充密码解密时,输入长度必须是 16 的倍数
或有时:
javax.crypto.BadPaddingException:给定的最终块未正确填充
谢谢大家!!!,我用下面的代码让它工作。
function hash (){
return CryptoJS.SHA256(password);
}
var cipher = (function(plaintext, password) {
passwordHash = hash(password);
var iv = CryptoJS.enc.Hex.parse('0000000000000000');
var cipher = CryptoJS.AES.encrypt(plaintext, passwordHash, {
iv: iv,
mode: CryptoJS.mode.CBC,
keySize: 256 / 32,
padding: CryptoJS.pad.Pkcs7
});
return cipher;
})(plaintext, password);
cipherBase64 = cipher.ciphertext.toString().hex2a().base64Encode();
Run Code Online (Sandbox Code Playgroud)