Reputation: 301
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 (
"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 Code:
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());
I'm getting an empty response from the cryptoJS decrypt method.
What should be the value of iv for cryptoJS ?
Upvotes: 0
Views: 2937
Reputation: 49111
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.
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.
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
.
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:
// 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>
and decrypts the ciphertext correctly into Test
.
Upvotes: 1
Reputation: 93
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);
}
Upvotes: 1