You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go中实现CryptoJS.AES.decrypt解密功能

问题:用Go实现CryptoJS AES解密失败

我有一段可用的CryptoJS AES解密代码,能通过指定密钥解密密文:

var CryptoJS = require('crypto-js');

let encrypted = 'U2FsdGVkX19dGrnVQb3BYZ9SWtQBCt2XZDeWFBEfWoi3qnSHg26aQnADUKjTDtSgpPUDzXc59XrIBsTZp9IRg4dYy9Lo0/GjSVn8qlINhE8NJXozQvUNPJSs6nvWSiivCsh9KHGsWFEusMeTefM9V2hKRpQHnFp5VHDLPgGImjHXOQO71eO4qFoQ3ESqUdnDO94nlTjcJU8AP+GabRMjHP08OVz87uyV4SfvT7AZhAYuOPOumHbJaV5nHz2ouqBZgXR3OK07AUk6V+Faz43BT3Qd2+xGLyz8C+teekmudVhmGlnzvMK/VUs0bNDUttdVVnkz/VbXVOj++07uhDsJoMKzZQYTNLkIl9HnuXDmhKOrLSYs2EYpNrH9T/2ZP3nwqJaI7bbLBCfCpNFGNLY4jyNou4Bl5GEK6sxg0zraUCZTgvfuuvBpKWFcFhPvYf8eJGoI3dOWTRWyRnS6e4j3bg==';
let key = 'KBlgcIOrad7EYpiz9LNNTMSg98QoqSVK';

var decrypted = CryptoJS.AES.decrypt(encrypted, key);

let data = decrypted.toString(CryptoJS.enc.Utf8);

console.log(data);

我尝试用Go实现相同逻辑但得到乱码,我的Go代码如下:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "fmt"
)

func main() {
    encrypted := "U2FsdGVkX19dGrnVQb3BYZ9SWtQBCt2XZDeWFBEfWoi3qnSHg26aQnADUKjTDtSgpPUDzXc59XrIBsTZp9IRg4dYy9Lo0/GjSVn8qlINhE8NJXozQvUNPJSs6nvWSiivCsh9KHGsWFEusMeTefM9V2hKRpQHnFp5VHDLPgGImjHXOQO71eO4qFoQ3ESqUdnDO94nlTjcJU8AP+GabRMjHP08OVz87uyV4SfvT7AZhAYuOPOumHbJaV5nHz2ouqBZgXR3OK07AUk6V+Faz43BT3Qd2+xGLyz8C+teekmudVhmGlnzvMK/VUs0bNDUttdVVnkz/VbXVOj++07uhDsJoMKzZQYTNLkIl9HnuXDmhKOrLSYs2EYpNrH9T/2ZP3nwqJaI7bbLBCfCpNFGNLY4jyNou4Bl5GEK6sxg0zraUCZTgvfuuvBpKWFcFhPvYf8eJGoI3dOWTRWyRnS6e4j3bg=="
    key := "KBlgcIOrad7EYpiz9LNNTMSg98QoqSVK"

    e, _ := base64.StdEncoding.DecodeString(encrypted)
    k := []byte(key)

    dst, err := decryptAES(e, k)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(dst))
}

func decryptAES(ciphertext []byte, key []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }

    if len(ciphertext) < aes.BlockSize {
        return nil, fmt.Errorf("ciphertext is too short")
    }

    iv := ciphertext[:aes.BlockSize]
    ciphertext = ciphertext[aes.BlockSize:]

    stream := cipher.NewCFBDecrypter(block, iv)
    plaintext := make([]byte, len(ciphertext))
    stream.XORKeyStream(plaintext, ciphertext)

    return plaintext, nil
}

运行后得到乱码结果:

�9�������ff��ܱ�������jTY:���SV�PZ_LDw%�z��0���&amp;���j@'��_H��0+����b�8�b}�;Yڸ�d���0�^P얿L�aC�3�2�_m��d׺�h�
-׸��%Z(0��c�v�r�:�=�>}���b��n������g�lu}�������&amp;�3�.�%|M���fxdGW27z�D��J���"(�[D�+<��n�z�4:�����
��iZs�ix��G�$��.= �3J��5{"g��#z ���Z�#���@���Xs��#�ZR;���VI������ ��w�X/�bp�r
��

解决方案

你的Go代码无法解密的核心原因是CryptoJS的默认行为和你手动实现的AES逻辑不匹配:

  1. CryptoJS处理的密文是OpenSSL格式(开头为Salted__),它不会直接用你传入的key作为AES密钥,而是通过EVP_BytesToKey算法(基于MD5哈希,迭代1次),结合密文中的盐值生成真正的AES密钥和IV。
  2. CryptoJS默认使用AES-CBC模式+PKCS7填充,而你的Go代码用了CFB模式,这也是导致乱码的原因之一。

修复后的Go代码如下:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"strings"
)

// EVP_BytesToKey 实现OpenSSL的EVP_BytesToKey算法,生成AES密钥和IV
func evpBytesToKey(password, salt []byte, keyLen, ivLen int) ([]byte, []byte) {
	var key, iv []byte
	var digest []byte
	for len(key) < keyLen || len(iv) < ivLen {
		hash := md5.New()
		if len(digest) > 0 {
			hash.Write(digest)
		}
		hash.Write(password)
		hash.Write(salt)
		digest = hash.Sum(nil)
		key = append(key, digest[:]...)
		if len(key) > keyLen {
			key = key[:keyLen]
		}
		if len(iv) < ivLen {
			remaining := ivLen - len(iv)
			if len(digest) > remaining {
				iv = append(iv, digest[:remaining]...)
			} else {
				iv = append(iv, digest[:]...)
			}
		}
	}
	return key, iv
}

// pkcs7Unpadding 去除PKCS7填充
func pkcs7Unpadding(data []byte) []byte {
	if len(data) == 0 {
		return data
	}
	padding := data[len(data)-1]
	return data[:len(data)-int(padding)]
}

func decryptAES(ciphertext []byte, password []byte) ([]byte, error) {
	// 解析OpenSSL格式密文:Salted__ + 8字节盐 + 密文
	if !strings.HasPrefix(string(ciphertext), "Salted__") {
		return nil, fmt.Errorf("invalid OpenSSL format ciphertext")
	}
	salt := ciphertext[8:16]
	actualCiphertext := ciphertext[16:]

	// 生成AES-256密钥和IV(CryptoJS默认AES-256)
	key, iv := evpBytesToKey(password, salt, 32, aes.BlockSize)

	// 创建AES块
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// CBC模式解密
	mode := cipher.NewCBCDecrypter(block, iv)
	plaintext := make([]byte, len(actualCiphertext))
	mode.CryptBlocks(plaintext, actualCiphertext)

	// 去除PKCS7填充
	plaintext = pkcs7Unpadding(plaintext)

	return plaintext, nil
}

func main() {
	encrypted := "U2FsdGVkX19dGrnVQb3BYZ9SWtQBCt2XZDeWFBEfWoi3qnSHg26aQnADUKjTDtSgpPUDzXc59XrIBsTZp9IRg4dYy9Lo0/GjSVn8qlINhE8NJXozQvUNPJSs6nvWSiivCsh9KHGsWFEusMeTefM9V2hKRpQHnFp5VHDLPgGImjHXOQO71eO4qFoQ3ESqUdnDO94nlTjcJU8AP+GabRMjHP08OVz87uyV4SfvT7AZhAYuOPOumHbJaV5nHz2ouqBZgXR3OK07AUk6V+Faz43BT3Qd2+xGLyz8C+teekmudVhmGlnzvMK/VUs0bNDUttdVVnkz/VbXVOj++07uhDsJoMKzZQYTNLkIl9HnuXDmhKOrLSYs2EYpNrH9T/2ZP3nwqJaI7bbLBCfCpNFGNLY4jyNou4Bl5GEK6sxg0zraUCZTgvfuuvBpKWFcFhPvYf8eJGoI3dOWTRWyRnS6e4j3bg=="
	key := "KBlgcIOrad7EYpiz9LNNTMSg98QoqSVK"

	e, err := base64.StdEncoding.DecodeString(encrypted)
	if err != nil {
		panic(err)
	}
	k := []byte(key)

	dst, err := decryptAES(e, k)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(dst))
}

这段代码做了以下关键调整:

  • 实现了evpBytesToKey函数,和CryptoJS的密钥生成逻辑对齐
  • 解析OpenSSL格式的密文,提取盐值
  • 使用AES-CBC模式解密,之后去除PKCS7填充
  • 处理了所有可能的错误(比如密文格式校验)

运行这段代码就能得到和CryptoJS一致的解密结果。

内容的提问来源于stack exchange,提问作者PhiHungTF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 07:30:55