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());  

我从 c​​ryptoJS 解密方法收到空响应。

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.