-
-
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 so muchhhhh~
Thank you for putting this together!
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!
This is the best tutorial for the people who are from Node. Hope more people can see this!