Node.js转Golang实现AES-256-CBC-HMAC-SHA1解密适配问题
适配Node.js AES-256-CBC-HMAC-SHA1解密逻辑到Golang
我来帮你把这段Node.js的解密逻辑完整适配到Golang里,先拆解一下Node.js代码的核心行为,再对应实现:
Node.js代码核心分析
你的Node.js代码做了这几件关键的事:
- 使用
aes-256-cbc-hmac-sha1算法(核心是AES-256-CBC解密,算法名包含HMAC-SHA1但你的代码里没显式做认证验证) - 关闭自动填充(
setAutoPadding(false)),意味着解密数据必须是AES块大小(16字节)的整数倍,且不需要移除PKCS7填充 - 从
binary编码的输入数据解密,输出UTF-8字符串
Golang完整实现代码
下面是完全对应上述逻辑的Golang代码,包含基础解密和可选的HMAC验证:
基础解密(对应你的Node.js代码核心)
package main import ( "crypto/aes" "crypto/cipher" "fmt" ) // decryptAES256CBC 对应Node.js的解密逻辑:AES-256-CBC + 无自动填充 + 字节转UTF-8 func decryptAES256CBC(derivedKey []byte, iv []byte, encryptedData []byte) (string, error) { // 验证AES-256密钥长度(必须32字节) if len(derivedKey) != 32 { return "", fmt.Errorf("invalid AES-256 key: expected 32 bytes, got %d", len(derivedKey)) } // 验证IV长度(必须等于AES块大小16字节) if len(iv) != aes.BlockSize { return "", fmt.Errorf("invalid IV: expected %d bytes, got %d", aes.BlockSize, len(iv)) } // 验证加密数据长度(无自动填充要求必须是块大小的整数倍) if len(encryptedData)%aes.BlockSize != 0 { return "", fmt.Errorf("encrypted data length must be multiple of %d bytes", aes.BlockSize) } // 创建AES cipher实例,对应Node.js的createDecipheriv初始化 block, err := aes.NewCipher(derivedKey) if err != nil { return "", fmt.Errorf("failed to create AES cipher: %w", err) } // 创建CBC解密器,对应Node.js的CBC模式 mode := cipher.NewCBCDecrypter(block, iv) // 执行解密(无自动填充,直接解密所有数据) decryptedBytes := make([]byte, len(encryptedData)) mode.CryptBlocks(decryptedBytes, encryptedData) // 转成UTF-8字符串,对应Node.js的utf8输出格式 return string(decryptedBytes), nil } func main() { // 替换成你的实际数据 derivedKey := []byte("your-32-byte-derived-key-example") iv := []byte("your-16-byte-iv-example") // encryptedData对应Node.js里的new_buf(binary编码即原始字节) encryptedData := []byte("your-encrypted-binary-data-here") result, err := decryptAES256CBC(derivedKey, iv, encryptedData) if err != nil { fmt.Printf("Decryption failed: %v\n", err) return } fmt.Printf("Decrypted result: %s\n", result) }
可选:HMAC-SHA1验证(对应算法名里的HMAC部分)
如果你的Node.js代码实际需要验证HMAC(算法名包含hmac-sha1),说明derived密钥可能是AES密钥+HMAC密钥的组合(比如前32字节是AES密钥,后20字节是HMAC密钥),可以补充以下验证逻辑:
import ( "crypto/hmac" "crypto/sha1" ) // decryptAndVerify 解密+验证HMAC-SHA1 func decryptAndVerify(derivedKey []byte, iv []byte, encryptedData []byte, hmacValue []byte) (string, error) { // 验证组合密钥长度(32字节AES + 20字节HMAC-SHA1密钥) if len(derivedKey) != 32+20 { return "", fmt.Errorf("invalid derived key: expected 52 bytes, got %d", len(derivedKey)) } aesKey := derivedKey[:32] hmacKey := derivedKey[32:] // 先执行解密 decryptedStr, err := decryptAES256CBC(aesKey, iv, encryptedData) if err != nil { return "", err } // 验证HMAC-SHA1 mac := hmac.New(sha1.New, hmacKey) mac.Write([]byte(decryptedStr)) expectedHMAC := mac.Sum(nil) if !hmac.Equal(expectedHMAC, hmacValue) { return "", fmt.Errorf("HMAC verification failed") } return decryptedStr, nil }
关键对应点说明
- 无自动填充:Golang里不需要额外处理填充,直接用
CryptBlocks解密即可,和Node.js的setAutoPadding(false)行为完全一致 - 编码转换:Node.js里的
binary输入对应Golang的[]byte,解密后的字节直接转字符串就是UTF-8格式,和Node.js的输出一致 - 密钥/IV长度:严格遵循AES-256和CBC模式的要求,避免出现解密失败的情况
内容的提问来源于stack exchange,提问作者Darksorrow
相关产品推荐
相关产品推荐

