-
-
Save brettscott/2ac58ab7cb1c66e2b4a32d6c1c3908a7 to your computer and use it in GitHub Desktop.
// 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) | |
} | |
}) | |
} |
Thank you
Thanks really helpful.
Used base64 encode/decode on top of it.
This works, thanks a lot!!
I get an error:
cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)
runtime error: makeslice: len out of range /Users/franky/sdk/go1.14.3/src/runtime/slice.go:27 (0x1052f08) panicmakeslicelen: panic(errorString("makeslice: len out of range")) /Users/franky/sdk/go1.14.3/src/runtime/slice.go:44 (0x1052fbc) makeslice: panicmakeslicelen() /Users/franky/go/src/github.com/mergermarket/go-pkcs7/pkcs7.go:22 (0x1c4fc39) Unpad: buf := make([]byte, bufLen) /Users/franky/Workspace/continu/gopen-api/main.go:169 (0x1c99cae) Decrypt: cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)
I get an error:
cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)
runtime error: makeslice: len out of range /Users/franky/sdk/go1.14.3/src/runtime/slice.go:27 (0x1052f08) panicmakeslicelen: panic(errorString("makeslice: len out of range")) /Users/franky/sdk/go1.14.3/src/runtime/slice.go:44 (0x1052fbc) makeslice: panicmakeslicelen() /Users/franky/go/src/github.com/mergermarket/go-pkcs7/pkcs7.go:22 (0x1c4fc39) Unpad: buf := make([]byte, bufLen) /Users/franky/Workspace/continu/gopen-api/main.go:169 (0x1c99cae) Decrypt: cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)
run your command this code
go get pault.ag/go/pkcs7
Thank you for sharing code...
When I try to build an App on Cloud66 the docker image fails to build with that Library:
` #12 [8/14] RUN go get github.com/paultag/go-pkcs7
#12 1.071 unrecognized import path "pault.ag/go/pkcs7/utils": reading https://pault.ag/go/pkcs7/utils?go-get=1: 404 Not Found
#12 ERROR: executor failed running [/bin/sh -c go get github.com/paultag/go-pkcs7]: runc did not terminate sucessfully
[8/14] RUN go get github.com/paultag/go-pkcs7:
failed to solve with frontend dockerfile.v0: failed to build LLB: executor failed running [/bin/sh -c go get github.com/paultag/go-pkcs7]: runc did not terminate sucessfully `
I would say this solution is not complete. In node, you can have the password in any length and it's converted to a passphrase automatically. In this example, you are using a password with exactly 32 chars, which is hardly the case always.
@buzzy take it as it is, expand on it and share!
I want to remind you it’s not productive to simply complain about free OSS software being incomplete or not meeting your own needs.
A better approach would have been to provide what’s missing in these comments for others to benefit from, or link to your own gist/package.
As for being “incomplete”, the above gist is complete for my needs when created years ago, and has hopefully saved others (perhaps even yourself) hours of time.
Also, take a closer look at cipher keys.
@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
good
Thank you!
Thank you for putting this together!