Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/41.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 是否可以使用nodejs密码在任意位置破译?_Node.js_Encryption_Aes_Random Access_Node Crypto - Fatal编程技术网

Node.js 是否可以使用nodejs密码在任意位置破译?

Node.js 是否可以使用nodejs密码在任意位置破译?,node.js,encryption,aes,random-access,node-crypto,Node.js,Encryption,Aes,Random Access,Node Crypto,我的理解是,理论上,CTR模式下的AES分组密码允许破译大文件的任何位置,而无需读取整个文件 但是,我不知道如何使用nodejs加密模块实现这一点。我可以在Decipher.update方法中输入虚拟块,直到我找到我感兴趣的部分,在这一点上,我会输入从文件中读取的实际数据,但这将是一个可怕的黑客行为,效率低下,而且脆弱,因为我需要知道块的大小 有没有一种方法可以使用加密模块,如果没有,我可以使用什么模块 我可以在Decipher.update方法中添加虚拟块,直到找到我感兴趣的部分 正如@Art

我的理解是,理论上,CTR模式下的AES分组密码允许破译大文件的任何位置,而无需读取整个文件

但是,我不知道如何使用nodejs加密模块实现这一点。我可以在
Decipher.update
方法中输入虚拟块,直到我找到我感兴趣的部分,在这一点上,我会输入从文件中读取的实际数据,但这将是一个可怕的黑客行为,效率低下,而且脆弱,因为我需要知道块的大小

有没有一种方法可以使用加密模块,如果没有,我可以使用什么模块

我可以在Decipher.update方法中添加虚拟块,直到找到我感兴趣的部分

正如@Artjom已经评论过的,假设使用CTR模式,您不需要向文件开头或任何伪块提供数据。你可以直接输入你感兴趣的密文。(使用AES开始128位的块大小)

请参阅,您只需将IV计数器设置为密文的起始块,仅输入要解密的加密文件的一部分(如果需要,您可能需要输入起始块的伪字节)

例如:


您需要使用AES从位置1048577解密文件,它是块65536(1048577/16)加1字节。因此,您将IV设置为
nonce | 65536
,解密伪1字节(移动到16*65536+1的位置),然后您只需从您感兴趣的文件部分输入密文即可

我找到了不同的方法来解决此问题:

方法1:CTR模式 这个答案基于@ArtjomB。还有@gusto2评论和回答,这确实给了我解决方案。然而,这里有一个新的答案,其中有一个工作代码示例,它还显示了实现细节(例如,IV必须作为一个大端数字递增)

其思想很简单:要从
n
块的偏移量开始解密,只需将IV增加
n
。每个块是16个字节

import crypto = require('crypto');
let key = crypto.randomBytes(16);
let iv = crypto.randomBytes(16);

let message = 'Hello world! This is test message, designed to be encrypted and then decrypted';
let messageBytes = Buffer.from(message, 'utf8');
console.log('       clear text: ' + message);

let cipher = crypto.createCipheriv('aes-128-ctr', key, iv);
let cipherText = cipher.update(messageBytes);
cipherText = Buffer.concat([cipherText, cipher.final()]);

// this is the interesting part: we just increment the IV, as if it was a big 128bits unsigned integer. The IV is now valid for decrypting block n°2, which corresponds to byte offset 32
incrementIV(iv, 2); // set counter to 2

let decipher = crypto.createDecipheriv('aes-128-ctr', key, iv);
let decrypted = decipher.update(cipherText.slice(32)); // we slice the cipherText to start at byte 32
decrypted = Buffer.concat([decrypted, decipher.final()]);
let decryptedMessage = decrypted.toString('utf8');
console.log('decrypted message: ' + decryptedMessage);
此程序将打印:

clear text: Hello world! This is test message, designed to be encrypted and then decrypted decrypted message: e, designed to be encrypted and then decrypted 明文:你好,世界!这是一条测试消息,设计用于加密然后解密 解密消息:e,设计为先加密后解密 正如预期的那样,解密后的消息移位了32字节

最后,这里是增量IV实现:

function incrementIV(iv: Buffer, increment: number) {
    if(iv.length !== 16) throw new Error('Only implemented for 16 bytes IV');

    const MAX_UINT32 = 0xFFFFFFFF;
    let incrementBig = ~~(increment / MAX_UINT32);
    let incrementLittle = (increment % MAX_UINT32) - incrementBig;

    // split the 128bits IV in 4 numbers, 32bits each
    let overflow = 0;
    for(let idx = 0; idx < 4; ++idx) {
        let num = iv.readUInt32BE(12 - idx*4);

        let inc = overflow;
        if(idx == 0) inc += incrementLittle;
        if(idx == 1) inc += incrementBig;

        num += inc;

        let numBig = ~~(num / MAX_UINT32);
        let numLittle = (num % MAX_UINT32) - numBig;
        overflow = numBig;

        iv.writeUInt32BE(numLittle, 12 - idx*4);
    }
}
函数递增iv(iv:缓冲区,递增:编号){
如果(iv.length!==16)抛出新错误(“仅针对16字节iv实现”);
常数MAX_UINT32=0xFFFFFFFF;
让incrementBig=~~(increment/MAX\u UINT32);
让incrementLittle=(增量%MAX_UINT32)-incrementBig;
//将128位IV拆分为4个数字,每个数字32位
设溢出=0;
对于(让idx=0;idx<4;++idx){
设num=iv.readUInt32BE(12-idx*4);
让inc=溢出;
如果(idx==0)inc+=incrementLittle;
如果(idx==1)inc+=incrementBig;
num+=inc;
设numBig=~(num/MAX\UINT32);
设numLittle=(num%MAX_UINT32)-numBig;
溢出=numBig;
iv.writeUInt32BE(numLittle,12-idx*4);
}
}
方法2:CBC模式
由于CBC使用前面的密文块作为IV,并且在解密阶段所有密文块都是已知的,所以您没有任何特殊的事情要做,您可以在流的任何点进行解密。唯一的问题是,您解密的第一个块将是垃圾,但下一个块将是好的。因此,您只需在实际要解密的部分之前启动一个块。

是的,如果您可以计算存储在
缓冲区中的数字,以推进IV,则可以执行此操作。

此外,如果您使用AES,则块大小固定为16字节。@ArtjomB。您指的是使用虚拟数据重复调用
破译.update
的“解决方案”吗?我真的认为那不是一个好方法。假设我有一个1TB的文件,我只想在接近末尾的时候从中读取几MB。我不想计算1TB的密码块来最终破译几MB…好吧,所以我不明白@ArtjomB是什么。我想我现在更明白他和你的意思了。我仍然不确定IV的格式,你的意思是将随机IV与计数器连接起来吗?每个字节有多少字节,计数器的尾数是多少,哪一个先出现,等等?youen取决于IV的构造方式。IV是128位字节数组。维基百科将CTR IV描述为与计数器(64位+64位)连接的nonce。最常见的是,我看到IV随机初始化(没有人说计数器必须从0开始),然后您只需将块计数添加到初始IV值的二进制表示形式中。非常感谢,工作起来很有魅力。我不是想偷你的答案,但是我发布了一个带有工作代码示例的答案,因为我认为它可以帮助其他人解决同样的问题,因为它更精确。很好。。我觉得,
incrementIV
对我来说太复杂了(我用的是Java witch,它有本地的工具),但是看起来你让它工作了,很好job@gusto2当然,可以简化它,和/或使它更具可读性。但是,javascript中没有处理大于32位的数字的本机功能(实际上,所有数字都是双精度浮点,它只能编码高达50位的整数或类似的数字)。有像“bigint”和“bignum”这样的库,但我不喜欢添加太多的依赖项,因为我需要的只是10行代码。。。我已经在各种情况下测试过这个函数(包括溢出和循环回零),我认为它很好。