OpenSSL上的EVP_DecryptFinal_ex错误 [英] EVP_DecryptFinal_ex Error on OpenSSL

查看:243
本文介绍了OpenSSL上的EVP_DecryptFinal_ex错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用OpenSSL EVP例程,使用AES 128 cbc模式解密。



我使用NIST站点指定的测试向量来测试我的程序。 / p>

程序似乎在EVP_DecryptFinal_ex例程中失败。



有人可以告诉我有什么问题吗? p>

另外我如何在这里检查错误,找出为什么这个例程失败?



UPDATED:



请检查下面的代码。我加了加密和解密部分。加密作品。但在解密过程中,尽管两者匹配,但是密码的十六进制似乎是80字节,而不是预期的64字节(NIST中提到的),尽管解密工作和解密的文本符合明文!
有人可以澄清吗?



预期的密文值应为:

 密码:0000 76 49 ab ac 81 19 b2 46 ce e9 8e 9b 12 e9 19 7d 
0010 50 86 cb 9b 50 72 19 ee 95 db 11 3a 91 76 78 b2
0020 73 be d6 b8 e3 c1 74 3b 71 16 e6 9e 22 22 95 16
0030 3f f1 ca a1 68 1f ac 09 12 0e ca 30 75 86 e1 a7

这里是代码:

  #include< string。 h取代; 
#include< stdio.h>
#include< stdlib.h>
#include< openssl / evp.h>

int AES_BLOCK_SIZE;

int main(int argc,char ** argv)
{

EVP_CIPHER_CTX en;
EVP_CIPHER_CTX de;
EVP_CIPHER_CTX_init(& en);
EVP_CIPHER_CTX_init(& de);
const EVP_CIPHER * cipher_type;
unsigned char * mode;
unsigned char * passkey,* passiv,* plaintxt;
int vector_len = 0;
char * plain;
char * plaintext;
unsigned char * ciphertext;
int olen,len;
int i = 0;

// NIST VALUES TO CHECK

unsigned char iv [] =
{0x00,0x01,0x02,0x03,
0x04,0x05,0x06 ,0x07,
0x08,0x09,0x0a,0x0b,
0x0c,0x0d,0x0e,0x0f,0};

unsigned char key [] =
{0x2b,0x7e,0x15,0x16,
0x28,0xae,0xd2,0xa6,
0xab,0xf7,0x15,0x88 ,
0x09,0xcf,0x4f,0x3c,0};

unsigned char input [] =
{0x6b,0xc1,0xbe,0xe2,
0x2e,0x40,0x9f,0x96,
0xe9,0x3d,0x7e,0x11 ,
0x73,0x93,0x17,0x2a,

0xae,0x2d,0x8a,0x57,
0x1e,0x03,0xac,0x9c,
0x9e,0xb7,0x6f ,0xac,
0x45,0xaf,0x8e,0x51,

0x30,0xc8,0x1c,0x46,
0xa3,0x5c,0xe4,0x11,
0xe5,0xfb ,0xc1,0x19,
0x1a,0x0a,0x52,0xef,

0xf6,0x9f,0x24,0x45,
0xdf,0x4f,0x9b,0x17,
0xad ,0x2b,0x41,0x7b,
0xe6,0x6c,0x37,0x10,0};

printf(AES ALGORITHM FOR 128 bit CBC MODE\\\
);
cipher_type = EVP_aes_128_cbc();
AES_BLOCK_SIZE = 128;
passkey = key;
passiv = iv;
plain = input;

printf(iv =); (i = 0; i< sizeof iv; i ++){
printf(%02x,iv [i]);

}
printf(\\\
);
printf(key =); (i = 0; i< sizeof key; i ++){
printf(%02x,key [i]);

}
printf(\\\
);

printf(初始化AES算法为CBC MODE..\\\
);

EVP_EncryptInit_ex(& en,cipher_type,NULL,passkey,passiv);

EVP_DecryptInit_ex(& de,cipher_type,NULL,passkey,passiv);

olen = len = strlen(input)+1;
printf(len value before aes_encrypt \%d \\\\
,len);

int c_len = len + AES_BLOCK_SIZE - 1;
int f_len = 0;
ciphertext =(unsigned char *)malloc(c_len);

if(!EVP_EncryptInit_ex(& en,NULL,NULL,NULL,NULL)){
printf(EVP_EncryptInit_ex \\\
中的ERROR);
返回NULL;
}

if(!EVP_EncryptUpdate(& en,ciphertext,& c_len,plain,len)){
printf(EVP_EncryptUpdate \\\
中的ERROR)
返回NULL;
}
printf(更新后的密文的strlen值\%d\\\\
,strlen(ciphertext));
if(!EVP_EncryptFinal_ex(& en,ciphertext + c_len,& f_len)){
printf(EVP_EncryptFinal_ex \\\
中的ERROR);
返回NULL;
}
printf(最终\%d\\\\
之后的密文的strlen值,strlen(ciphertext));
EVP_CIPHER_CTX_cleanup(& en);

len = c_len + f_len;
printf(len value after aes_encrypt \%d\\\\
,len);

len = strlen(ciphertext);

printf(strlen value of ciphertext after aes_encrypt \%d \\\\
,len);

int p_len = len;
f_len = 0;
plaintext =(unsigned char *)malloc(p_len);
// memset(plaintext,0,sizeof(plaintext));
if(!EVP_DecryptInit_ex(& de,NULL,NULL,NULL,NULL)){
printf(EVP_DecryptInit_ex \\\
中的ERROR);
返回NULL;
}
EVP_CIPHER_CTX_set_padding(& de,0);

if(!EVP_DecryptUpdate(& de,plaintext,& p_len,ciphertext,len)){
printf(EVP_DecryptUpdate\\\
中的ERROR)
返回NULL;
}

if(!EVP_DecryptFinal_ex(& de,plaintext + p_len,& f_len)){
printf(EVP_DecryptFinal_ex\\\
中的ERROR)
返回NULL;
}
EVP_CIPHER_CTX_cleanup(& de);
len = p_len + f_len;
printf(解密值=%s\\\
,明文);

printf(len value after aes_decrypt \%d \\\\
,len);


if(strncmp(plaintext,input,olen))
printf(FAIL:enc / dec failed for \%s\\\\
输入);
else
printf(OK:enc / dec ok for \%s\\\\
,plaintext); // \%s\\\\


printf(OK:ciphertext is \%s\\\\
,ciphertext); // \%s\\\\

printf(\\\
);

unsigned char * s3 = ciphertext;
printf(s3 = \\\
);
int nc = 0;
while(* s3!='\0'){
printf(%02x,* s3);
s3 ++;
nc ++;
if(nc == 16){
printf(\\\
);
nc = 0;
}

}
printf(\\\
);
// printf(nc =%d\\\
,nc);
free(ciphertext);
免费(明文);

return 0;
}


解决方案

就像你需要匹配密钥和IV当您加密和解密时,您还需要匹配填充设置。 NIST测试没有填充。以下是OpenSSL 文档的摘录/ a>:


EVP_DecryptInit_ex(),
EVP_DecryptUpdate()和
EVP_DecryptFinal_ex()是
对应的解密操作。
EVP_DecryptFinal()将返回
错误代码,如果填充已启用,
最终块不正确
格式化
。参数和
限制与
加密操作相同,只是如果
padding启用解密数据
缓冲区传递给
EVP_DecryptUpdate()应该有
足够的空间(inl +
cipher_block_size)字节,除非
密码块大小为1,在这种情况下
inl字节就足够了。


搜索相同页面的padding,您会看到函数 EVP_CIPHER_CTX_set_padding


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


所以在您调用 EVP_CIPHER_CTX_init 之后的某个时间点,然后开始解密你需要这样做:

  EVP_CIPHER_CTX_set_padding(& de,0); 


I am playing around with OpenSSL EVP routines for decryption using AES 128 cbc mode.

I use the test vectors specified at the NIST site to test my program.

The program seems to fail at EVP_DecryptFinal_ex routine.

Can anybody please tell me what is the problem?

Also how do I do the error checking here to find out why this routine fails?

UPDATED:

Please check the code below. I have added the encrypt and decrypt part. Encrypt works. But during the decryption, although the results of both match, the hexvalue of the cipher seems 80 bytes as opposed to the expected 64 bytes(mentioned in NIST) although the decryption works and the decrypted text matches the plaintext! Can somebody clarify?

The expected ciphertext value should be:

cipher: 0000 76 49 ab ac 81 19 b2 46 ce e9 8e 9b 12 e9 19 7d 
    0010 50 86 cb 9b 50 72 19 ee 95 db 11 3a 91 76 78 b2 
    0020 73 be d6 b8 e3 c1 74 3b 71 16 e6 9e 22 22 95 16 
    0030 3f f1 ca a1 68 1f ac 09 12 0e ca 30 75 86 e1 a7

here is the code:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>

int AES_BLOCK_SIZE;

int main(int argc, char **argv)
{

    EVP_CIPHER_CTX en;
    EVP_CIPHER_CTX de;
    EVP_CIPHER_CTX_init(&en);
    EVP_CIPHER_CTX_init(&de);
    const EVP_CIPHER *cipher_type;
    unsigned char *mode;
    unsigned char *passkey, *passiv, *plaintxt;
    int vector_len = 0;
    char *plain;
    char *plaintext;
    unsigned char *ciphertext;
    int olen, len;
    int i =0;

    //NIST VALUES TO CHECK

    unsigned char iv[]  =
    {   0x00, 0x01, 0x02, 0x03,
        0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b,
        0x0c, 0x0d, 0x0e, 0x0f,  0 };

    unsigned char key[] =
    {   0x2b, 0x7e, 0x15, 0x16,
        0x28, 0xae, 0xd2, 0xa6,
        0xab, 0xf7, 0x15, 0x88,
        0x09, 0xcf, 0x4f, 0x3c , 0 };

    unsigned char input[] =
    {   0x6b, 0xc1, 0xbe, 0xe2,
        0x2e, 0x40, 0x9f, 0x96,
        0xe9, 0x3d, 0x7e, 0x11,
        0x73, 0x93, 0x17, 0x2a,

        0xae, 0x2d, 0x8a, 0x57,
        0x1e, 0x03, 0xac, 0x9c,
        0x9e, 0xb7, 0x6f, 0xac,
        0x45, 0xaf, 0x8e, 0x51,

        0x30, 0xc8, 0x1c, 0x46,
        0xa3, 0x5c, 0xe4, 0x11,
        0xe5, 0xfb, 0xc1, 0x19,
        0x1a, 0x0a, 0x52, 0xef,

        0xf6, 0x9f, 0x24, 0x45,
        0xdf, 0x4f, 0x9b, 0x17,
        0xad, 0x2b, 0x41, 0x7b,
        0xe6, 0x6c, 0x37, 0x10, 0 };

    printf("AES ALGORITHM FOR 128 bit CBC MODE\n");
    cipher_type = EVP_aes_128_cbc();
    AES_BLOCK_SIZE = 128;
    passkey = key;
    passiv = iv;
    plain = input;

    printf("iv=");
    for(i = 0; i < sizeof iv; i++){
        printf("%02x", iv[i]);
    }
    printf("\n");
    printf("key=");
    for(i = 0; i < sizeof key; i++){
        printf("%02x", key[i]);
    }
    printf("\n");

    printf("Initializing AES ALGORITHM FOR CBC MODE..\n");

    EVP_EncryptInit_ex(&en, cipher_type, NULL, passkey, passiv);

    EVP_DecryptInit_ex(&de, cipher_type, NULL, passkey, passiv);

    olen = len = strlen(input)+1;
    printf("len value before aes_encrypt \"%d\"\n", len);

    int c_len = len + AES_BLOCK_SIZE - 1;
    int f_len = 0;
    ciphertext = (unsigned char *)malloc(c_len);

    if(!EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL)){
        printf("ERROR in EVP_EncryptInit_ex \n");
        return NULL;
    }

    if(!EVP_EncryptUpdate(&en, ciphertext, &c_len, plain, len)){
        printf("ERROR in EVP_EncryptUpdate \n");
        return NULL;
    }
    printf("strlen value of ciphertext after update \"%d\"\n", strlen(ciphertext));
    if(!EVP_EncryptFinal_ex(&en, ciphertext+c_len, &f_len)){
        printf("ERROR in EVP_EncryptFinal_ex \n");
        return NULL;
    }
    printf("strlen value of ciphertext after final \"%d\"\n", strlen(ciphertext));
    EVP_CIPHER_CTX_cleanup(&en);

    len = c_len + f_len;
    printf("len value after aes_encrypt \"%d\"\n", len);

    len = strlen(ciphertext);

    printf("strlen value of ciphertext after aes_encrypt \"%d\"\n", len);

    int p_len = len;
    f_len = 0;
    plaintext = (unsigned char *)malloc(p_len);
    //memset(plaintext,0,sizeof(plaintext));
    if(!EVP_DecryptInit_ex(&de, NULL, NULL, NULL, NULL)){
        printf("ERROR in EVP_DecryptInit_ex \n");
        return NULL;
    }
    EVP_CIPHER_CTX_set_padding(&de, 0);

    if(!EVP_DecryptUpdate(&de, plaintext, &p_len, ciphertext, len)){
        printf("ERROR in EVP_DecryptUpdate\n");
        return NULL;
    }

    if(!EVP_DecryptFinal_ex(&de, plaintext+p_len, &f_len)){
        printf("ERROR in EVP_DecryptFinal_ex\n");
        return NULL;
    }
    EVP_CIPHER_CTX_cleanup(&de);
    len = p_len + f_len;
    printf("Decrypted value = %s\n", plaintext);

    printf("len value after aes_decrypt \"%d\"\n", len);


    if (strncmp(plaintext, input, olen))
        printf("FAIL: enc/dec failed for \"%s\"\n", input);
    else
        printf("OK: enc/dec ok for \"%s\"\n", plaintext); // \"%s\"\n

    printf("OK: ciphertext is \"%s\"\n", ciphertext); // \"%s\"\n
    printf("\n");

    unsigned char *s3 = ciphertext;
    printf("s3 =\n");
    int nc = 0;
    while(*s3 != '\0'){
        printf("%02x", *s3);
        s3++;
        nc ++;
        if(nc == 16){
            printf("\n");
            nc = 0;
        }

    }
    printf("\n");
    //printf("nc = %d\n", nc);
    free(ciphertext);
    free(plaintext);

    return 0;
}

解决方案

Just like you need to match the key and IV when you encrypt and decrypt, you also need to match the padding setting. The NIST tests are not padded. Here's an excerpt from the OpenSSL documentation:

EVP_DecryptInit_ex(), EVP_DecryptUpdate() and EVP_DecryptFinal_ex() are the corresponding decryption operations. EVP_DecryptFinal() will return an error code if padding is enabled and the final block is not correctly formatted. The parameters and restrictions are identical to the encryption operations except that if padding is enabled the decrypted data buffer out passed to EVP_DecryptUpdate() should have sufficient room for (inl + cipher_block_size) bytes unless the cipher block size is 1 in which case inl bytes is sufficient.

Searching that same page for "padding", you'll see the function EVP_CIPHER_CTX_set_padding:

EVP_CIPHER_CTX_set_padding() enables or disables padding. By default encryption operations are padded using standard block padding and the padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur.

So at some point after you call EVP_CIPHER_CTX_init and before you start decrypting, you need to do this:

EVP_CIPHER_CTX_set_padding(&de, 0);

这篇关于OpenSSL上的EVP_DecryptFinal_ex错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆