在AES密码对象上禁用PKCS#7填充?

时间:2016-10-30 12:14:12

标签: c encryption openssl aes pkcs#7

我正在编写一个保险丝文件系统,我有一个问题。

我正在使用CBC AES加密磁盘中的数据。问题是填充。当密码大小例如是15个字节时,没有问题,因为它增加了1个字节。问题是,当我试图加密4096字节时,它还增加了我16字节的padd,它对我来说是失败的。我不知道它为什么添加填充因为4096是128(size aes block)的倍数。我需要修改我的c代码,对openssl说只有在需要时才添加填充但不总是......

我知道如果明文不是128的倍数,那么它将添加填充。但为什么不呢?我该怎么办?

这是我的密码:

    int encrypt_data(unsigned char *plaintext, int plaintext_len, unsigned char *key,
                unsigned char *iv, unsigned char *ciphertext, int algorithm_pos)
{
        EVP_CIPHER_CTX *ctx;

        int len;

        int ciphertext_len;

        /* Create and initialise the context */
        if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

        /* Initialise the encryption operation. IMPORTANT - ensure you use a key
         * and IV size appropriate for your cipher
         * In this example we are using 256 bit AES (i.e. a 256 bit key). The
         * IV size for *most* modes is the same as the block size. For AES this
         * is 128 bits */
        if(1 != EVP_EncryptInit_ex(ctx, ciphers[algorithm_pos].algorithm(), NULL, key, iv))
                handleErrors();

        /* Provide the message to be encrypted, and obtain the encrypted output.
         * EVP_EncryptUpdate can be called multiple times if necessary
         */
        if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
                handleErrors();
        ciphertext_len = len;

        /* Finalise the encryption. Further ciphertext bytes may be written at
         * this stage.
         */
        if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
        ciphertext_len += len;

        /* Clean up */
        EVP_CIPHER_CTX_free(ctx);

        return ciphertext_len;
}

2 个答案:

答案 0 :(得分:3)

PKCS#7 padding。填充块大小的精确倍数的原因是没有办法判断是否没有填充,因此必须始终或永远不要使用填充。考虑数据是否为4096字节,最后一个字节是0x01。看起来像填充的一个字节,但它不是,它是数据的一部分。

但是您应该使用磁盘扇区加密模式,例如XTS,XTS仅建议用于全盘加密。这就是它由IEEE标准1619设计的。

请参阅Explanation of the XTS Encryption Mode

也是NIST:The XTS-AES Mode for Confidentiality on Storage Devices

答案 1 :(得分:0)

  

问题在于,当我尝试加密4096字节时,它还会增加16字节的padd,这对我来说是失败的。我不知道它为什么添加填充因为4096是128(size aes block)的倍数。

正如Zaph所述,正在添加PKCS#7填充。填充是确定性的,因此也填充16个字节的精确倍数以确保移除。否则,广义算法如何知道何时(1)纯文本在16字节边界上结束,而(2)纯文本在16字节边界上结束并填充?

您可以使用EVP_CIPHER_CTX_ctrlEVP_CIPHER_CTX_set_padding禁用密码对象的填充行为。 EVP_CIPHER_CTX_set_paddingEVP_CIPHER_CTX_ctrl的宏观版本。这是它的样子:

int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *x, int padding);

从手册页:

  

EVP_CIPHER_CTX_set_padding()启用或禁用填充。默认情况下   加密操作使用标准块填充和填充   在解密时检查并删除填充。如果是pad参数   为零,则不执行填充,即数据总量   加密或解密必须是块大小的倍数或   会发生错误。

  

我知道如果明文不是128的倍数,那么它将添加填充。但为什么不呢?我该怎么办?

禁用密码上下文对象的填充。以下是图书馆的工作方式:

$ grep -IR EVP_CIPHER_CTX_set_padding *
CHANGES:  *) New function EVP_CIPHER_CTX_set_padding() this is used to
apps/enc.c:            EVP_CIPHER_CTX_set_padding(ctx, 0);
apps/speed.c:                EVP_CIPHER_CTX_set_padding(&ctx, 0);
crypto/cms/cms_pwri.c:    EVP_CIPHER_CTX_set_padding(&kekctx, 0);
crypto/evp/evp.h:int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad);
crypto/evp/evp_enc.c:int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad)
crypto/evp/evp_test.c:        EVP_CIPHER_CTX_set_padding(&ctx, 0);
crypto/evp/evp_test.c:        EVP_CIPHER_CTX_set_padding(&ctx, 0);