在多语言的生产环境下,常常是由一种语言进行加密而由另一种语言来进行解密,因此有必要保持各种语言之间加密解密算法的一致性。下面列出了Go,Nodejs,Java 的 Aes-128-Cbc的加密解密算法,它们的加解密结果是一致的。CBC比ECB加密强度更大,更难破解。
Go 1.15
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
)
func AesEncryptCBC(origDataStr string, keystr string) string {
origData := []byte(origDataStr)
key := []byte(keystr)
// 分组秘钥
// NewCipher该函数限制了输入k的长度必须为16, 24或者32
block, _ := aes.NewCipher(key)
blockSize := block.BlockSize() // 获取秘钥块的长度
origData = pkcs5Padding(origData, blockSize) // 补全码
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) // 加密模式
encrypted := make([]byte, len(origData)) // 创建数组
blockMode.CryptBlocks(encrypted, origData) // 加密
return hex.EncodeToString(encrypted)
}
func AesDecryptCBC(ciphertext string, keystr string) (string, error) {
encrypted, err := hex.DecodeString(ciphertext)
if err != nil {
return "", err
}
key := []byte(keystr)
block, _ := aes.NewCipher(key) // 分组秘钥
blockSize := block.BlockSize() // 获取秘钥块的长度
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) // 加密模式
decrypted := make([]byte, len(encrypted)) // 创建数组
blockMode.CryptBlocks(decrypted, encrypted) // 解密
decrypted = pkcs5UnPadding(decrypted) // 去除补全码
return string(decrypted), nil
}
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func pkcs5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
func main() {
origData := "863861057163595" // 待加密的数据
key := "sykKwe59_q11peDz" // 16字节加密的密钥
fmt.Printf("原 文:%s\n", origData)
encrypted := AesEncryptCBC(origData, key)
fmt.Printf("加密结果:%s\n", encrypted)
decrypted, err := AesDecryptCBC(encrypted, key)
if err != nil {
panic(err)
}
fmt.Printf("解密结果:%s\n", decrypted)
}
Nodejs 8.16
crypto = require("crypto");
aesEncrypt = function(plaintext, key) {
var cip, encrypted;
encrypted = '';
cip = crypto.createCipheriv('aes-128-cbc', key, key);
encrypted += cip.update(plaintext, 'binary', 'hex');
encrypted += cip.final('hex');
return encrypted;
};
aesDecrypt = function(encrypted, key) {
var _decipher, decrypted, err;
decrypted = '';
_decipher = crypto.createDecipheriv('aes-128-cbc', key, key);
decrypted += _decipher.update(encrypted, 'hex', 'binary');
decrypted += _decipher.final('binary');
return decrypted;
};
let key = "sykKwe59_q11peDz"
let plaintext = "863861057163595"
console.log("原 文:" + plaintext);
try {
let encrypted = aesEncrypt(plaintext, key);
console.log("加密结果:" + encrypted);
console.log("解密结果:" + aesDecrypt(encrypted, key));
} catch(err) {
console.log(err)
}
Java 1.8
package com.basic;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class AesCbc {
private static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex);
}
return sb.toString();
}
public static String encrypt(String value, String key) {
try {
IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
// cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(value.getBytes());
return parseByte2HexStr(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
private static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++) {
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
}
return result;
}
public static String decrypt(String encrypted, String key) {
try {
IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
// cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(toByte(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String key = "sykKwe59_q11peDz";
String originalString = "863861057163595";
System.out.println("原 文:" + originalString);
String encryptedString = encrypt(originalString, key);
System.out.println("加密结果:" + encryptedString);
String decryptedString = decrypt(encryptedString, key);
System.out.println("解密结果:" + decryptedString);
}
}
输出:
原 文:863861057163595
加密结果:b95ba57ea11449c36e1d4130dade4efa
解密结果:863861057163595
相关文章:
《Go Nodejs Java Aes 128 ECB加密解密结果保持一致》
参考文章:
《nodejs和java的AES加密结果保持一致》
《golang的AES加密和解密的三种模式实现(CBC/ECB/CFB)》