使用 NodeJS 的加密与使用 Python (cryptography.fernet) 的加密不匹配

Encryption with NodeJS doesn't match encryption using Python (cryptography.fernet)

这里是密码学菜鸟。我正在尝试在 NodeJS 中编写一个脚本,该脚本加密一个字符串并生成与使用 cryptography.fernet 库的 Python 脚本的输出相匹配的输出。我的总体目标是使用原始密钥加密 Node 中的消息,稍后将使用 Python.

对其进行解密

我的 Python 代码示例:

from cryptography.fernet import Fernet

key = Fernet.generate_key() # For example: 6saGtiTFEXej729GUWSeAyQdIpRFdGhfY2XFUDpvsu8=
f = Fernet(key)
message = 'Hello World'
encoded = message.encode()
encrypted = f.encrypt(encoded)

产生输出:gAAAAABhJs_E-dDVp_UrLK6PWLpukDAM0OT5M6bfcqvVoCvg7r63NSi4OWOamLpABuYQG-5wsts_9h7cLbCsWmctArXcGqelXz_BXl_o2C7KM9o7_eq7VTc=

我的节点脚本使用内置的加密模块,并且还必须使用我的 Python 程序中使用的相同 32 字节密钥。我知道 fernet 使用的是 AES-128-CBC 作为它的算法,所以这就是我在我的节点脚本中使用的算法。

我的 NodeJS 代码:

const crypto = require("crypto");

const key = '6saGtiTFEXej729GUWSeAyQdIpRFdGhfY2XFUDpvsu8=';
const algorithm = 'aes-128-cbc';
const message = 'Hello World';
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
const encrypted = cipher.update(message, 'utf8', 'hex') + cipher.final('hex');

哪个给我:Error: Invalid key length

我的第一个问题是我不确定如何转换密钥以使其长度合适。通过查看 fernet 的源代码,我还知道密钥分为两部分:前 16 个字节是 signing_key,最后 16 个字节是 encryption_key - 我没有找到太多信息whether/how 我需要在我的 Node 实现中处理这两个原始密钥。

由于我是新手,所以我对如何完成我所追求的目标感到有点困惑。非常感谢任何提示或建议。

可以在 https://github.com/fernet/spec/blob/master/Spec.md

上找到 Fernet 格式的规范

他们在那里指定了生成步骤和非常重要的步骤,这里是生成步骤,应该为您的实施提供足够的信息:

  • Record the current time for the timestamp field.
  • Choose a unique IV.
  • Construct the ciphertext:
    • Pad the message to a multiple of 16 bytes (128 bits) per RFC 5652, section 6.3. This is the same padding technique used in PKCS #7 v1.5 and all versions of SSL/TLS (cf. RFC 5246, section 6.2.3.2 for TLS 1.2).
    • Encrypt the padded message using AES 128 in CBC mode with the chosen IV and user-supplied encryption-key.
  • Compute the HMAC field as described above using the user-supplied signing-key.
  • Concatenate all fields together in the format above.
  • base64url encode the entire token.

由此可见,签名密钥(full key的前半部分)用在HMAC中,而后半部分用在AES128-CBC中,所以只需将密钥分成两个独立的元素(使用适当的从十六进制字符串到字节的转换)应该足以使用 Node.js 加密模块(https://nodejs.org/en/knowledge/cryptography/how-to-use-crypto-module/)构建您自己的实现。