AES/CBC 在 golang 中加密,在 angular CryptoJS 中解密
AES/CBC encrypt in golang,decrypt in angular CryptoJS
我正在尝试使用带有 PKCS7 填充的 AES CBC 模式在 Go 中加密数据并在 Angular 中解密。
但是当我尝试解密 Angular 中的数据时,它没有返回任何东西
转到代码:
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
)
func main() {
secret := []byte("28cEVB4BUE7GKNwjuRhN3szK5E3!&q*y")
data := []byte("Test")
encResult, err := Encrypt(data, secret)
fmt.Println("encResult", encResult)
fmt.Println("enc err", err)
// encrypted := "U2FsdGVkX1+LU7rE47VtIDwGIOsJa05BzOmAzQfdbVk="
result, err := Dncrypt(encResult, secret)
fmt.Println("decrypted result", result)
fmt.Println("decryption err", err)
}
/*CBC encryption Follow the example code of the golang standard library
But there is no padding inside, so make up
*/
// Use PKCS7 to fill, IOS is also 7
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
//aes encryption, filling the 16 bits of the key key, 24, 32 respectively corresponding to AES-128, AES-192, or AES-256.
func AesCBCEncrypt(rawData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
//fill the original
blockSize := block.BlockSize()
rawData = PKCS7Padding(rawData, blockSize)
// Initial vector IV must be unique, but does not need to be kept secret
cipherText := make([]byte, blockSize+len(rawData))
//block size 16
iv := cipherText[:blockSize]
fmt.Println("iv", iv)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
//block size and initial vector size must be the same
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(cipherText[blockSize:], rawData)
return cipherText, nil
}
func AesCBCDncrypt(encryptData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
blockSize := block.BlockSize()
if len(encryptData) < blockSize {
panic("ciphertext too short")
}
iv := encryptData[:blockSize]
encryptData = encryptData[blockSize:]
// CBC mode always works in whole blocks.
if len(encryptData)%blockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(encryptData, encryptData)
// Unfill
encryptData = PKCS7UnPadding(encryptData)
return encryptData, nil
}
func Encrypt(rawData, key []byte) (string, error) {
data, err := AesCBCEncrypt(rawData, key)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(data), nil
}
func Dncrypt(rawData string, key []byte) (string, error) {
data, err := base64.StdEncoding.DecodeString(rawData)
if err != nil {
return "", err
}
dnData, err := AesCBCDncrypt(data, key)
if err != nil {
return "", err
}
return string(dnData), nil
}
Angular/CryptoJs代码:
var CryptoJS = require("crypto-js");
var iv = CryptoJS.enc.Hex.parse("00000000000000000000000000000000");
var decrypted= CryptoJS.AES.decrypt("hKZ8CZgDopjCthfVZf7VmkSlX00nAJXpzNPRIUhGsO8=","28cEVB4BUE7GKNwjuRhN3szK5E3!&q*y",{iv:iv, padding: CryptoJS.pad.Pkcs7})
console.log("decrypted",decrypted.toString());
我从 cryptoJS 解密方法收到空响应。
cryptoJS 的 iv 值应该是多少?
试试这个,确保您使用相同的密钥进行加密和解密
//The get method is use for decrypt the value.
get(keys, value){
var key = CryptoJS.enc.Utf8.parse(keys);
var iv = CryptoJS.enc.Utf8.parse(keys);
var decrypted = CryptoJS.AES.decrypt(value, key, {
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
Go 代码生成一个随机 IV,并在 CBC 模式下使用 AES-256 和 PKCS7 填充执行加密。 IV 与密文 IV|ciphertext
连接,结果经过 Base64 编码。密钥是通过 Utf8 编码从给定的字符串生成的。
注意 Go 代码
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
用随机值初始化 IV。所以 IV 的输出应该在那之后。由于它在发布的代码中 before 打印,因此显示零 IV,但这与使用的 IV 不对应。
顺便说一句,对于解密,显式输出不是必需的,因为如前所述,代码连接了 IV 和密文。
在 CryptoJS 代码中,使用零 IV,可能是因为 Go 代码中的输出不正确。相反,IV 和密文必须分开。
此外,密钥作为字符串传递。这是不正确的,因为 CryptoJS 将字符串解释为密码并执行基于密码的密钥派生。相反,密钥必须作为 WordArray
.
传递
由于密钥在 Go 代码中是 Utf8 编码的,因此必须应用 Utf8 编码器(另请参阅 )。
CBC 和 PKCS7 填充是默认值,可以但不必指定。
以下CryptoJS代码中的密文是使用Go代码生成的:
// Separate IV and ciphertext
var data = CryptoJS.enc.Base64.parse("WL7oDghTeEbjZ6QPeb/TGuDGijktQ4PZS7+wd0Ayu8Y="); // from Go code
var iv = CryptoJS.lib.WordArray.create(data.words.slice(0, 4)); // first 4 words = 16 bytes
var ct = CryptoJS.lib.WordArray.create(data.words.slice(4)); // rest
// Decrypt
var decrypted = CryptoJS.AES.decrypt(
{ciphertext: ct}, // alternatively as Base64 encoded string
CryptoJS.enc.Utf8.parse("28cEVB4BUE7GKNwjuRhN3szK5E3!&q*y"), // Utf8 encode key string
{iv:iv}
);
console.log("Decrypted: ", decrypted.toString(CryptoJS.enc.Utf8)); // Decrypted: Test
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
并将密文正确解密为Test
.
我正在尝试使用带有 PKCS7 填充的 AES CBC 模式在 Go 中加密数据并在 Angular 中解密。 但是当我尝试解密 Angular 中的数据时,它没有返回任何东西
转到代码:
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
)
func main() {
secret := []byte("28cEVB4BUE7GKNwjuRhN3szK5E3!&q*y")
data := []byte("Test")
encResult, err := Encrypt(data, secret)
fmt.Println("encResult", encResult)
fmt.Println("enc err", err)
// encrypted := "U2FsdGVkX1+LU7rE47VtIDwGIOsJa05BzOmAzQfdbVk="
result, err := Dncrypt(encResult, secret)
fmt.Println("decrypted result", result)
fmt.Println("decryption err", err)
}
/*CBC encryption Follow the example code of the golang standard library
But there is no padding inside, so make up
*/
// Use PKCS7 to fill, IOS is also 7
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
//aes encryption, filling the 16 bits of the key key, 24, 32 respectively corresponding to AES-128, AES-192, or AES-256.
func AesCBCEncrypt(rawData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
//fill the original
blockSize := block.BlockSize()
rawData = PKCS7Padding(rawData, blockSize)
// Initial vector IV must be unique, but does not need to be kept secret
cipherText := make([]byte, blockSize+len(rawData))
//block size 16
iv := cipherText[:blockSize]
fmt.Println("iv", iv)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
//block size and initial vector size must be the same
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(cipherText[blockSize:], rawData)
return cipherText, nil
}
func AesCBCDncrypt(encryptData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
blockSize := block.BlockSize()
if len(encryptData) < blockSize {
panic("ciphertext too short")
}
iv := encryptData[:blockSize]
encryptData = encryptData[blockSize:]
// CBC mode always works in whole blocks.
if len(encryptData)%blockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(encryptData, encryptData)
// Unfill
encryptData = PKCS7UnPadding(encryptData)
return encryptData, nil
}
func Encrypt(rawData, key []byte) (string, error) {
data, err := AesCBCEncrypt(rawData, key)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(data), nil
}
func Dncrypt(rawData string, key []byte) (string, error) {
data, err := base64.StdEncoding.DecodeString(rawData)
if err != nil {
return "", err
}
dnData, err := AesCBCDncrypt(data, key)
if err != nil {
return "", err
}
return string(dnData), nil
}
Angular/CryptoJs代码:
var CryptoJS = require("crypto-js");
var iv = CryptoJS.enc.Hex.parse("00000000000000000000000000000000");
var decrypted= CryptoJS.AES.decrypt("hKZ8CZgDopjCthfVZf7VmkSlX00nAJXpzNPRIUhGsO8=","28cEVB4BUE7GKNwjuRhN3szK5E3!&q*y",{iv:iv, padding: CryptoJS.pad.Pkcs7})
console.log("decrypted",decrypted.toString());
我从 cryptoJS 解密方法收到空响应。
cryptoJS 的 iv 值应该是多少?
试试这个,确保您使用相同的密钥进行加密和解密
//The get method is use for decrypt the value.
get(keys, value){
var key = CryptoJS.enc.Utf8.parse(keys);
var iv = CryptoJS.enc.Utf8.parse(keys);
var decrypted = CryptoJS.AES.decrypt(value, key, {
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
Go 代码生成一个随机 IV,并在 CBC 模式下使用 AES-256 和 PKCS7 填充执行加密。 IV 与密文 IV|ciphertext
连接,结果经过 Base64 编码。密钥是通过 Utf8 编码从给定的字符串生成的。
注意 Go 代码
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
用随机值初始化 IV。所以 IV 的输出应该在那之后。由于它在发布的代码中 before 打印,因此显示零 IV,但这与使用的 IV 不对应。
顺便说一句,对于解密,显式输出不是必需的,因为如前所述,代码连接了 IV 和密文。
在 CryptoJS 代码中,使用零 IV,可能是因为 Go 代码中的输出不正确。相反,IV 和密文必须分开。
此外,密钥作为字符串传递。这是不正确的,因为 CryptoJS 将字符串解释为密码并执行基于密码的密钥派生。相反,密钥必须作为 WordArray
.
传递
由于密钥在 Go 代码中是 Utf8 编码的,因此必须应用 Utf8 编码器(另请参阅
CBC 和 PKCS7 填充是默认值,可以但不必指定。
以下CryptoJS代码中的密文是使用Go代码生成的:
// Separate IV and ciphertext
var data = CryptoJS.enc.Base64.parse("WL7oDghTeEbjZ6QPeb/TGuDGijktQ4PZS7+wd0Ayu8Y="); // from Go code
var iv = CryptoJS.lib.WordArray.create(data.words.slice(0, 4)); // first 4 words = 16 bytes
var ct = CryptoJS.lib.WordArray.create(data.words.slice(4)); // rest
// Decrypt
var decrypted = CryptoJS.AES.decrypt(
{ciphertext: ct}, // alternatively as Base64 encoded string
CryptoJS.enc.Utf8.parse("28cEVB4BUE7GKNwjuRhN3szK5E3!&q*y"), // Utf8 encode key string
{iv:iv}
);
console.log("Decrypted: ", decrypted.toString(CryptoJS.enc.Utf8)); // Decrypted: Test
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
并将密文正确解密为Test
.