gpt4 book ai didi

php - PHP通过CBC实现密文窃取(CTS)

转载 作者:行者123 更新时间:2023-12-03 02:05:32 27 4
gpt4 key购买 nike

我一直试图在PHP中为CBC实现Ciphertext Stealing(CTS)。

在下面引用两个链接

How can I encrypt/decrypt data using AES CBC+CTS (ciphertext stealing) mode in PHP?



http://en.wikipedia.org/wiki/Ciphertext_stealing

我对XOR的最后一步和最简单的步骤感到困惑和困惑。
我知道这很愚蠢,但是尝试了所有组合之后,我不知道我在想什么。
代码如下。



// 1. Decrypt the second to last ciphertext block, using zeros as IV.       
$second_to_last_cipher_block = substr($cipher_text, strlen($cipher_text) - 32, 16);
$second_to_last_plain = @mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $second_to_last_cipher_block, MCRYPT_MODE_CBC);

// 2. Pad the ciphertext to the nearest multiple of the block size using the last B-M
// bits of block cipher decryption of the second-to-last ciphertext block.
$n = 16 - (strlen($cipher_text) % 16);
$cipher_text .= substr($second_to_last_plain, -$n);

// 3. Swap the last two ciphertext blocks.
$cipher_block_last = substr($cipher_text, -16);
$cipher_block_second_last = substr($cipher_text, -32, 16);
$cipher_text = substr($cipher_text, 0, -32) . $cipher_block_last . $cipher_block_second_last;

// 4. Decrypt the ciphertext using the standard CBC mode up to the last block.
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init($cipher, $key, $iv);
$plain_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher_text, MCRYPT_MODE_CBC , $iv);

// 5. Exclusive-OR the last ciphertext (was already decrypted in step 1) with the second last ciphertext.
// ???
// echo $??? ^ $???;

最佳答案

我发现具体的用例对理解算法非常有帮助。这里有2个用例,以及分步演练。

两种用例的起点。

这些用例假定您要解密的消息使用具有CBC链接模式和密文窃取的AES-256进行块量化。为了生成这些用例,我使用了Delphi 2010编译器和TurboPower LockBox3库(SVN修订版243)。在下面的内容中,我使用这样的表示法...

IV := [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


...表示将名为“ IV”的某些变量分配为等于16个字节的数组。最左边的字节是数组的最低符号(最低地址)字节的呈现,而最右边的字节是最高有效字节的呈现。这些字节以十六进制表示,因此,例如,如果放置...

X := [2] 03 10


...这表示LSB为3而MSB为16

用例一


让AES-256 32字节压缩密钥(按AES标准定义)为...

key = [32] 0D EE 8F 9F 8B 0B D4 A1 17 59 FA 05 FA 2B 65 4F 23 00 29 26 0D EE 8F 9F 8B 0B D4 A1 17 59 FA 05


使用TurboPower LockBox 3,可以通过将TCodec组件的密码('UTF8Password')属性设置为...来实现。

password = (UTF-8) 'Your lips are smoother than vasoline.'

要发送的纯文本消息将是

Message = (UTF-8) 'Leeeeeeeeeroy Jenkins!'


编码为22个字节长。 AES-256的块大小为16字节,因此长度在1到2个块之间。
令IV为1。(此外:在Delphi端,这可以通过设置

TRandomStream.Instance.Seed := 1;


加密之前)。
因此,将由PHP解密的密文消息将是(带有一个8字节的IV,前面加一个la LockBox3)...

ciphertext = [30] 01 00 00 00 00 00 00 00 17 5C C0 97 FF EF 63 5A 88 83 6C 00 62 BF 87 E5 1D 66 DB 97 2E 2C
(base64 equivalent ='AQAAAAAAAAAXXMCX/+9jWoiDbABiv4flHWbbly4s')


将其分解为IV,第一个密文块(c [0])和最后一个(部分)密文块(c [1])...

IV = [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c[0] = [16] 17 5C C0 97 FF EF 63 5A 88 83 6C 00 62 BF 87 E5
c[1] = [6] 1D 66 DB 97 2E 2C

现在,让我们逐步了解密文窃取的解密过程。


简历:= IV

CV = [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

通常,对于第n个块(最后2个块除外),我们的常规CBC算法是...

m[n]    := Decrypt( c[n]) XOR CV;
CV[n+1] := c[n]


哪里:


m是输出的纯文本块;
Decrypt()表示该块上的AES-256 ECB解密;
简历是我们的载体。链接模式定义了它如何在块之间变化。

但是对于倒数第二个块(N-1)(用例一中的N = 2),转换更改为...(此例外是由于选择了密文窃取而造成的)

m[n]    := Decrypt( c[n]) XOR CV;
CV[n+1] := CV[n] // Unchanged!

适用于我们的用例:

CV = [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c[0] = [16] 17 5C C0 97 FF EF 63 5A 88 83 6C 00 62 BF 87 E5
Decrypt(c[0]) = [16] 6F 6B 69 6E 73 21 F0 7B 79 F2 AF 27 B1 52 D6 0B
m[0] := Decrypt(c[0]) XOR CV = [16] 6E 6B 69 6E 73 21 F0 7B 79 F2 AF 27 B1 52 D6 0B


现在处理最后一个块。它是一部分,长度为6个字节。通常,最后一个块的处理如下:

y := c[N-1] | LastBytes( m[N-2], BlockSize-Length(c[N-1]));
m[N-1] := Decrypt( y) XOR CV


应用于用例一:

c[1] = [6] 1D 66 DB 97 2E 2C
y := c[1] | LastBytes( m[0], 10)
y = [16] 1D 66 DB 97 2E 2C F0 7B 79 F2 AF 27 B1 52 D6 0B
Decrypt( y) = [16]= 4D 65 65 65 65 65 65 65 65 65 72 6F 79 20 4A 65
m[1] := Decrypt(y) XOR CV
m[1] = [16] 4C 65 65 65 65 65 65 65 65 65 72 6F 79 20 4A 65

解密过程的最后一步是最后两个块的发射。我们颠倒顺序,先发射m [N-1],然后发射m [N-2]的第一部分(其长度等于c [N-1]的长度)。申请用例一...


发射m [1]

m[1] = [16] 4C 65 65 65 65 65 65 65 65 65 72 6F 79 20 4A 65

发出m [0]的前6个字节

FirstBytes( m[0], 6) = 6E 6B 69 6E 73 21

综上所述,我们得到了...的重构明文。

[22] 4C 65 65 65 65 65 65 65 65 65 72 6F 79 20 4A 65 6E 6B 69 6E 73 21



这是“ Leeeeeeeeeroy Jenkins!”的UTF-8编码!


用例二

在此用例中,消息正好是2个块长。这称为圆盒。在圆形情况下,没有部分块可以量化,因此它像正常的CBC一样进行。密码,密钥和IV与用例一相同。要解密的密文消息(包括前置8字节IV)为...


建立

Ciphertext = [40] 01 00 00 00 00 00 00 00 70 76 12 58 4E 38 1C E1 92 CA 34 FB 9A 37 C5 0A 75 F2 0B 46 A1 DF 56 60 D4 5C 76 4B 52 19 DA 83
which is encoded base64 as 'AQAAAAAAAABwdhJYTjgc4ZLKNPuaN8UKdfILRqHfVmDUXHZLUhnagw=='


可以分为四段,第一段和第二段,就像这样...

IV = [16] 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c[0] = [16] 70 76 12 58 4E 38 1C E1 92 CA 34 FB 9A 37 C5 0A
c[1] = [16] 75 F2 0B 46 A1 DF 56 60 D4 5C 76 4B 52 19 DA 83

一般和倒数第二

Decrypt(c[0]) = [16] 45 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72
m[0] := Decrypt(c[0]) XOR CV = [16] 44 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72
Next CV := c[0] = [16] 70 76 12 58 4E 38 1C E1 92 CA 34 FB 9A 37 C5 0A

最后一块:

在此用例中,我们的最后一块是圆形的。

Decrypt(c[1]) = [16] 75 F2 0B 46 A1 DF 56 60 D4 5C 76 4B 52 19 DA 83
m[1] := Decrypt(c[1]) XOR CV = [16] 65 65 76 65 72 20 79 6F 75 20 6D 61 79 20 62 65

解密过程的最后一步是最后两个块的发射。在这种情况下,我们不会撤销订单。我们先发射m [N-2],然后发射m [N-1]。应用于用例二...


发射m [0]

m[0] = [16] 44 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72

发射整个m 1

m[1] = [16] 65 65 76 65 72 20 79 6F 75 20 6D 61 79 20 62 65

综上所述,我们得到了...的重构明文。

[32] 44 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72 65 65 76 65 72 20 79 6F 75 20 6D 61 79 20 62 65



这是“无论您在哪里,都可以跳舞”的UTF-8编码
要考虑的边缘案例。
有两种边缘情况,此处提供的两个用例未对此进行说明。


短消息。短消息是一条消息,其长度以字节为单位:


不为零;和
少于一个街区;

零长度消息。



在短消息的情况下,从技术上讲,仍然可以通过使用IV作为密文的前一块来实现密文窃取。但是,恕我直言,以这种方式使用密文窃取的理由并不在于缺乏对密码强度影响的研究,更不用说增加了实现复杂性。在TurboPower LockBox 3中,当消息为短消息,并且链接模式不是密钥流式消息时,则将链接模式视为CFB-8bit。 CFB-8位是密钥流模式。

对于零长度的消息,它真的很简单。零长度的明文消息将一对一映射到零长度的密文消息。不需要,不需要生成或添加IV。该映射与链接模式和密码无关(在块模式密码的情况下)。

有关PHP实现的说明

警告

我不是PHP程序员。我不懂PHP。我在这里说的任何话都应加一点盐。

字节数组

似乎您正在使用PHP字符串存储字节数组。这对我来说很危险。如果字节值之一为零怎么办?这会缩短字符串吗?在这种情况下,strlen()的行为如何?如果PHP的本机数据类型是字节数组,那么这可能会更安全。但是我真的不知道。如果您还没有意识到这一点,那么我只是想提醒您。可能这并不是一个真正的问题。

mcrypt_decrypt库

我对这个图书馆不熟悉。它本身支持密文窃取吗?我认为不是。因此,您有两种可能的策略。


使用CBC模式为除最后两个块以外的所有块调用库的解密。按照我对您的描述处理最后两个块。但这需要使用CV。 API是否公开了此信息?如果没有,则此策略对您而言不是可行的选择。
使用ECB模式为除最后两个块之外的所有块调用库的解密,然后滚动CBC链接。相当容易实现,并且可以定义,您可以使用CV。


如何在PHP中进行XOR

有人发布了该问题的答案,但目前已撤回。但是他是对的。似乎要在PHP中对字节数组进行XOR,一个接一个地遍历字符,然后对字节进行XOR。该技术显示为 here

关于php - PHP通过CBC实现密文窃取(CTS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12328320/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com