- 明文 - 需要加密的内容
- 密钥 - 用于加密内容的密码
- 向量IV - 不知道作何解释,因为对加密原理不太了解,对向量长度有要求,16字节,PHP里面的mcrypt_encrypt函数可能需要32字节
JS环境下的加解密
var plaintText = '1234567812345678'; // 明文
var keyStr = '1234567812345678'; // 一般key为一个字符串
var iv = '1234567812345678';//向量IV
//首先计算密钥hash
//CryptoJS.PBKDF2第二个参数是salt,这里直接使用密码算了,实际应用中可以任意随机,但是加解密需要相同
var keyHash = CryptoJS.PBKDF2(keyStr, keyStr, {hasher:CryptoJS.algo.SHA256, keySize: 8, iterations: 1000 });
keyHash = keyHash();
iv = keyHash.substr(32, 16);
keyStr = keyHash.substr(0, 32);
var key = CryptoJS.enc.Utf8.parse(keyStr);
iv = CryptoJS.enc.Utf8.parse(iv);
var encryptedData = CryptoJS.AES.encrypt(plaintText, key, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv:iv
});
var encryptedBase64Str = encryptedData.toString();
console.log(encryptedBase64Str);//encryptedBase64Str就是最后生成的密文,已经base64过了
//解密
var decode = CryptoJS.AES.decrypt(encryptedBase64Str, key, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv:iv
});
var decodeStr = decode.toString(CryptoJS.enc.Utf8);
console.info(decodeStr);//decodeStr就是解密之后的明文
class AES{
const CIPHER = 'AES-256-CBC';
static $padding = OPENSSL_ZERO_PADDING;
public static function encode($str, $key){
$str = self::pkcs7padding($str, 32);
$key = hash_pbkdf2('sha256', $key, $key, 1000, 0, false);
$iv = substr($key, 32, 16);
$key = substr($key, 0, 32);
$data = openssl_encrypt($str, self::CIPHER, $key, self::$padding, $iv);
if(!$data){
var_dump(openssl_error_string());exit();
}
return $data;
}
public static function decode($data, $key){
//$data = base64_decode($data);
$key = hash_pbkdf2('sha256', $key, $key, 1000, 0, false);
$iv = substr($key, 32, 16);
$key = substr($key, 0, 32);
$res = openssl_decrypt($data, self::CIPHER, $key, self::$padding, $iv);
$res = self::pkcs7unPadding($res);
return $res;
}
public static function pkcs7padding($data, $blocksize) {
$padding = $blocksize - strlen($data) % $blocksize;
$padding_text = str_repeat(chr($padding), $padding);
return $data . $padding_text;
}
public static function pkcs7unPadding($data) {
$length = strlen($data);
$unpadding = ord($data[$length - 1]);
return substr($data, 0, $length - $unpadding);
}
}
import java.security.Security;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class AES {
public static String charset = "utf-8";
public static String encode(String data, String password) throws Exception {
byte[] bytes = aes(data.getBytes(charset), password, Cipher.ENCRYPT_MODE);
String encode = base64Encode(bytes);
return encode;
}
public static String decode(String data, String password) throws Exception {
byte[] base64Bytes = base64Decode(data);
byte[] bytes = aes(base64Bytes, password, Cipher.DECRYPT_MODE);
return new String(bytes);
}
private static byte[] aes(byte[] content, String password, int opmode) throws Exception{
Provider provider = new BouncyCastleProvider();
//这里传第二个参数,可以兼容android,PBKDF2WithHmacSHA256算法在最新的android8里面才支持
byte[] keys = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256", provider).generateSecret(new PBEKeySpec(password.toCharArray(), password.getBytes(), 1000, 256)).getEncoded();
//这里比较关键,不能把keys直接传给SecretKeySpec,一定要经过下面的转换才能跟PHP和js互通
String keyStr = bytesToHexString(keys);
IvParameterSpec ivParameterSpec = new IvParameterSpec(keyStr.substring(32, 48).getBytes());
keyStr = keyStr.substring(0, 32);
keys = keyStr.getBytes();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", provider );
cipher.init(opmode, new SecretKeySpec(keys, "AES"), ivParameterSpec);
return cipher.doFinal(content);
}
public static String base64Encode(byte[] data){
try {
return new String(Base64.getEncoder().encode(data), charset);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String base64Encode(String str){
try {
return base64Encode(str.getBytes(charset));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] base64Decode(String str){
try {
return Base64.getDecoder().decode(str.getBytes(charset));
} catch (Exception e1) {
e1.printStackTrace();
}
return null;
}
public static String bytesToHexString(byte[] src){
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}