python - 将 Python AES 转换为节点
问题描述
我一直无法让 Python 中的现有遗留代码像 NodeJS 一样加密/解密。我确实正确解码了前 16 个字符。
这是Python代码:
from Crypto.Cipher import AES
counter = b'HOJFKGQMRCTKUQHP'
cipher = AES.new(self.symmetric_key, AES.MODE_CTR, counter=lambda: counter)
encrypted = cipher.encrypt(data)
我发现每次迭代都使用相同的计数器的来源: PyCrypto problem using AES+CTR
在 NodeJS (ts-node) 中仅对前 16 个字符起作用的是:
import { createDecipheriv, Decipher } from 'crypto'
const decrypt = (inputBase64: string): string => {
const algorithm = 'aes-192-ctr'; // 24 byte key, 16 byte "counter"
var decipher: Decipher = createDecipheriv(algorithm, key, counter /* yes, it's an iv */)
// decipher.setAutoPadding(false);
return decipher.update(inputBase64, 'base64', 'utf8') + decipher.final('utf8');
}
我找到了各种在线资源,它们都增加了计数器 - 有没有办法使用内置的 Node 加密库来控制计数器的增量?我发现了一些我可能会覆盖的在线实现(如果发生这种情况): https ://github.com/ricmoo/aes-js/blob/master/index.js#L656 https://github.com/白利糖度/crypto-js/blob/develop/src/mode-ctr.js#L26
我怎样才能让它在 Node 中工作?我的 python 代码(这是遗留的,如果不迁移现有值就无法更改)具有以下输出:
encrypt('Testing--StackOverflow')
# outputs: 'r7G8gFNIHuY27nBjSo51nZ6mqZhVUQ=='
decrypt
从使用上述功能的节点:
const key = 'LKOXBRRUNBOSMENKEPPZUKWB';
const counter = 'HOJFKGQMRCTKUQHP';
const encrypted = 'r7G8gFNIHuY27nBjSo51nZ6mqZhVUQ==';
const clearText = decrypt(encrypted);
console.log('clear text:', clearText)
// outputs: clear text: Testing--StackOv�::��m
希望有人可以在这里分享一些见解!
解决方案
CTR 模式的本质是计数器的递增,这就是为什么这种模式实际上被称为计数器模式[1]。由于在 Python 代码中计数器是一个常量,即根本不递增,因此该代码最多形式地实现了 CTR 模式,但在功能上肯定不是,而且也是疏忽不安全的[2] [3]。
大多数图书馆都会尝试防止这种对 CTR 模式的滥用。因此,很难在 NodeJS(或任何其他语言)中找到一个有意使之成为可能的库。
尽管如此,NodeJS(或任何其他语言)中的解密相对容易通过手动实现该模式来实现:在 CTR 模式中,从 IV 生成一个字节序列,从初始 IV 开始,通过为每个附加相应的递增 IV堵塞。然后用 AES 对以这种方式生成的序列进行加密,并将结果与明文/密文[1]进行异或运算。该方案适用于加密和解密。由于 Python 代码不执行任何递增,因此必须简单地跳过此步骤,例如:
const crypto = require('crypto');
var algorithm = 'aes-192-ecb';
var key = Buffer.from('LKOXBRRUNBOSMENKEPPZUKWB', 'utf8');
var byteSeq = Buffer.from('HOJFKGQMRCTKUQHPHOJFKGQMRCTKUQHP', 'utf8');
var ciphertext = Buffer.from('r7G8gFNIHuY27nBjSo51nZ6mqZhVUQ==', 'base64');
// Encrypt the byte-sequence generated from the IV (no incrementation)
var cipher = crypto.createCipheriv(algorithm, key, null);
var byteSeqEnc = Buffer.concat([cipher.update(byteSeq), cipher.final()], byteSeq.length);
// XORing of ciphertext and IV
var decrypted = xor(ciphertext, byteSeqEnc);
console.log("Decrypted: " + decrypted.toString('utf8'));
// Output: Decrypted: Testing--StackOverflow
// Implementation of XOR
function xor(buf1, buf2){
var buf = Buffer.alloc(buf1.length);
for (i = 0; i < buf1.length; i++){
buf.writeUInt8(buf1.readUInt8(i, i + 1) ^ buf2.readUInt8(i, i + 1), i);
}
return buf;
}
字节序列的长度对应于明文/密文的长度,四舍五入为块大小的整数倍。在当前示例中,字节序列的长度为 32 个字节,并且为简单起见进行了硬编码。
推荐阅读
- policy - Azure API 管理限制多个调用方 IP 地址
- javascript - JavaScript 将函数参数与现有变量相结合
- c# - 为什么 EF 不能按另一个集合的顺序对项目进行排序以及如何解决?
- jquery - 如何获取for循环/javascript生成的textarea的值
- php - 条纹网络钩子
- windows - git - 强制 lf 行结尾不捕获二进制文件
- javascript - 安装 grunt 插件时如何修复需要 grunt@~0.4.0 的对等方?
- ios - 弹出包含 ARKit 场景视图的视图控制器后,应用程序停止响应触摸
- python - 如何在使用 crontab 安排的脚本中定期调用函数?
- javascript - 如何在angularjs控制器中以时间格式转换字符串