JConnell
JConnell

Reputation: 33

Golang Decrypting strings that were encrypted with Node.js

I have a bunch passwords for an internal app that were encrypted with node.js and stored (irrelevantly) in mongodb. I would like to convert this application to Go, but I'm getting tripped up on the node.js encryption. I've looked through the node.js source code for this, and it's using the OpenSSL evpBytesToKey method. I've found a Golang implementation of this on the web, but I still can't decrypt the password in Go that was encrypted with node.js. "algo" is "aes256"

this.encrypt = function(s){
var cipher = crypto.createCipher(algo, key);

var i = 0;
var encrypted = "";
while (i < s.length){
    var end = Math.min(s.length-i, 15);
    var chunk = s.substring(i, end+i);
    encrypted += cipher.update(chunk, "utf8", "base64");
    i+= end;
}

encrypted += cipher.final("base64");
encrypted = encrypted.replace(/\//g,"_").replace(/\+/g, "-"); // base64 url encode
return encrypted;
}

And the Go code:

func evpBytesToKey(password string, keyLen int) (key []byte, iv []byte) {
const md5Len = 16

cnt := (keyLen-1)/md5Len + 1
m := make([]byte, cnt*md5Len)
key = make([]byte, keyLen)
iv = make([]byte, md5Len)


copy(m, md5sum([]byte(password)))

// Repeatedly call md5 until bytes generated is enough.
// Each call to md5 uses data: prev md5 sum + password.
d := make([]byte, md5Len+len(password))
start := 0
for i := 1; i < cnt; i++ {
    start += md5Len
    copy(d, m[start-md5Len:start])
    copy(d[md5Len:], password)
    copy(m[start:], md5sum(d))
}
return m[:keyLen], iv
}

And the decrypt function

func Decrypt(key string, b64 string) string {
text := decodeBase64(b64)   // base64.StdEncoding.DecodeString helper method
block, err := aes.NewCipher(evpBytesToKey(key,32))
if err != nil {
    panic(err)
}
if len(text) < aes.BlockSize {
    panic("ciphertext too short")
}
iv := text[:aes.BlockSize]
text = text[aes.BlockSize:]

fmt.Println(iv)
fmt.Println(text)

cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(text, text)
return string(text)
}

Here is some sample data:

8PTcrR0Nf0sltmdtvLUrFg== (you tell ME what it decrypts to :)

The key is var key = "random array of characters"; literally.

This is above my personal encryption experience and training. It is my last roadblock... Thanks for any help and guidance you can provide.

Upvotes: 3

Views: 2728

Answers (1)

In OpenSSL 'aes256' is equivalent to 'aes-256-cbc'. So your use of NewCFBDecrypter seems off. Other than that the IV/key generation needed to be tweaked a little to actually generate an IV.

This test script gives me an output that's at least ASCII.

http://play.golang.org/p/zsPMd8QN0b

I found the IV / key to look for by having OpenSSL generate it for me (made debugging genIvAndKey a little easier).

Note that you still need to determine where to split between the actual password and the padding. (unicode.IsPrint?)

Upvotes: 1

Related Questions