Last active
August 23, 2024 15:31
-
-
Save brettscott/2ac58ab7cb1c66e2b4a32d6c1c3908a7 to your computer and use it in GitHub Desktop.
AES 256 CBC encryption between Golang and Node JS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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) | |
} | |
}) | |
} |
good
Thank you!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@brettscott Well, another library has existed since 4 years that already does all this automatically, so I don't really have to re-invent the wheel. https://github.com/Luzifer/go-openssl