在Golang中使用AES-128 ECB对字符串进行编码,然后在JavaScript中进行解密。

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

encode string aes-128 ecb in golang and decrypt in js

问题

我正在尝试在Golang服务器上对字符串进行加密,我有一个AES-128加密工具。

func EncryptAES(key []byte, plaintext string) (string, error) {
	// 创建密码器
	c, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	// 为加密后的数据分配空间
	out := make([]byte, len(plaintext))

	for i := 1; i <= len(plaintext)/16; i++ {
		tempBuf := make([]byte, 16)

		offset := (i - 1) * 16
		limit := offset + 16
		// 加密
		c.Encrypt(tempBuf, []byte(plaintext[offset:limit]))

		for j := 0; j < len(tempBuf); j++ {
			out[offset+j] = tempBuf[j]
		}
	}
	// 返回十六进制字符串
	return hex.EncodeToString(out), nil
}

然后,我尝试做类似以下的操作:

hasher := sha256.New()
hasher.Write([]byte(word))
sha := hasher.Sum(nil)

cypherText := word + userSessionKey

for len([]byte(cypherText))%16 != 0 {
	cypherText += "0"
}

sha128 := sha[:len(sha)/2]

captchaKey, err := utils.EncryptAES([]byte(hex.EncodeToString(sha128)), cypherText)
if err != nil {
	SendErrorResponse(ctx, fasthttp.StatusInternalServerError, []byte("error generating aes session key "+err.Error()))
	return
}

但是对于这个密钥和密文,我在加密/解密AES网站上遇到了这个错误。

这个JavaScript函数解码也不起作用:

async function decryptAES128(key, cipherText){
    let hash = CryptoJS.SHA256(key).toString();
    hash = hash.substring(0, hash.length/2);

    console.log(hash);
    console.log(cipherText)

    const bytes = await CryptoJS.AES.decrypt(CryptoJS.enc.Hex.parse(cipherText), CryptoJS.enc.Hex.parse(hash), { mode: CryptoJS.mode.ECB });

    return CryptoJS.enc.Utf8.stringify(bytes.words)
}

什么都没有打印出来。

英文:

I am trying to encrypt string on golang server, i have a aes-128 encrypt util

func EncryptAES(key []byte, plaintext string) (string, error) {
	// create cipher
	c, err := aes.NewCipher(key)
	if err != nil {
		return &quot;&quot;, err
	}

	// allocate space for ciphered data
	out := make([]byte, len(plaintext))

	for i := 1; i &lt;= len(plaintext)/16; i++ {
		tempBuf := make([]byte, 16)

		offset := (i - 1) * 16
		limit := offset + 16
		// encrypt
		c.Encrypt(tempBuf, []byte(plaintext[offset:limit]))

		for j := 0; j &lt; len(tempBuf); j++ {
			out[offset+j] = tempBuf[j]
		}
	}
	// return hex string
	return hex.EncodeToString(out), nil
}

and after that i am trying to do something like that

	hasher := sha256.New()
	hasher.Write([]byte(word))
	sha := hasher.Sum(nil)

	cypherText := word + userSessionKey

	for len([]byte(cypherText))%16 != 0 {
		cypherText += &quot;0&quot;
	}

	sha128 := sha[:len(sha)/2]

	captchaKey, err := utils.EncryptAES([]byte(hex.EncodeToString(sha128)), cypherText)
	if err != nil {
		SendErrorResponse(ctx, fasthttp.StatusInternalServerError, []byte(&quot;error generating aes session key &quot;+err.Error()))
		return
	}

but for this key and ciphertext i am getting this error on encryption/decryption aes site
在Golang中使用AES-128 ECB对字符串进行编码,然后在JavaScript中进行解密。

js func for decoding not working too

async function decryptAES128(key, cipherText){
    let hash = CryptoJS.SHA256(key).toString();
    hash = hash.substring(0, hash.length/2);

    console.log(hash);
    console.log(cipherText)

    const bytes = await CryptoJS.AES.decrypt(CryptoJS.enc.Hex.parse(cipherText), CryptoJS.enc.Hex.parse(hash), { mode: CryptoJS.mode.ECB });

    return CryptoJS.enc.Utf8.stringify(bytes.words)
}

just prints nothing

答案1

得分: 1

Go代码在明文(cypherText,顺便说一句,这个术语有误导性)的大小不是块大小(AES的16字节)的整数倍时,使用0x30值进行填充。作为密钥,使用密码(word)的SHA256值的前16个字节的十六进制编码的UTF-8编码。密文是十六进制编码的。

使用在线工具进行解密失败,因为在线工具使用PKCS#7填充,并且对密文进行了Base64解码。为了能够进行解密,必须禁用默认的PKCS#7填充,并对密文进行十六进制解码,例如参见CyberChef

使用JavaScript代码进行解密失败,因为CryptoJS默认使用PKCS#7填充,密钥进行了十六进制解码,并且密文没有作为CipherParams对象传递。为了能够进行解密,必须禁用默认的PKCS#7填充,将密钥进行UTF-8编码,并将密文作为CipherParams对象传递:

var password = 'день';
var key = CryptoJS.SHA256(password).toString();
key = key.substring(0, key.length/2);

var ciphertext = '46ef70c1193fa29024595964a0eb0157c4e6602da6c1429f8a2b81146f79e798';
var decrypted = CryptoJS.AES.decrypt(
    {ciphertext: CryptoJS.enc.Hex.parse(ciphertext)}, // 修复1:传递CipherParams对象
    CryptoJS.enc.Utf8.parse(key), // 修复2:对密钥进行UTF-8编码
    { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); // 修复3:禁用填充
console.log(decrypted.toString(CryptoJS.enc.Utf8));

解密后,UTF-8解码的数据为:деньBvFGlrXeWCnPTwFC00000000


安全性:ECB不使用初始化向量(IV),因此不安全。现在通常使用认证加密(例如GCM),但至少要使用带有IV的模式(例如CBC)。
此外,使用摘要作为密钥派生函数(KDF)是不安全的。有专门的函数可用于此(例如Argon2或PBKDF2)。此外,应直接使用KDF的字节字符串,而不是其UTF-8编码的十六进制编码,以提高安全性。
通常不可靠的填充方式是0x30填充。更可靠的方式是使用PKCS#7填充。

英文:

The Go code pads with 0x30 values if the size of the plaintext (cypherText, a misleading term by the way) is not an integer multiple of the blocksize (16 bytes for AES). As key the UTF-8 encoding of the hex encoding of the first 16 bytes of the SHA256 value of the password (word) is used. The ciphertext is hex encoded.

Decryption with the online tool fails because the online tool uses PKCS#7 padding and the ciphertext is Base64 decoded. For decryption to be possible, the default PKCS#7 padding must be disabled and the ciphertext must be hex decoded, see e.g. CyberChef.

Decryption with the JavaScript code fails because CryptoJS uses PKCS#7 padding by default, the key is hex decoded, and the ciphertext is not passed as CipherParams object. For decryption to be possible, the default PKCS#7 padding must be disabled, the key must be UTF-8 encoded, and the ciphertext must be passed as a CipherParams object:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

var password = &#39;день&#39;;
var key = CryptoJS.SHA256(password).toString();
key = key.substring(0, key.length/2);

var ciphertext = &#39;46ef70c1193fa29024595964a0eb0157c4e6602da6c1429f8a2b81146f79e798&#39;
var decrypted = CryptoJS.AES.decrypt(
    {ciphertext: CryptoJS.enc.Hex.parse(ciphertext)}, // Fix 1: pass a CipherParams object
    CryptoJS.enc.Utf8.parse(key), // Fix2: UTF-8 encode the key
    { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); // Fix 3: disable padding
console.log(decrypted.toString(CryptoJS.enc.Utf8));

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

gives as decrypted, UTF-8 decoded data: деньBvFGlrXeWCnPTwFC00000000.


Security: ECB does not use an IV and is therefore insecure. Nowadays, authenticated encryption is applied (e.g. GCM), but at least a mode with an IV (e.g. CBC).<br>
Furthermore, it is insecure to use a digest as key derivation function (KDF). There are dedicated functions for this (e.g. Argon2 or PBKDF2). Also, the byte string of the KDF should be used directly and not the UTF-8 encoding of the hex encoding, which reduces security.<br>
The 0x30 padding applied is generally unreliable. More reliable is e.g. PKCS#7 padding.

huangapple
  • 本文由 发表于 2022年6月24日 13:39:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/72739443.html
匿名

发表评论

匿名网友

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

确定