在我的C代码中,我在CTR模式下使用OpenSSL的AES通过EVP接口进行加密,即我有这样的事情:
ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, key, iv))
...
ret = EVP_EncryptUpdate(ctx, out, &outlen, in, inlen);
输入数据的长度不是AES块大小的倍数,因此如果使用CBC模式,我将不得不在输出缓冲区中为填充分配额外的字节。
我是否需要在点击率模式下做同样的事情?而且我对CFB和OFB模式感到好奇。
EVP_EncryptUpdate上的OpenSSL man没有提到任何关于“类似流”模式的具体内容,他们只是警告需要填充的额外字节。
答案 0 :(得分:2)
TLDR:执行副总裁不支持点击率(及其他流模式/密码)
实际上EVP_EncryptUpdate
本身从不会填充,尽管它可以随身携带'从一个电话到下一个电话的部分阻止;因此,如果代码中的...
不包含任何先前的EncryptUpdate
,那么此(第一个)EncryptUpdate
将始终是块对齐的,并且其输出将永远不会更长:
EVP_EncryptUpdate()从缓冲区加密inl字节,并将加密版本写入out。可以多次调用此函数来加密连续的数据块。写入的数据量取决于加密数据的块对齐:因此写入的数据量可以是从零字节到(inl + cipher_block_size - 1)的任何值,因此out应包含足够的空间。写入的实际字节数放在outl中。它还检查in和out是否部分重叠,如果它们为0则返回以指示失败。
EVP_EncryptFinal[_ex]
添加了填充,因此添加了额外的'在需要时输出,如手册页的下一段所述:
如果启用了填充(默认值),则EVP_EncryptFinal_ex()会加密" final"数据,即保留在部分块中的任何数据。它使用标准块填充(也称为PKCS填充),如下面的NOTES部分所述。加密的最终数据被写入,其中应该有足够的空间用于一个密码块。写入的字节数放在outl中。调用此函数后,加密操作完成,不再调用EVP_EncryptUpdate()。
如果禁用填充,则EVP_EncryptFinal_ex()将不再加密任何数据,如果任何数据保留在部分块中,它将返回错误:即总数据长度不是块大小的倍数。
但是,由于密文实际上包含所有Update
个呼叫的输出(或只有一个呼叫)加上 Final
呼叫的输出,在填充 em>的情况下,总缓冲区确实需要(最多)一个块大于输入。
手册页没有说(并且应该)是填充不适用于流密码(如RC4)或流模式(包括CTR OFB * CFB *)。每个密码/模式组合由EVP_CIPHER
类型的对象描述,该对象是struct evp_cipher_st
的typedef;这是EVP_aes_256_ctr()
和类似例程返回指针的内容。除此之外,这个结构包含一个字段block_size
,它包含,你猜对了,块大小(以字节为单位)。对于流模式和密码,它包含一个特殊处理的虚拟值1:EncryptFinal_ex
即使启用也不添加填充,DecryptFinal_ex
即使启用也不会删除和检查填充。
答案 1 :(得分:1)
对于CTR模式,我是否需要输出缓冲区为AES块大小的倍数?
不,CTR模式没有这个要求。在这方面,CTR模式类似于OFB和CFB模式。相比之下,ECB和CBC模式需要块大小的倍数。
OpenSSL使用 Init / Update / Final 模式,输入和输出字节都被缓冲,直到需要为止。如果你愿意的话,你可以一次插入一个字节。
在内部,EVP对象将缓冲输入,直到足以执行加密。由于CTR模式可以流式传输,因此在处理一个输入字节后,一个输出字节将可用(它是带有纯文本的加密计数器的简单XOR)。 EVP对象也将缓冲输出字节,直到您调用Final。