部分加密和解密似乎不起作用

Encrypt and decrypt by parts do not seem to work

考虑代码:

const CryptoJS = require("crypto-js");

var key = CryptoJS.enc.Hex.parse("000102030405060708090a0b0c0d0e0f");
var iv = CryptoJS.enc.Hex.parse("101112131415161718191a1b1c1d1e1f");

// encrypt
var aesEncryptor = CryptoJS.algo.AES.createEncryptor(key, { iv: iv });

var ciphertextPart1 = aesEncryptor.process("Message Part 1");
var ciphertextPart2 = aesEncryptor.process("Message Part 2");
var ciphertextPart3 = aesEncryptor.process("Message Part 3");
var ciphertextPart4 = aesEncryptor.finalize();

// decrypt
var aesDecryptor = CryptoJS.algo.AES.createDecryptor(key, { iv: iv });

var plaintextPart1 = aesDecryptor.process(ciphertextPart1);
var plaintextPart2 = aesDecryptor.process(ciphertextPart2);
var plaintextPart3 = aesDecryptor.process(ciphertextPart3);
var plaintextPart4 = aesDecryptor.process(ciphertextPart4);
var plaintextPart5 = aesDecryptor.finalize();

console.log(plaintextPart5.toString());

来源:https://cryptojs.gitbook.io/docs/#ciphers

也许我错了,但是我希望消息被解密

实际输出为:

61676520506172742033

我不知道输出的含义和来源。

如果我打印出另一部分,同样的问题:

console.log(plaintextPart4.toString());

输出:

7373616765205061727420324d657373

讨论

一条评论说我对这个方法的工作原理的假设是错误的,一个好的答案也可以很好地纠正我!从我的研究中,我知道单向加密和部分加密之间的区别:它的实际工作方式对我来说毫无意义,它似乎是一个错误。我的想法是你可以继续添加要加密的消息,就像我们可以使用散列一样,在散列的情况下(来自上述相同来源),它似乎有效,为什么不加密呢?

.process 方法 returns 通过处理作为 .process 的参数给出的明文以及早期加密器遗留下来的任何明文而生成的任何新密文块activity.

在这种情况下,密码算法是 AES。具体来说是 AES-128,因为用于创建加密器的密钥是 128 位长。 AES-128 使用 128 位(16 字节)块中的明文,并为每个明文块发出 128 位(16 字节)的密文。这种基于块的处理会产生您不理解的结果。

你的程序会发生什么:

var ciphertextPart1 = aesEncryptor.process("Message Part 1");

加密器有 14 个字节的输入。这不足以让它生成密文块,因此 .process returns 一个空的密文结果存储在 ciphertextPart1 中。加密器内部存储未处理的 14 个字节。

var ciphertextPart2 = aesEncryptor.process("Message Part 2");

这给了加密器另外 14 个字节。它将这些附加到上次调用留下的 14 个字节,因此它现在总共有 28 个未处理的字节。它会尽可能多地处理这些字节。也就是说,它处理这些字节的前 16 个 ("Message Part1Me") 和 returns 这 16 个字节的密文块,您将其存储在 cipherText2 中。加密器现在包含 12 个未处理的字节。

var ciphertextPart3 = aesEncryptor.process("Message Part 3");

这给了加密器另外 14 个字节。它现在有 26 个未处理的字节。它处理这些字节的前 16 个 ("ssage Part2Mess") 和 returns 存储在 cipherText3 中的这 16 个字节的密文块。加密器现在包含 10 个未处理的字节。

var ciphertextPart4 = aesEncryptor.finalize();

这会强制加密器处理任何未处理的字节。它只能在 16 字节的块上工作,因此它向剩余的 10 个未处理的明文字节 ("age Part 3") 添加 6 个字节的填充,加密该块和该块的密文 returns。您将该密文块存储为 ciphertextPart4.

现在你解密密文块。

var plaintextPart1 = aesDecryptor.process(ciphertextPart1);

cipherTextPart1 是一个空块,所以 plaintextPart1 将是空的,显然解密器将不会保留任何未处理的密文。

var plaintextPart2 = aesDecryptor.process(ciphertextPart2);

cipherTextPart2 包含明文前 16 个字节的加密版本,因此 plaintextPart2 将包含 "Message Part 1Me"。密文输入正好是 16 个字节长,因此解密器不包含未处理的密文。

var plaintextPart3 = aesDecryptor.process(ciphertextPart3);

cipherTextPart3 包含明文接下来 16 个字节的加密版本,因此 plaintextPart3 将包含 "ssage Part 2Mess"。同样,解密器没有未处理的密文。

var plaintextPart4 = aesDecryptor.process(ciphertextPart4);

cipherTextPart4 包含明文最后 10 个字节的加密版本,因此 plaintextPart3 将包含 "age Part 3"。解密器中没有未处理的密文。

var plaintextPart5 = aesDecryptor.finalize();

解密器中没有未处理的密文,因此finalize没有工作要做,plaintextPart5将为空。

I honestly expected this example to work since it is from the official documentation, and they do not mention anything.

全面的文档是一种罕见的野兽。

it makes no sense to me the way it is actually working, it seems a bug

它是这样工作的:

const CryptoJS = require("crypto-js");

const original_message = " ...0, ...1, ...2, ...3, ...4, ...5, ...6, ...7, ...8, ...9, ...The End!"

var key = CryptoJS.enc.Hex.parse("000102030405060708090a0b0c0d0e0f");
var iv  = CryptoJS.enc.Hex.parse("101112131415161718191a1b1c1d1e1f");

const aesEncryptor = CryptoJS.algo.AES.createEncryptor(key, { iv: iv });
const aesDecryptor = CryptoJS.algo.AES.createDecryptor(key, { iv: iv });

const fragment_size = 25
const e_acc = []
for(let i = 0 ; i*fragment_size < original_message.length ; ++i ) {
  const slice = original_message.slice(i*fragment_size, i*fragment_size + fragment_size)
  console.log("slice to encrypt", slice)
  e_acc.push(aesEncryptor.process(slice));
}
e_acc.push(aesEncryptor.finalize());

let message = ""
for(let i = 0 ; i !== e_acc.length ; ++i ) {
  message += aesDecryptor.process(e_acc[i]).toString(CryptoJS.enc.Utf8)
  console.log("intermidiate message", message) 
}
message += aesDecryptor.finalize().toString(CryptoJS.enc.Utf8)
console.log("full message", message) 

[...] it supposes to be a trick that you can add information by parts
[...] My idea is that you could keep adding message to be encrypted

而且您可以,唯一的问题是 - 您无法破译未填充块的消息部分。您只能获得适合 完整 块链的数量。

考虑代码

const sum1 = solver.process("1+22+3")
const sum2 = solver.process("03")
const sum3 = solver.finalize()

在这里你可以获得中级 sum1 - 122 的总和。但是您不能立即添加 3,因为稍后您会看到,它实际上不是 3,而是 303。与 sum2 相同 - solver 还不知道是否应该添加 303 或者它可能会变成 3031234...。所以 solver 唯一能做的就是记住 3 然后 303,但不要使用它。直到你打电话给 finalize

aesEncryptor 类似于 solver 但要复杂得多。

让我们回到 aesDecryptor 以及为什么所有 plaintextPart* 只包含消息的一部分...为什么首先需要 "Progressive Ciphering"?可能是因为您正在通过网络发送片段?关键字是 碎片 - 它们故意不包含消息的所有先前部分,因为它们可能有千兆字节!

in the case of hashing [...], it seems to work, why not for encryption as well?

哈希是完全不同的东西。您不能指望 AES 具有与散列法相同的所有属性,因为您不能指望散列法具有与求和等所有相同的属性。