将go语言的AES加密函数移植到Node.js。

huangapple go评论92阅读模式
英文:

Port go AES Encrypt function to node.js

问题

我正在尝试将一个可以通过"SmartView" API控制三星电视的Go程序(https://github.com/McKael/samtv)移植到node.js。

在程序中有一个"AES加密"函数,我在移植到node.js时遇到了问题。

func (s *SmartViewSession) aesEncrypt(plaindata []byte) ([]byte, error) {
	//logrus.Debugf("aesEncrypt(%#v) : '%s'", plaindata, string(plaindata))
	//logrus.Debugf("session ID:  %d", s.sessionID)
	//logrus.Debugf("session key: '%x'\n  %v", string(s.sessionKey), s.sessionKey)

	// 创建密码块
	block, err := aes.NewCipher(s.sessionKey)
	if err != nil {
		return nil, err
	}

	bs := block.BlockSize()
	//logrus.Debugf("block size: %d", bs)

	// 添加填充
	padding := bs - len(plaindata)%bs
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	//logrus.Debugf("padding: %d byte(s)", padding)
	plaindata = append(plaindata, padtext...)

	// 加密
	ciphertext := make([]byte, len(plaindata))
	for cipherrange := ciphertext; len(plaindata) > 0; {
		block.Encrypt(cipherrange, plaindata[:bs])
		plaindata = plaindata[bs:]
		cipherrange = cipherrange[bs:]
	}

	//logrus.Debugf("ciphertext: %#v", ciphertext)
	return ciphertext, nil
}

我现在面临的问题是,我不知道使用了什么算法,或者在我的node.js函数中需要指定的"初始向量"来自哪里:

const SESSION_KEY = "59e8ca4b09f2a19ab5421cf55d604c7c";

var aesEncrypt = ((val, algo = "aes-256-cbc") => {
    let cipher = crypto.createCipheriv(algo, SESSION_KEY, IV);
    let encrypted = cipher.update(val, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
});

我应该使用crypto.createCipher(...)吗?但它已经被弃用,而且我也感觉填充部分很重要。

我对加密一无所知。任何提示都受欢迎。

注意:在go函数中,s.sessionKey的值与node.js中的SESSION_KEY = "59e8ca4b09f2a19ab5421cf55d604c7c"相同。

英文:

Im trying to port a go program (https://github.com/McKael/samtv) that can control samsung TVs via the "SmartView" API to node.js

In the program is a "AES Encrypt" function that i have trouble with porting to node.

func (s *SmartViewSession) aesEncrypt(plaindata []byte) ([]byte, error) {
	//logrus.Debugf("aesEncrypt(%#v) : '%s'", plaindata, string(plaindata))
	//logrus.Debugf("session ID:  %d", s.sessionID)
	//logrus.Debugf("session key: '%x'\n  %v", string(s.sessionKey), s.sessionKey)

	// Create cipher block
	block, err := aes.NewCipher(s.sessionKey)
	if err != nil {
		return nil, err
	}

	bs := block.BlockSize()
	//logrus.Debugf("block size: %d", bs)

	// Add padding
	padding := bs - len(plaindata)%bs
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	//logrus.Debugf("padding: %d byte(s)", padding)
	plaindata = append(plaindata, padtext...)

	// Encrypt
	ciphertext := make([]byte, len(plaindata))
	for cipherrange := ciphertext; len(plaindata) > 0; {
		block.Encrypt(cipherrange, plaindata[:bs])
		plaindata = plaindata[bs:]
		cipherrange = cipherrange[bs:]
	}

	//logrus.Debugf("ciphertext: %#v", ciphertext)
	return ciphertext, nil
}

The problem im facing right now is, i dont know what algorythim is used, or where the "initial vector" is coming from i need to specify in my node.js function:

const SESSION_KEY = "59e8ca4b09f2a19ab5421cf55d604c7c";

var aesEncrypt = ((val, algo = "aes-256-cbc") => {
    let cipher = crypto.createCipheriv(algo, SESSION_KEY, IV);
    let encrypted = cipher.update(val, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
});

Sould i use crypto.createCipher(...) instead? But its deprecated and have also the feeling that the padding stuff is important.

I have absolutely no clue about encryption.
Any hint is welcome.

NOTE: In the go function, s.sessionKey is the same value as in node.js the SESSION_KEY = "59e8ca4b09f2a19ab5421cf55d604c7c"

答案1

得分: 2

Go代码使用AES-ECB模式和PKCS#7填充。AES变种是根据密钥大小隐式确定的,例如,对于16字节的密钥,使用AES-128。密文以[]byte形式返回。

在NodeJS代码中,AES变种是显式指定的,同时指定了模式,例如aes-128-ecb。ECB模式不使用IV,因此在createCipheriv()中必须将其指定为null。默认使用PKCS#7填充。密文可以作为Buffer返回,它与[]byte最接近。

发布的密钥59e8ca4b09f2a19ab5421cf55d604c7c看起来像是一个十六进制编码的密钥,解码后为16字节,因此对应AES-128。在Go中,可以使用encoding/hex包进行十六进制解码,例如hex.DecodeString("59e8ca4b09f2a19ab5421cf55d604c7c")

以下是一个使用AES-128(16字节密钥)、ECB模式和PKCS#7填充的NodeJS代码示例:

var crypto = require('crypto');

const SESSION_KEY = Buffer.from("59e8ca4b09f2a19ab5421cf55d604c7c", "hex");

var aesEncrypt = ((val, algo = "aes-128-ecb") => {
    let cipher = crypto.createCipheriv(algo, SESSION_KEY, null);
    return Buffer.concat([cipher.update(val, 'utf8'), cipher.final()]);
});

var ciphertext = aesEncrypt("The quick brown fox jumps over the lazy dog");
console.log(ciphertext.toString('base64')); // T/uQforseVFkY93mqwpwCGVVnEFDTT5Gle8a8XUxCfOXCfYUo3uCJ/nwzCIJ9xqf

使用相同的密钥(解码后的十六进制形式)和明文,Go代码将得到相同的结果,并对密文进行Base64编码。

为了完整起见:密钥也可以是UTF-8编码的,这样将得到一个32字节的密钥,在Go代码中可以使用key := []byte("59e8ca4b09f2a19ab5421cf55d604c7c"),在NodeJS代码中可以使用const SESSION_KEY = Buffer.from("59e8ca4b09f2a19ab5421cf55d604c7c", "utf-8")。在NodeJS代码中,还必须应用aes-256-ecb。最终,密钥规范必须提供有关使用哪种编码的信息。

请注意,ECB模式是不安全的。现在通常使用认证加密,例如GCM模式。

英文:

The Go code applies AES in ECB mode with PKCS#7 padding. The AES variant is implicitly derived from the keysize, e.g. AES-128 for a 16 bytes key. The ciphertext is returned as []byte.

In the NodeJS code, the AES variant is explicitly specified, along with the mode, e.g. aes-128-ecb. The ECB mode does not apply an IV, so it must be specified as null in createCipheriv(). As padding PKCS#7 (default) is used. The ciphertext can be returned as Buffer, which is closest to []byte.

The posted key 59e8ca4b09f2a19ab5421cf55d604c7c looks like a hex encoded key, which is hex decoded 16 bytes large and thus corresponds to AES-128. The hex decoding can be achieved in Go with the encoding/hex package, e.g. with hex.DecodeString("59e8ca4b09f2a19ab5421cf55d604c7c").

Example for a NodeJS code that uses AES-128 (16 bytes key) in ECB mode and PKCS#7 padding:

var crypto = require('crypto');

const SESSION_KEY = Buffer.from("59e8ca4b09f2a19ab5421cf55d604c7c", "hex");

var aesEncrypt = ((val, algo = "aes-128-ecb") => {
    let cipher = crypto.createCipheriv(algo, SESSION_KEY, null);
    return Buffer.concat([cipher.update(val, 'utf8'), cipher.final()]);
});

var ciphertext = aesEncrypt("The quick brown fox jumps over the lazy dog");
console.log(ciphertext.toString('base64')); // T/uQforseVFkY93mqwpwCGVVnEFDTT5Gle8a8XUxCfOXCfYUo3uCJ/nwzCIJ9xqf

The Go code gives the same result using the same key (hex decoded) and plaintext and with Base64 encoding of the ciphertext.

For completeness: The key could also be UTF-8 encoded and would then result in a 32 bytes key, e.g. with key := []byte("59e8ca4b09f2a19ab5421cf55d604c7c") in the Go code and const SESSION_KEY = Buffer.from("59e8ca4b09f2a19ab5421cf55d604c7c", "utf-8") in the NodeJS code. In the NodeJS code, additionally aes-256-ecb must be applied. Ultimately, the key specification must provide information about which encoding to use.


Note that the ECB mode is insecure. Nowadays, authenticated encryption is usually used, e.g. via GCM mode.

huangapple
  • 本文由 发表于 2022年12月22日 20:57:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/74888856.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定