Skip to content

Instantly share code, notes, and snippets.

@wudi
Forked from brettscott/aes-256-cbc-test.js
Created January 24, 2021 04:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wudi/2b5bc51f61d9dcac346bf708eb1d0a75 to your computer and use it in GitHub Desktop.
Save wudi/2b5bc51f61d9dcac346bf708eb1d0a75 to your computer and use it in GitHub Desktop.
AES 256 CBC encryption between Golang and Node JS
// Node v6.9.0
//
// TEST FILE (cut down for simplicity)
// To ensure Golang encrypted string can be decrypted in NodeJS.
//
let crypto;
try {
crypto = require('crypto');
} catch (err) {
console.log('crypto support is disabled!');
}
const ALGORITHM = 'aes-256-cbc';
const CIPHER_KEY = "abcdefghijklmnopqrstuvwxyz012345"; // Same key used in Golang
const BLOCK_SIZE = 16;
const plainText = "1234567890"; // This plainText was encrypted to make the cipherText below by Golang
const cipherText = "f17ba46472fa64e40ca496d1b4c91e8fac967926dfbdd7097b4c8f8ebd18f898"; // hexidecimal cipherText created by Golang
const decrypted = decrypt(cipherText);
if (decrypted !== plainText) {
console.log(`FAILED: expected ${plainText} but got "${decrypted}"`);
} else {
console.log(`PASSED: ${plainText}`);
}
// Decrypts cipher text into plain text
function decrypt(cipherText) {
const contents = Buffer.from(cipherText, 'hex');
const iv = contents.slice(0, BLOCK_SIZE);
const textBytes = contents.slice(BLOCK_SIZE);
const decipher = crypto.createDecipheriv(ALGORITHM, CIPHER_KEY, iv);
let decrypted = decipher.update(textBytes, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
// Encrypts plain text into cipher text
function encrypt(plainText) {
const iv = crypto.randomBytes(BLOCK_SIZE);
const cipher = crypto.createCipheriv(ALGORITHM, CIPHER_KEY, iv);
let cipherText;
try {
cipherText = cipher.update(plainText, 'utf8', 'hex');
cipherText += cipher.final('hex');
cipherText = iv.toString('hex') + cipherText
} catch (e) {
cipherText = null;
}
return cipherText;
}
// Golang v1.8
package blahblah
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"github.com/mergermarket/go-pkcs7"
"io"
)
// Cipher key must be 32 chars long because block size is 16 bytes
const CIPHER_KEY = "abcdefghijklmnopqrstuvwxyz012345"
// Encrypt encrypts plain text string into cipher text string
func Encrypt(unencrypted string) (string, error) {
key := []byte(CIPHER_KEY)
plainText := []byte(unencrypted)
plainText, err := pkcs7.Pad(plainText, aes.BlockSize)
if err != nil {
return "", fmt.Errorf(`plainText: "%s" has error`, plainText)
}
if len(plainText)%aes.BlockSize != 0 {
err := fmt.Errorf(`plainText: "%s" has the wrong block size`, plainText)
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
cipherText := make([]byte, aes.BlockSize+len(plainText))
iv := cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return "", err
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(cipherText[aes.BlockSize:], plainText)
return fmt.Sprintf("%x", cipherText), nil
}
// Decrypt decrypts cipher text string into plain text string
func Decrypt(encrypted string) (string, error) {
key := []byte(CIPHER_KEY)
cipherText, _ := hex.DecodeString(encrypted)
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
if len(cipherText) < aes.BlockSize {
panic("cipherText too short")
}
iv := cipherText[:aes.BlockSize]
cipherText = cipherText[aes.BlockSize:]
if len(cipherText)%aes.BlockSize != 0 {
panic("cipherText is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(cipherText, cipherText)
cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)
return fmt.Sprintf("%s", cipherText), nil
}
// Golang v1.8
//
// TEST FILE
//
package blahblah
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestAES(t *testing.T) {
t.Run("Encrypts and decrypts", func(t *testing.T) {
plainTexts := []string{"1234567890", "123456789012345678901234567890123456789012345678901234567890", "1", ""}
for _, plainText := range plainTexts {
encrypted, err := Encrypt(plainText)
if err != nil {
t.Fatalf("Failed to encrypt: %s - %s", plainText, err.Error())
}
decrypted, err := Decrypt(encrypted)
if err != nil {
t.Fatalf("Failed to decrypt: %s - %s", plainText, err.Error())
}
assert.Equal(t, plainText, decrypted)
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment