VBC
VBC

Reputation: 301

AES/CBC encrypt in golang,decrypt in angular CryptoJS

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

Answers (2)

Topaco
Topaco

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

vinay jain
vinay jain

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

Related Questions