Golang 解密使用 Node.js 加密的字符串
Golang Decrypting strings that were encrypted with Node.js
我有一堆内部应用程序的密码,这些密码使用 node.js 加密并(无关地)存储在 mongodb 中。我想将此应用程序转换为 Go,但我被 node.js 加密绊倒了。为此,我查看了 node.js 源代码,它使用的是 OpenSSL evpBytesToKey 方法。我在网上找到了这个的 Golang 实现,但我仍然无法解密用 node.js 加密的 Go 中的密码。 "algo" 是 "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;
}
Go 代码:
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
}
以及解密函数
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)
}
这是一些示例数据:
8PTcrR0Nf0sltmdtvLUrFg==
(你告诉我解密后的内容:)
关键是 var key = "random array of characters";
字面意思。
以上是我个人的加密经验和培训。这是我最后的障碍...感谢您提供的任何帮助和指导。
在 OpenSSL 中 'aes256' 等同于 'aes-256-cbc'。因此,您对 NewCFBDecrypter
的使用似乎已关闭。除此之外,IV/key 生成需要稍微调整才能实际生成 IV。
这个测试脚本给我的输出至少是 ASCII 码。
http://play.golang.org/p/zsPMd8QN0b
通过让 OpenSSL 为我生成它,我找到了要查找的 IV / 密钥(使调试 genIvAndKey
更容易一些)。
请注意,您仍然需要确定实际密码和填充之间的分隔位置。 (unicode.IsPrint
?)
我有一堆内部应用程序的密码,这些密码使用 node.js 加密并(无关地)存储在 mongodb 中。我想将此应用程序转换为 Go,但我被 node.js 加密绊倒了。为此,我查看了 node.js 源代码,它使用的是 OpenSSL evpBytesToKey 方法。我在网上找到了这个的 Golang 实现,但我仍然无法解密用 node.js 加密的 Go 中的密码。 "algo" 是 "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;
}
Go 代码:
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
}
以及解密函数
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)
}
这是一些示例数据:
8PTcrR0Nf0sltmdtvLUrFg==
(你告诉我解密后的内容:)
关键是 var key = "random array of characters";
字面意思。
以上是我个人的加密经验和培训。这是我最后的障碍...感谢您提供的任何帮助和指导。
在 OpenSSL 中 'aes256' 等同于 'aes-256-cbc'。因此,您对 NewCFBDecrypter
的使用似乎已关闭。除此之外,IV/key 生成需要稍微调整才能实际生成 IV。
这个测试脚本给我的输出至少是 ASCII 码。
http://play.golang.org/p/zsPMd8QN0b
通过让 OpenSSL 为我生成它,我找到了要查找的 IV / 密钥(使调试 genIvAndKey
更容易一些)。
请注意,您仍然需要确定实际密码和填充之间的分隔位置。 (unicode.IsPrint
?)