用Crypto.js和pycrypto加密生成不同的加密密文

标签 encryption cryptography aes cryptojs pycrypto

我正在尝试使用 Crypto.js 使用其 AES 算法在 Node 中生成加密文本。它在 Js 中可以用于加密和解密。同样,我尝试使用 pycrypto 在 Python 中实现相同的功能,它在 python 中进行加密和解密。但是当我想使用JS中的加密密文在Python中解密时,问题就出现了。问题是JS生成的密文和Python生成的密文不一样。

这是基于 JS 的 AES 用法:

import CryptoJS from "crypto-js";

let str = "lol";
let salt = "ABCDEFGHIJKLMNOP";
let key = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP";

salt = CryptoJS.enc.Hex.parse(salt);
key = CryptoJS.enc.Hex.parse(key);

const options = {
  iv: salt,
  padding: CryptoJS.pad.ZeroPadding,
  mode: CryptoJS.mode.CFB,
};

// function to encrypt the string
function encrypt(str, salt, key) {
  const cipher = CryptoJS.AES.encrypt(str, key, options);
  console.log("cipher", CryptoJS.enc.Hex.stringify(cipher.ciphertext));
  return cipher.ciphertext.toString(CryptoJS.enc.Base64);
}

// function to decrypt the string
function decrypt(str, salt, key) {
  const cipher = CryptoJS.AES.decrypt(str, key, options);
  return cipher.toString(CryptoJS.enc.Utf8);
}

const encrypted = encrypt(str, salt, key);
console.log("encrypted", encrypted);


const decrypted = decrypt(encrypted, salt, key);
console.log("decrypted", decrypted);

// OUTPUT
// encrypted sd4Xpz/ws8x2j+cgF17t6A==
// decrypted lol

这是基于 Python 的 AES 用法:

from Crypto.Cipher import AES
from base64 import b64encode, b64decode

str = "lol";
salt = b"ABCDEFGHIJKLMNOP";
key = "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP";
enc_dec_method = 'utf-8'


def encrypt(str_to_enc, str_key, salt):
    aes_obj = AES.new(str_key.encode('utf-8'), AES.MODE_CFB, salt)
    hx_enc = aes_obj.encrypt(str_to_enc.encode('utf8'))
    df = b64encode(hx_enc)
    mret = b64encode(hx_enc).decode(enc_dec_method)
    return mret

def decrypt(str_to_dec, str_key, salt):
    aes_obj = AES.new(str_key.encode('utf-8'), AES.MODE_CFB, salt)
    str_tmp = b64decode(str_to_dec.encode(enc_dec_method))
    str_dec = aes_obj.decrypt(str_tmp)
    mret = str_dec.decode(enc_dec_method)
    return mret

test_enc_text = encrypt(str, key, salt)
test_dec_text = decrypt(test_enc_text, key, salt)

print(f"Encrypted Text: {test_enc_text}")
print(f"Decrypted Text: {test_dec_text}")

# OUTPUT
# Encrypted Text: o9XB
# Decrypted Text: lol
  • 我厌倦了用这两种语言进行加密和解密,并检查了这两个库的文档和源代码。
  • 也尝试检查我是否缺少编码或解码,但没有成功。

我在这里遗漏了哪些关键概念可以帮助弥合此处的兼容性差距?

最佳答案

这些代码不兼容,因为:

  • Key 和 IV 不是十六进制编码,因此十六进制编码器不得在 CryptoJS 代码中使用。如果要像Python代码一样应用Utf-8编码,则必须使用Utf-8编码器。

    salt = CryptoJS.enc.Utf8.parse(salt);
    key = CryptoJS.enc.Utf8.parse(key);
    
  • CFB 是一种不需要填充的流密码模式。但是,在当前的 CryptoJS 代码中,使用零填充 (CryptoJS.pad.ZeroPadding)。相反,必须禁用填充(这不会隐式发生,与 Python 代码不同):

    padding: CryptoJS.pad.NoPadding,
    
  • CFB 配置了一个附加参数,即段大小,它指定每个加密步骤加密的位数。 CryptoJS 代码仅支持一种段大小,即 128 位。使用 PyCryptodome 可以配置段大小,默认使用 8 位。为了兼容性,必须将其更改为 128 位:

    aes_obj = AES.new(str_key.encode('utf-8'), AES.MODE_CFB, salt, segment_size=128)
    

通过这些更改,两个代码都是兼容的。

测试:两个代码都为以下明文提供以下密文:

plaintext:  The quick brown fox jumps over the lazy dog
ciphertext: m0T/7e04eV49RTcgd7KtwHxSOavNzHNwlrvjt1YmmHidBy4rHS0oovclKQ==

请注意,您所说的实际上是初始化向量 (IV)。术语“盐”更常用于 key 导出函数(如 PBKDF2)。

关于安全性:用于测试的 salt 和 IV 的值是可以的,但在现实场景中,必须为每次加密的 IV 应用随机字节序列,该随机字节序列必须与密文一起传递到解密端(通常串联)。
此外,作为 key ,不必使用密码,而是使用随机字节序列。密码(当然是强密码)只能与 key 派生函数结合使用。

关于用Crypto.js和pycrypto加密生成不同的加密密文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75252906/

相关文章:

c++ - 无法在 OpenSSL 中设置公钥/私钥

c# - 我的 C# 和 PHP 解密方法有何不同?

java - 请帮助-卡住无效 key 异常

java - python AES加密java解密

ruby-on-rails - 无法在 Ruby on Rails 应用程序中使用 openssl

java - 使用 Meteor 和 Java 加密和解密数据

java - 使用x509证书加密.net中的xml文件和解密java中的加密文件

javascript - 如何使用javascript文件解码编码?

go - Go中的生物识别登录(webauthn),如何验证签名

encryption - 加密/解密字符串 Kotlin