在Golang中进行AES/CBC加密,然后在Angular中使用CryptoJS进行解密。

huangapple go评论90阅读模式
英文:

AES/CBC encrypt in golang,decrypt in angular CryptoJS

问题

我正在为你翻译代码部分,请稍等片刻。

Go代码:

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)

	result, err := Decrypt(encResult, secret)
	fmt.Println("decrypted result", result)
	fmt.Println("decryption err", err)
}

// 使用PKCS7填充,iOS也是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加密,填充16位的密钥,24位和32位分别对应AES-128,AES-192或AES-256。
func AESEncrypt(rawData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	// 填充原始数据
	blockSize := block.BlockSize()
	rawData = PKCS7Padding(rawData, blockSize)

	// 初始化向量IV必须是唯一的,但不需要保密
	cipherText := make([]byte, blockSize+len(rawData))
	iv := cipherText[:blockSize]

	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	// 块大小和初始向量大小必须相同
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(cipherText[blockSize:], rawData)

	return cipherText, nil
}

func AESDecrypt(encryptedData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	blockSize := block.BlockSize()

	if len(encryptedData) < blockSize {
		panic("ciphertext too short")
	}
	iv := encryptedData[:blockSize]
	encryptedData = encryptedData[blockSize:]

	// CBC模式总是以整个块为单位工作。
	if len(encryptedData)%blockSize != 0 {
		panic("ciphertext is not a multiple of the block size")
	}

	mode := cipher.NewCBCDecrypter(block, iv)

	// 如果两个参数相同,CryptBlocks可以原地工作。
	mode.CryptBlocks(encryptedData, encryptedData)

	// 取消填充
	encryptedData = PKCS7UnPadding(encryptedData)
	return encryptedData, nil
}

func Encrypt(rawData, key []byte) (string, error) {
	data, err := AESEncrypt(rawData, key)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(data), nil
}

func Decrypt(encryptedData string, key []byte) (string, error) {
	data, err := base64.StdEncoding.DecodeString(encryptedData)
	if err != nil {
		return "", err
	}
	decryptedData, err := AESDecrypt(data, key)
	if err != nil {
		return "", err
	}
	return string(decryptedData), 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中,iv的值应为16个零的十六进制字符串:"00000000000000000000000000000000"。

英文:

I'm trying to encrypt the data in Go and decrypt it in Angular using the AES CBC mode with PKCS7 padding.
But when I try to decrypt the data in Angular, Its not returning anything

Go Code:


package main
import (
&quot;bytes&quot;
&quot;crypto/aes&quot;
&quot;crypto/cipher&quot;
&quot;crypto/rand&quot;
&quot;encoding/base64&quot;
&quot;fmt&quot;
&quot;io&quot;
)
func main() {
secret := []byte(&quot;28cEVB4BUE7GKNwjuRhN3szK5E3!&amp;q*y&quot;)
data := []byte(&quot;Test&quot;)
encResult, err := Encrypt(data, secret)
fmt.Println(&quot;encResult&quot;, encResult)
fmt.Println(&quot;enc err&quot;, err)
//	encrypted := &quot;U2FsdGVkX1+LU7rE47VtIDwGIOsJa05BzOmAzQfdbVk=&quot;
result, err := Dncrypt(encResult, secret)
fmt.Println(&quot;decrypted result&quot;, result)
fmt.Println(&quot;decryption err&quot;, 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(&quot;iv&quot;, 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) &lt; blockSize {
panic(&quot;ciphertext too short&quot;)
}
iv := encryptData[:blockSize]
encryptData = encryptData[blockSize:]
// CBC mode always works in whole blocks.
if len(encryptData)%blockSize != 0 {
panic(&quot;ciphertext is not a multiple of the block size&quot;)
}
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 &quot;&quot;, 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 &quot;&quot;, err
}
dnData, err := AesCBCDncrypt(data, key)
if err != nil {
return &quot;&quot;, err
}
return string(dnData), nil
}

Angular/CryptoJs Code:

var CryptoJS = require(&quot;crypto-js&quot;);
var iv   = CryptoJS.enc.Hex.parse(&quot;00000000000000000000000000000000&quot;);
var decrypted= CryptoJS.AES.decrypt(&quot;hKZ8CZgDopjCthfVZf7VmkSlX00nAJXpzNPRIUhGsO8=&quot;,&quot;28cEVB4BUE7GKNwjuRhN3szK5E3!&amp;q*y&quot;,{iv:iv, padding: CryptoJS.pad.Pkcs7})
console.log(&quot;decrypted&quot;,decrypted.toString());  

I'm getting an empty response from the cryptoJS decrypt method.

What should be the value of iv for cryptoJS ?

答案1

得分: 1

尝试这个,确保你在加密和解密时使用相同的密钥。

// get方法用于解密值。
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);
}
英文:

Try this, make sure you are using same key for encryption and decryption

//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);
}

答案2

得分: 1

这段代码使用Go语言生成一个随机的IV,并使用AES-256算法以CBC模式和PKCS7填充进行加密。IV与密文进行拼接,形成IV|ciphertext,然后对结果进行Base64编码。密钥是通过对给定字符串进行UTF-8编码生成的。

需要注意的是,Go代码中的以下部分:

if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    panic(err)
}

使用随机值初始化了IV。因此,IV的输出应该在此之后。由于在发布的代码中它被打印在之前,所以显示了一个零IV,但实际上并不对应使用的IV。另外,对于解密来说,不需要显式输出,因为代码已经将IV和密文拼接在一起。

在CryptoJS代码中,使用了一个零IV,可能是因为Go代码的输出有误。相反,IV和密文必须分开处理。此外,密钥被作为字符串传递是不正确的,因为CryptoJS将字符串解释为密码,并执行基于密码的密钥派生。相反,密钥必须作为WordArray传递。由于Go代码中的密钥是UTF-8编码的,因此必须应用UTF-8编码器(参见其他答案)。

CBC和PKCS7填充是默认值,可以指定,但不是必需的。

以下CryptoJS代码中的密文是使用Go代码生成的:

// 分离IV和密文
var data = CryptoJS.enc.Base64.parse("WL7oDghTeEbjZ6QPeb/TGuDGijktQ4PZS7+wd0Ayu8Y="); // 来自Go代码
var iv = CryptoJS.lib.WordArray.create(data.words.slice(0, 4));    // 前4个字 = 16字节
var ct = CryptoJS.lib.WordArray.create(data.words.slice(4));       // 剩下的

// 解密
var decrypted = CryptoJS.AES.decrypt(
    {ciphertext: ct},                                              // 或者作为Base64编码的字符串
    CryptoJS.enc.Utf8.parse("28cEVB4BUE7GKNwjuRhN3szK5E3!&q*y"),   // 对密钥字符串进行UTF-8编码
    {iv:iv}
);

console.log("解密结果: ", decrypted.toString(CryptoJS.enc.Utf8)); // 解密结果: Test

这段代码将密文正确解密为Test

英文:

The Go code generates a random IV and performs encryption using AES-256 in CBC mode with PKCS7 padding. The IV is concatenated with the ciphertext, IV|ciphertext, and the result is Base64 encoded. The key is generated from the given string by Utf8 encoding.

Note that the Go code

if _, err := io.ReadFull(rand.Reader, iv); err != nil {
    panic(err)
}

initializes the IV with random values. So the output of the IV should be after that. Since it is printed before in the posted code, a zero IV is displayed, which however does not correspond to the IV used.<br>
By the way, for decryption the explicit output is not necessary, because as already mentioned the code concatenates IV and ciphertext.


In the CryptoJS code, a zero IV is used, probably because of the incorrect output in the Go code. Instead, the IV and ciphertext must be separated.<br>
Also, the key is passed as a string. This is incorrect because CryptoJS interprets a string as a password and performs a password-based key derivation. Instead, the key must be passed as a WordArray.<br>
Since the key is Utf8 encoded in the Go Code, the Utf8 encoder must be applied (see also the other answer).

CBC and PKCS7 padding are the default values and can, but need not, be specified.


The ciphertext in the following CryptoJS code was generated using the Go code:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

// Separate IV and ciphertext
var data   = CryptoJS.enc.Base64.parse(&quot;WL7oDghTeEbjZ6QPeb/TGuDGijktQ4PZS7+wd0Ayu8Y=&quot;); // 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(&quot;28cEVB4BUE7GKNwjuRhN3szK5E3!&amp;q*y&quot;),   // Utf8 encode key string
{iv:iv}
);
console.log(&quot;Decrypted: &quot;, decrypted.toString(CryptoJS.enc.Utf8)); // Decrypted:  Test

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

and decrypts the ciphertext correctly into Test.

huangapple
  • 本文由 发表于 2021年7月15日 16:36:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/68390508.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定