Loading

AES 加解密(前后端)

AES 加解密(前后端)

加密

前端加密:

aesEncrypt(plainText: string, key: string) {
    const key = CryptoJS.enc.Latin1.parse(key);
    const iv = CryptoJS.enc.Latin1.parse('1234567890123456');
    const encrypted = CryptoJS.AES.encrypt(plainText, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.ZeroPadding // CryptoJS.pad.ZeroPadding, CryptoJS.pad.Pkcs7
    });
    return encrypted.toString();
}

调用时的打印结果:

// padding = CryptoJS.pad.ZeroPadding
aesEncrypt("123456", "ABCDEFGHIJKLMNOP"); // 83MCLn7rL5/P2eXEyBzPDQ==
aesEncrypt("123456", "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"); // ebUKt3ZWeU78On/hns7W1w==

// padding = CryptoJS.pad.Pkcs7
aesEncrypt("123456", "ABCDEFGHIJKLMNOP"); // d1R21TsRewTG3mRIeYnIWw==
aesEncrypt("123456", "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"); // uCvloRIqYLLJauF5EpIuGA==

// 
aesEncrypt("123456"); // padding = CryptoJS.pad.NoPadding -> 83MCLn7r

后端PHP加密,OPENSSL_ZERO_PADDING 方式(0补位,不推荐这种方式,所以补位的逻辑需要自行实现):

$key = 'ABCDEFGHIJKLMNOP';
$iv = '1234567890123456';
$blockSize = 16;
$planText = "123456";
if (strlen($planText) % $blockSize) {
    $planText = str_pad($planText, strlen($planText) + $blockSize - strlen($planText) % $blockSize, "\0");
}
// key 是 16 位,对应 AES-128-CBC
$encrypted = openssl_encrypt($planText, "AES-128-CBC", $key, OPENSSL_ZERO_PADDING, $iv); // 83MCLn7rL5/P2eXEyBzPDQ==

// key 是 32 位,对应 AES-256-CBC
$key = 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP';
$encrypted = openssl_encrypt($planText, "AES-256-CBC", $key, OPENSSL_ZERO_PADDING, $iv); // ebUKt3ZWeU78On/hns7W1w==

// 如果 key 是 24 位的,对应的是 AES-192-CBC

后端PHP加密,OPENSSL_RAW_DATA 方式(PKCS7补位):

// https://www.php.net/manual/zh/openssl.constants.other.php#constant.openssl-raw-data
// openssl_encrypt 中如果设置了 OPENSSL_RAW_DATA 将原样返回,没有设置时返回的是 base64
$encrypted = openssl_encrypt($planText, "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv);
// 需要 base64_encode 一下
$encrypted = base64_encode($encrypted); // d1R21TsRewTG3mRIeYnIWw==

$key = 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP';
$encrypted = openssl_encrypt($planText, "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv);
$encrypted  = base64_encode($encrypted); // uCvloRIqYLLJauF5EpIuGA==

后端 go 加密,PKCS7:

// AesEncrypt 加密
func AesEncrypt(plainText string, key string, iv string) (string, error) {
	// 创建加密实例
	keyBytes := []byte(key)
	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		return "", err
	}
	data := []byte(plainText)
	ivBytes := []byte(iv) // 不使用手动指定的 iv 时,可以使用 key 的前 blockSize 位
	// 加密快的大小
	blockSize := block.BlockSize()
	// 填充
	encryptBytes := pkcs7Padding(data, blockSize)
	// 初始化加密数据接收切片
	crypted := make([]byte, len(encryptBytes))
	// CBC 加密模式
	blockMode := cipher.NewCBCEncrypter(block, ivBytes)
	// 加密
	blockMode.CryptBlocks(crypted, encryptBytes)
	// 转为 base64 格式
	return base64.StdEncoding.EncodeToString(crypted), nil
}

// pkcs7Padding 填充
func pkcs7Padding(data []byte, blockSize int) []byte {
	// 补位长度,最少1,最多 blockSize
	padding := blockSize - len(data)%blockSize
	// 补位 padding 个 padding
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

func main() {
	key := "ABCDEFGHIJKLMNOP"
	iv := "1234567890123456"
	crypted, _ := AesEncrypt("123456", key, iv)
	fmt.Println("crypted =", crypted) // crypted = d1R21TsRewTG3mRIeYnIWw==

    key = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
	crypted, _ = aes.AesEncrypt("123456", key, iv)
	fmt.Println("key = ", key, ", crypted =", crypted) // crypted = uCvloRIqYLLJauF5EpIuGA==
}

零补位时,padText := bytes.Repeat([]byte{byte(padding)}, padding)​ -> padText := bytes.Repeat([]byte{0}, padding)​:

// 方法名 zeroPadding
func zeroPadding(data []byte, blockSize int) []byte {
	// 补位长度,最少1,最多 blockSize
	padding := blockSize - len(data)%blockSize
	// 补位 padding 个 padding
	padText := bytes.Repeat([]byte{0}, padding)
	return append(data, padText...)
}

func main() {
	key := "ABCDEFGHIJKLMNOP"
	iv := "1234567890123456"
	crypted, _ := AesEncrypt("123456", key, iv)
	fmt.Println("crypted =", crypted) // crypted = 83MCLn7rL5/P2eXEyBzPDQ==

    key = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
	crypted, _ = aes.AesEncrypt("123456", key, iv)
	fmt.Println("key = ", key, ", crypted =", crypted) // crypted = ebUKt3ZWeU78On/hns7W1w==
}

解密

前端解密:

aesDecrypt(encrypted: string, key: string) {
    const SECRET_KEY  = CryptoJS.enc.Latin1.parse(key);
    const SECRET_IV = CryptoJS.enc.Latin1.parse('1234567890123456');
    const decrypted = CryptoJS.AES.decrypt(encrypted, SECRET_KEY, {
        iv: SECRET_IV,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.ZeroPadding // CryptoJS.pad.ZeroPadding, CryptoJS.pad.Pkcs7
    });

    return decrypted.toString(CryptoJS.enc.Utf8);
}

打印结果:

// padding = CryptoJS.pad.ZeroPadding
aesDecrypt("83MCLn7rL5/P2eXEyBzPDQ==", "ABCDEFGHIJKLMNOP")); // 123456
aesDecrypt("ebUKt3ZWeU78On/hns7W1w==", "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"); // 123456


// padding = CryptoJS.pad.Pkcs7
aesDecrypt("d1R21TsRewTG3mRIeYnIWw==", "ABCDEFGHIJKLMNOP"))
aesDecrypt("uCvloRIqYLLJauF5EpIuGA==", "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")

后端PHP解密,OPENSSL_ZERO_PADDING 方式:

$key = 'ABCDEFGHIJKLMNOP';
$iv = '1234567890123456';
$encrypted = '83MCLn7rL5/P2eXEyBzPDQ==';
$decrypted = openssl_decrypt($encrypted, 'AES-128-CBC', $key, OPENSSL_ZERO_PADDING, $iv); // 123456\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
// 去除补位的 0
$decrypted = rtrim($decrypted, chr(0)); // 123456

$key = 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP';
$encrypted = 'ebUKt3ZWeU78On/hns7W1w==';
$decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', $key, OPENSSL_ZERO_PADDING, $iv); // 123456\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
$decrypted = rtrim($decrypted, chr(0)); // 123456

后端PHP解密,OPENSSL_RAW_DATA 方式:

$iv = '1234567890123456';
$key = 'ABCDEFGHIJKLMNOP';
$encrypted = 'd1R21TsRewTG3mRIeYnIWw==';
$decrypted = openssl_decrypt(base64_decode($encrypted), 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv); // 123456

$key = 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP';
$encrypted = 'uCvloRIqYLLJauF5EpIuGA==';
$decrypted = openssl_decrypt(base64_decode($encrypted), 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv); // 123456

后端 go 解密,PKCS7:

// AesDecrypt 解密
func AesDecrypt(cryptedText string, key string, iv string) (string, error) {
	data, err := base64.StdEncoding.DecodeString(cryptedText)
	if err != nil {
		return "", err
	}

	keyBytes := []byte(key)
	// 创建实例
	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		return "", err
	}
	ivBytes := []byte(iv)
	blockMode := cipher.NewCBCDecrypter(block, ivBytes)
	// 初始化解密数据接收切片
	crypted := make([]byte, len(data))
	// 解密
	blockMode.CryptBlocks(crypted, data)
	// 去除填充
	crypted, err = pkcs7UnPadding(crypted)
	if err != nil {
		return "", err
	}
	return string(crypted), nil
}

// pkcs7UnPadding
func pkcs7UnPadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, errors.New("加密字符串错误!")
	}
	// 补位个数
	unPadding := int(data[length-1])
	return data[:(length - unPadding)], nil
}

func main() {
	key := "ABCDEFGHIJKLMNOP"
	iv := "1234567890123456"
	decrypted, _ := AesDecrypt("d1R21TsRewTG3mRIeYnIWw==", key, iv)
	fmt.Println("decrypted =", decrypted) // decrypted = 123456

	key = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
	decrypted, _ = AesDecrypt("uCvloRIqYLLJauF5EpIuGA==", key, iv)
	fmt.Println("decrypted =", decrypted) // decrypted = 123456
}

零补位时,补位的长度需要计算

// ZeroUnpadding
func ZeroUnPadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, errors.New("加密字符串错误!")
	}
	unPadding := 0
	for i := length - 1; i >= 0; i-- {
		if data[i] == 0 {
			unPadding++
		} else {
			break
		}
	}
	if unPadding == 0 {
		return nil, errors.New("加密字符串错误,没有补位长度!")
	}
	return data[:length-unPadding], nil
}

func main() {
	key := "ABCDEFGHIJKLMNOP"
	iv := "1234567890123456"
	decrypted, _ := AesDecrypt("83MCLn7rL5/P2eXEyBzPDQ==", key, iv)
	fmt.Println("decrypted =", decrypted) // decrypted = 123456

	key = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
	decrypted, _ = AesDecrypt("ebUKt3ZWeU78On/hns7W1w==", key, iv)
	fmt.Println("decrypted =", decrypted) // decrypted = 123456
}
posted @ 2024-03-15 20:44  zhpj  阅读(86)  评论(0)    收藏  举报