我一直在尝试在PHP中为CBC实现密文窃取(CTS)。
参考下面两个链接
如何在PHP中使用AES CBC CTS(密文窃取)模式加密/解密数据?
和
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 $??? ^ $???;
我正在为perl寻找类似的答案。Perl的库仅限于CBC模式。以下是我如何使用AES 256 CBC模式和CTS方法3让CTS工作的。我认为这可能对PHP也有帮助。
以下是实际的 NIST 文档。文档编号: NIST800-38A CBC-CS3 标题: 建议分组密码操作模式;CBC模式密文窃取的三种变体 来源:http://csrc.nist.gov/publications/nistpubs/800-38a/addendum-to-nist_sp800-38A.pdf
这是密码。。。
use Crypt::CBC;
use Crypt::Cipher::AES;
my $key = pack("H*","0000000000000000000000000000000000000000000000000000000000000000");
my $iv = pack("H*","00000000000000000000000000000000");
my $pt = pack("H*","0000000000000000000000000000000000");
my $ct = aes256_cbc_cts_decrypt( $key, $iv, $pt );
#AES 256 CBC with CTS
sub aes256_cbc_cts_decrypt {
my ($key, $iv, $in) = @_;
my $len_in_bytes = length(unpack("H*", $in)) / 2;
my $in_idx = 0;
my $null_iv = pack( "H32", "00000000000000000000000000000000");
my $cipher = Crypt::CBC->new(
-key => $key,
-iv => $null_iv,
-literal_key => '1',
-keysize => 32,
-blocksize => 16,
-header => 'none',
-cipher => 'Crypt::Cipher::AES');
my $out;
while ( $len_in_bytes >= 16 )
{
my $tmp = substr($in, $in_idx, 16);
my $outblock = $cipher->decrypt($tmp);
if ( ( ($len_in_bytes % 16) eq 0 ) || ( $len_in_bytes > 32 ) )
{
$outblock = $outblock ^ $iv;
$iv = $tmp;
}
$out .= $outblock;
$in_idx += 16;
$len_in_bytes -= 16;
}
if ($len_in_bytes) {
my $tmp = substr($in,$in_idx,$len_in_bytes);
my $out_idx = $in_idx - 16;
$tmp .= substr($out,$out_idx + $len_in_bytes, 16 - $len_in_bytes);
$out .= substr($out, $out_idx, $len_in_bytes) ^ substr($tmp, 0, $len_in_bytes);
substr($out,$out_idx,16) = $iv ^ $cipher->decrypt($tmp);
}
return $out;
}
我发现具体的用例对理解算法很有帮助。这里有两个用例,以及一个逐步的演示。
这些用例假设您正在使用AES-256和CBC链接模式解密消息,并使用密文窃取进行块量化。为了生成这些用例,我使用了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。(题外话:在德尔福方面,这可以通过设置来实现
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
现在让我们通过密文窃取来完成解密。
>
CV:=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]
其中:
但是对于倒数第二个块 (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]]的长度)。正在应用于用例一。。。
> < li>
发出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
这是“Leeeeeeroy Jenkins!”的UTF-8编码
在这个用例中,消息正好有2个块长。这被称为圆形外壳。在循环情况下,没有部分块要量化,所以它就像正常的CBC一样进行。密码、密钥和IV与用例1中的相同。要解密的密文消息(包括前置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]。应用于用例二...
> < li>
发出m[0]
m[0] = [16] 44 61 6E 63 65 20 74 68 65 6E 2C 20 77 68 65 72
发出m1的全部
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作为密文的前一块来实现密文窃取。然而,IMHO,这种使用密文窃取的方式是不合理的,因为缺乏对加密强度影响的研究,更不用说增加了实现的复杂性。在TurboPower LockBox 3中,如果消息是短消息,并且链接模式不是密钥流模式,则链接模式被视为CFB-8bit。CFB-8位是一种密钥流模式。
对于零长度消息,这非常简单。零长度明文消息一对一地映射到零长度密文消息。不需要、不生成也不预先考虑IV。这种映射独立于链接模式和密码(在块模式密码的情况下)。
我不是PHP程序员。我不懂PHP。我在这里说的任何事情都不能全信。
看起来你在使用PHP字符串来存储字节数组。这对我来说很危险。如果其中一个字节值为零呢?这会缩短字符串吗?在这种情况下strlen()会有什么行为?如果PHP有一个本机数据类型,它是一个字节数组,那么这可能会更安全。但我真的不知道。如果你还没有意识到这一点,我只是提醒你注意。可能这不是一个真正的问题。
我对这个图书馆不熟悉。它本身是否支持密文窃取?我想不会吧。所以有两种可能的策略。
>
在CBC模式下,调用库的解密来解密除最后两个块之外的所有块。按照我向您描述的方式处理最后两个块。但这需要访问简历。API是否公开了这一点?如果没有,这个策略对你来说不是一个可行的选择。
用ECB模式调用库的decrypt,除了最后两个块,并滚动CBC链接。相当容易实现,并被定义,你可以访问的简历。
还有人发布了这个问题的答案,但目前已经撤回了。但他是对的。它看起来像是在PHP中对字节数组执行XOR,逐个遍历字符,然后执行字节级XOR。此处显示了该技术。
我必须在PHP中以AES CTS模式(密文窃取,有时称为AES-XTS)加密和解密数据,以便与用NET平台。英寸NET 4,本机支持这种模式。 对于PHP,我找不到解决方案,根据手册,mcrypt似乎不支持这种模式。 任何人都可以解释一下普通CBC和CBC-CTS之间的区别吗?是否可以使用现有的模块/库使后者在PHP中工作?
几天来,我一直试图用java解密一个用OpenSSL加密的消息。使用以下命令对邮件进行了加密: openssl enc-e-aes-256-cbc-kfile$file.key-in toto-out toto.enc。 文件file.key包含256位的对称密钥。命令中没有指定salt,但文件以salted__开头。下面是我编写的类,试图解密文件,但即使删除文件的16个字符也无法得到任何东西,即
问题内容: Java 256位AES加密 基本上,我正在做的是编写一个程序,该程序将加密通过TCP / IP发送的请求,然后由服务器程序解密。加密将需要是AES,并且进行一些研究后发现我需要使用CBC和PKCS5Padding。所以基本上我也需要一个秘密密钥和一个IV。 我正在开发的应用程序是用于手机的,因此我想使用Java安全包来减小尺寸。我已经完成了设计,但是不确定IV和共享密钥的实现。 这是
我有一个Python应用程序和PHP网站,通过一些特定的网络层发送消息进行通信。我的任务是使用该通道发送所有AES加密和Base64编码的消息。加密密钥是为双方手动预共享的。 在PHP中,我使用以下代码创建名为的最终消息文本: 我在我的Python应用程序中收到这样的消息,去掉了魔力,得到了base64字节的数据。我找不到一个示例来使兼容的AES密码来解码此消息的问题。 Key和“Magic”只是
下面是我到现在为止所尝试的 下面是适用于我的node.js代码。在CryptoJ中,我没有成功地实现类似的功能。根据我的理解,crypto是内置库,其中的节点在其上有自己的包装器。
我使用以下命令加密了一个文件 openssl rand 32>test.key openssl enc-aes-256-cbc-iter 10000-pbkdf2-salt-输入test.txt-输出test.txt.enc-通过文件:test.key 我的代码 我得到的错误 我引用了以下链接 尝试使用时,仍然得到错误