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

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

问题描述

我玩弄OpenSSL的EVP程序使用AES 128 CBC模式解密。

我用在NIST网站指定的测试向量来测试我的节目。

该计划似乎在EVP_DecryptFinal_ex常规失败。

谁能告诉我是什么问题?

另外我怎么做错误检查此处,了解为什么这个例程失败?

更新:

请检查下面的code。我已经添加了加密和解密的部分。加密工程。但该解密过程中,虽然两者的比赛的结果,密码的hexvalue似乎相对于预期64个字节(在NIST提及)虽然解密作品和解密文明文匹配80字节!
有人可以澄清?

预期的密文值应为:

 密码:0000 76 49 AB AC 81 19 46 B2 E9 CE 8E 9B 12 E9 19 7D
    0010 50 86 CB 9B 50 72 19 EE95分贝11 3A 91 76 78 B2
    0020 73是D6 B8 E3 C1 74 3B 71 16 E6 9E 22 22 95 16
    0030 3F F1 CA A1 68 1F交流09 12 0E 30 CA 75 86 E1 A7

这里是code:

 的#include<&string.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;的OpenSSL / evp.h>INT AES_BLOCK_SIZE;INT主(INT ARGC,字符** argv的)
{    EVP_C​​IPHER_CTX连接;
    EVP_C​​IPHER_CTX德;
    EVP_C​​IPHER_CTX_init(安培;连接);
    EVP_C​​IPHER_CTX_init(安培;去);
    常量EVP_C​​IPHER * cipher_type;
    无符号字符*模式;
    无符号字符*密钥,* passiv,* plaintxt;
    INT vector_len = 0;
    字符*平原;
    字符*明文;
    无符号字符*密文;
    奥伦诠释,LEN;
    INT I = 0;    // NIST要检查的值    unsigned char型IV [] =
    {0×00,0×01,0×02,×03,
        0×04,0×05,0×06,0×07,
        0×08,×09,的0x0A,0x0B中,
        的0x0C,符进行,为0x0E,为0x0F,0};    无符号的字符键[] =
    {0x2B访问,0x7e格式,为0x15,0x16,
        0x28,0xae,0xd2,0xa6,
        是0xAB,0xf7,为0x15,均为0x88,
        为0x09,0xcf,0x4f,为0x3C,0};    无符号的字符输入[] =
    {0x6b,0xc1,0xbe,0xe2,
        0x2E之间,0X40,0x9f,0x96,
        0xe9,0x3D之间,0x7e格式,为0x11,
        0x73,0x93,0x17已,0x2a,        0xae,0x2d,0x8a,0×57,
        0X1E,×03,0xac,为0x9c,
        0x9e,0xb7,0x6f,0xac,
        ×45,0XAF,为0x8E,0x51,        为0x30,0xc8,为0x1C,0×46,
        0xA3执行,0x5c,0xe4,为0x11,
        为0xE5,0xFB的才能,0xc1,的0x19,
        0X1A,0x0A的,0×52,0xef,        0xf6,0x9f,0X24,×45,
        0xdf,0x4f,0x9b,0x17已,
        写入0xAD,0x2B访问,×41,0x7b,
        0xe6,0x6c,0x37符号,为0x10,0};    的printf(AES算法的128位CBC模式\\ n);
    cipher_type = EVP_aes_128_cbc();
    AES_BLOCK_SIZE = 128;
    密钥=键;
    passiv = IV;
    纯=输入;    的printf(IV =);
    对于(i = 0; I<第四sizeof的;我++){
        的printf(%02X,IV [I]);
    }
    的printf(\\ n);
    的printf(键=);
    对于(i = 0; I< sizeof的关键;我++){
        的printf(%02X键[I]);
    }
    的printf(\\ n);    的printf(初始化AES算法CBC模式.. \\ n);    EVP_EncryptInit_ex(安培;恩,cipher_type,NULL,密钥,passiv);    EVP_DecryptInit_ex(安培;德,cipher_type,NULL,密钥,passiv);    奥伦= LEN = strlen的(输入)+1;
    的printf(LEN前值AES_ENCRYPT \\%d个\\\\ n,LEN);    INT c_len = LEN + AES_BLOCK_SIZE - 1;
    INT f_len = 0;
    密文=(无符号字符*)malloc的(c_len);    如果(EVP_EncryptInit_ex(安培;!烯,NULL,NULL,NULL,NULL)){
        的printf(ERROR在EVP_EncryptInit_ex \\ n);
        返回NULL;
    }    如果(EVP_EncryptUpdate(安培;!恩,密文,和放大器; c_len,平原,LEN)){
        的printf(ERROR在EVP_EncryptUpdate \\ n);
        返回NULL;
    }
    的printf(%d个\\\\ n更新后\\密文strlen的价值,strlen的(密文));
    如果(EVP_EncryptFinal_ex(安培;!恩,密文+ c_len,&安培; f_len)){
        的printf(ERROR在EVP_EncryptFinal_ex \\ n);
        返回NULL;
    }
    的printf(%d个\\\\ n后的最终\\密文strlen的价值,strlen的(密文));
    EVP_C​​IPHER_CTX_cleanup(安培;连接);    LEN = c_len + f_len;
    的printf(LEN值后AES_ENCRYPT \\%d个\\\\ n,LEN);    LEN = strlen的(密文);    的printf(%d个\\\\ n,LEN后AES_ENCRYPT \\密文strlen的值);    INT p_len = LEN;
    f_len = 0;
    明文=(无符号字符*)malloc的(p_len);
    // memset的(明文,0,sizeof的(明文));
    如果(EVP_DecryptInit_ex(安培;!德,NULL,NULL,NULL,NULL)){
        的printf(ERROR在EVP_DecryptInit_ex \\ n);
        返回NULL;
    }
    EVP_C​​IPHER_CTX_set_padding(安培;德,0);    如果(EVP_DecryptUpdate(安培;!德,明文,&安培; p_len,密文,LEN)){
        的printf(ERROR在EVP_DecryptUpdate \\ n);
        返回NULL;
    }    如果(EVP_DecryptFinal_ex(安培;!德,明文+ p_len,&安培; f_len)){
        的printf(ERROR在EVP_DecryptFinal_ex \\ n);
        返回NULL;
    }
    EVP_C​​IPHER_CTX_cleanup(安培;去);
    LEN = p_len + f_len;
    的printf(解密值=%s的\\ n,明文);    的printf(LEN值后AES_DECRYPT \\%d个\\\\ n,LEN);
    如果(STRNCMP(明文输入,奥伦))
        的printf(FAIL:ENC / DEC失败\\%s \\的\\ n,输入);
    其他
        的printf(OK:ENC / DEC确定为\\%s \\的\\ n,明文); // \\%s \\的\\ n    的printf(OK:密文\\%s \\的\\ n,密文); // \\%s \\的\\ n
    的printf(\\ n);    无符号字符* S3 =密文;
    的printf(S3 = \\ n);
    INT NC = 0;
    而(* S3!='\\ 0'){
        的printf(%02X,* S3);
        S3 ++;
        NC ++;
        如果(NC == 16){
            的printf(\\ n);
            NC = 0;
        }    }
    的printf(\\ n);
    //输出(NC =%d个\\ N,NC);
    免费(密文);
    免费(明文);    返回0;
}


解决方案

就像你需要匹配的钥匙,当你加密和解密,还需要匹配填充设置IV。 NIST的测试不填充。下面是来自OpenSSL的<一个摘录href=\"http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/EVP_DecryptInit_ex.3ssl.html\"相对=nofollow>文档:


  

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


搜索,对于填充同一个页面,你会看到函数 EVP_C​​IPHER_CTX_set_padding


  

EVP_C​​IPHER_CTX_set_padding()使
  或禁用填充。默认
  加密操作使用填充
  标准块填充和填充
  被选中并除去时
  解密。如果垫参数
  零,那么不执行填充的
  加密的数据的总量或
  然后解密的必须的倍数
  块的大小或错误会发生。


因此​​,在某些时候,你打电话后 EVP_C​​IPHER_CTX_init ,你就会开始解密之前,你需要做的:

  EVP_C​​IPHER_CTX_set_padding(安培;德,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天全站免登陆