什么是"长度QUOT; AES EVP_Decrypt的参数? [英] What is the "length" parameter of AES EVP_Decrypt?

查看:157
本文介绍了什么是"长度QUOT; AES EVP_Decrypt的参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是链接到<一个href=\"http://stackoverflow.com/questions/5665698/evp-decryptfinal-ex-error-on-openssl/5669505#5669505\">EVP_DecryptFinal_ex OpenSSL的错误

我试图找出为什么AES解密将无法工作,最终我发现了什么问题,现在找人帮我解决吧:)

I was trying to find out why the AES decrypt won't work and finally I have found what the problem is and now looking for someone to help me solve it :)

下面是我测试过的code(从这里各个岗位):

Here is the code that I tested with(from various posts here):

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

int AES_BLOCK_SIZE = 128;

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 *passkey, *passiv, *plaintxt;
  char *plain;
  char *plaintext;
  unsigned char *ciphertext;
  int olen, len;
  int i =0;

  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 = "hi this is patrick immling\n'Doctor'.\n'Doctor' who ?\nPrecisely! 123910!§$$§% !%%$&$(/=))?=(#ü++Ü**<,.here we go sometimes it i s difficult but 187! 1$5 78@2 14  .TӒ��틪�ձ1z.$�?�U���<y";

    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("key[%d]= %02x\n", i, key[i]);
    }
    printf("\n");
    printf("key=");
      for(i = 0; i < sizeof key; i++){
            printf("%02x", key[i]);
          //printf("key[%d]= %02x\n", i, 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);


      // max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes 
      int c_len = len + AES_BLOCK_SIZE - 1;
      int f_len = 0;
      ciphertext = (unsigned char *)malloc(c_len);

      /* allows reusing of 'e' for multiple encryption cycles */
      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("len value after update \"%d\"\n", len);
     // printf("size of ciphertext after update \"%d\"\n", sizeof(ciphertext));
      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("len value  after final \"%d\"\n", len);
      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);

//HERE IS THE PROBLEM: IF I USE len= strlen(ciphertext) I GET ERROR
    //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;
      }
      printf("len value after decrypt update \"%d\"\n", len);
      if(!EVP_DecryptFinal_ex(&de, plaintext+p_len, &f_len)){
        printf("ERROR in EVP_DecryptFinal_ex\n");
        ERR_print_errors_fp(stderr);
        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("\n");

   free(ciphertext);
   free(plaintext);

  return 0;
}

我不明白:

我应该怎么养活作为OpenSSL的执行副总裁解密程序的LEN参数?
这是什么神奇的len = c_len + f_len?

What should I feed as the "len" parameter for the openSSL EVP Decrypt routines? what is this magic len = c_len+ f_len?

我应该如何得到这个情况下,我只给定的密钥和IV的密码?这应该是总有可能吧?我知道的strlen是一个坏parametr特别是对于二进制作为输入到EVP解密的密文是二进制的:?所以我应该怎么得到这个

How should I get this in case I am given just the cipher with the key and the iv? This should be always possible right? I know strlen is a bad parametr especially for binary as the ciphertext input to EVP Decrypt is binary: so how should I get this?

我已经可以看到,如果我使用LEN = strlen的(密文)给了我一个错误的答案和sizeof参数也没有之一,因为它返回4。

I can already see that if I use len= strlen(ciphertext) gives me a wrong answer and sizeof parameter is also not the one as it returns 4.

标准错误清楚地表明,EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH和我的理解,你都指出,AES数据应该是16字节的块。
所以,我应该改变养活长度?

The stderr shows clearly that the EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH and which I understand as you have all pointed out that the AES data should be 16 byte chunks. So what should I change to feed the length?

推荐答案

首先,不要从主返回NULL()。其次,我固定它并注明它,所以希望你能看到什么长度变量的意思。我想你错过了关键的一点是你给了OpenSSL的功能的缓冲器,可以写入数据。就像拿一个缓冲的功能很多,你给它一个缓冲区大小,并返回到你实际写入缓冲区的字节数。为什么?因为你要知道当你的缓冲区已满,或者如果你填写您的缓冲区递增你必须知道在哪里写数据的下一个块。

First, don't return NULL from main(). Second, I fixed it and annotated it so hopefully you can see what the length variables mean. I think the key point you're missing is that you're giving the OpenSSL functions a buffer where it can write its data. Like many functions that take a buffer, you give it a buffer size and it returns to you the number of bytes it actually wrote into the buffer. Why? Because you have to know when your buffer is full, or if you're filling your buffer incrementally you have to know where to write the next chunk of data.

另外,我觉得你应该阅读有关如何使用二进制数据以及如何它不同于C风格的字符串工作的一些教程。 OpenSSL的EVP功能与二进制数据的工作,这就是为什么你需要告诉每个功能的数据有多少字节的。

Also, I think you should read some tutorials on how to work with binary data and how it differs from a C-style string. The OpenSSL EVP functions work with binary data, which is why you need to tell every function how many bytes your data is.

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

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 *passkey, *passiv, *plaintxt;
  unsigned char *plaintext = NULL;
  unsigned char *ciphertext = NULL;
  int input_len = 0;

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

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

  const char *string_to_encrypt = "hi this is patrick immling\n'Doctor'.\n'Doctor' who ?\nPrecisely! 123910!§$$§% !%%$&$(/=))?=(#ü++Ü**<,.here we go sometimes it i s difficult but 187! 1$5 78@2 14  .TӒ��틪�ձ1z.$�?�U���<y";

    cipher_type = EVP_aes_128_cbc();

    EVP_EncryptInit_ex(&en, cipher_type, NULL, key, iv);
    EVP_DecryptInit_ex(&de, cipher_type, NULL, key, iv);

    // The data we want to encrypt is a string.  So we can just do a simple
    // strlen to calculate its length.  But the encrypted buffer is going to
    // be padded with PKCS padding.  In the worst case, our string is a
    // multiple of the AES block size (16 bytes).  In that case, the PKCS
    // padding will be an additional 16 bytes after our data.  So we could
    // precisely calculate the buffer with this:
    // int input_len = strlen(string_to_encrypt);
    // malloc( input_len + 16 - (input_len % 16) );
    // But why get fancy?  Just add an extra AES block and have at most 16
    // unused bytes at the end, and usually less than that.
    static const int MAX_PADDING_LEN = 16;

    // We add 1 because we're encrypting a string, which has a NULL terminator
    // and want that NULL terminator to be present when we decrypt.
    input_len = strlen(string_to_encrypt) + 1;
    ciphertext = (unsigned char *) malloc(input_len + MAX_PADDING_LEN);

      /* allows reusing of 'e' for multiple encryption cycles */
      if(!EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL)){
        printf("ERROR in EVP_EncryptInit_ex \n");
        return 1;
      }

      // This function works on binary data, not strings.  So we cast our
      // string to an unsigned char * and tell it that the length is the string
      // length + 1 byte for the null terminator.
      int bytes_written = 0;
      int ciphertext_len = 0;
      if(!EVP_EncryptUpdate(&en,
                           ciphertext, &bytes_written,
                           (unsigned char *) string_to_encrypt, input_len) ) {
        printf("ERROR in EVP_EncryptUpdate \n");
        return 1;
      }
      ciphertext_len += bytes_written;

      // Right now the ciphertext buffer contains only the encrypted version
      // of the input data up to the last full AES block.  E.g., if your input
      // size is 206, then ciphertext_len will be 192 because you have 14 bytes
      // left to encrypt and those bytes can't fill a full AES block.  But the
      // encryptor has stored those bytes and is waiting either for more bytes
      // or the call to EVP_EncryptFinal where it will add padding to make the
      // encrypted data the same size as the AES block (i.e., 2 bytes of padding
      // in the above example).
      printf("Input len: %d, ciphertext_len: %d\n", input_len, ciphertext_len);

      // EVP_EncryptFinal_ex writes the padding.  The whole point of the
      // bytes_written variable from EVP_EncryptUpdate is to tell us how much
      // of the buffer is full so we know where we can write the padding.
      // Note that we know our buffer is large enough so we're not bothering to
      // keep track of the buffer size.  We just keep track of how much data is
      // in it.

      if(!EVP_EncryptFinal_ex(&en,
                              ciphertext + bytes_written,
                              &bytes_written)){
        printf("ERROR in EVP_EncryptFinal_ex \n");
        return 1;
      }
      ciphertext_len += bytes_written;

      EVP_CIPHER_CTX_cleanup(&en);

      printf("Input len: %d, ciphertext_len: %d\n", input_len, ciphertext_len);

      // We'll pretend we don't know the input length here.  We do know that
      // the ciphertext length is at most 16 bytes + the input length.  So
      // since the ciphertext is always greater than the input length, we can
      // declare plaintext buffer size = ciphertext buffer size and know that
      // there's no way we'll overflow our plaintext buffer.  It will have at
      // most 16 bytes of wasted space on the end, but that's ok.
      plaintext = (unsigned char *) malloc(ciphertext_len);

      if(!EVP_DecryptInit_ex(&de, NULL, NULL, NULL, NULL)){
        printf("ERROR in EVP_DecryptInit_ex \n");
        return 1;
      }

      // No!  You're encrypting arbitrary data, so you should use padding.  You
      // don't use padding only if you know in advance that you're encrypting
      // data whose length is a multiple of the block size.  Like when running
      // the AES known-answer tests.
      // EVP_CIPHER_CTX_set_padding(&de, 0); /* no! */

      int plaintext_len = 0;
      if(!EVP_DecryptUpdate(&de,
                            plaintext, &bytes_written,
                            ciphertext, ciphertext_len)){
        printf("ERROR in EVP_DecryptUpdate\n");
        return 1;
      }
      plaintext_len += bytes_written;

      // This function verifies the padding and then discards it.  It will
      // return an error if the padding isn't what it expects, which means that
      // the data was malformed or you are decrypting it with the wrong key.
      if(!EVP_DecryptFinal_ex(&de,
                              plaintext + bytes_written, &bytes_written)){
        printf("ERROR in EVP_DecryptFinal_ex\n");
        return 1;
      }
      plaintext_len += bytes_written;

      EVP_CIPHER_CTX_cleanup(&de);

      // We encrypted a string, so we know that we decrypted a string.  So we
      // can just print it.  Note that we know our binary data is a string so
      // we just cast it to a char *.  We could just have easily declared it
      // originally as a char * (I think I changed that from your original
      // program, actually) and then cast it in the call to EVP_DecryptUpdate.
      printf("input_len: %d, ciphertext_len: %d, plaintext_len: %d\n",
          input_len, ciphertext_len, plaintext_len);

      printf("Decrypted value = %s\n", plaintext);
      if( strcmp(string_to_encrypt, (char *) plaintext) == 0 ) {
          printf("Decrypted data matches input data.\n");
      }
      else {
          printf("Decrypted data does not match input data.\n");
      }

   free(ciphertext);
   free(plaintext);

  return 0;
}

这篇关于什么是&QUOT;长度QUOT; AES EVP_Decrypt的参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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