Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
AES_cbc_加密中的Segfault_C_Linux_Openssl_Segmentation Fault - Fatal编程技术网

AES_cbc_加密中的Segfault

AES_cbc_加密中的Segfault,c,linux,openssl,segmentation-fault,C,Linux,Openssl,Segmentation Fault,我试图更详细地理解OpenSSL库。因此,我没有使用高级EVP函数集,而是尝试使用AES_*函数。按照中的常规调用集(尽管我使用的是CBC而不是计数器模式),我产生了以下代码: void ctr(log_t* log) { unsigned char ivec[16]; /* Out buffer for ciphertext */ unsigned char outBuf[16]; blockReader_t* br = blockReaderInit(log, ".

我试图更详细地理解OpenSSL库。因此,我没有使用高级EVP函数集,而是尝试使用AES_*函数。按照中的常规调用集(尽管我使用的是CBC而不是计数器模式),我产生了以下代码:

void ctr(log_t* log)
{
   unsigned char ivec[16];
   /* Out buffer for ciphertext */
   unsigned char outBuf[16];

   blockReader_t* br = blockReaderInit(log, "./input.txt", 128);
   int outFD;

   if ((outFD = open("out.bin", O_WRONLY)) == -1)
   {
      logPrint(br->log, LOG_ARGS, LOG_ERR, "open: %s", strerror(errno));
      logExit(br->log, LOG_ARGS, EXIT_FAILURE);
   }

   memset(ivec, 0, 16);

   unsigned char* ivec2 = ivec + 8;
   unsigned long* ivec3 = (unsigned long*) ivec2;
   *ivec3 = (unsigned long) 0xfd0;

   AES_KEY aesKey;
   char* myKey = "Pampers baby-dry";
   int res;

   if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
   {
      logPrint(log, LOG_ARGS, LOG_ERR, "AES_set_encrypt_key: returned %d", res);
      logExit(log, LOG_ARGS, EXIT_FAILURE);
   }

   unsigned char* buf;

   while ((buf = blockReaderGet(br)) != NULL)
   {
      logPrint(log, LOG_ARGS, LOG_INFO, "ivec =");
      logHexdump(log, LOG_ARGS, LOG_INFO, (char*) ivec, 16);

      logPrint(log, LOG_ARGS, LOG_INFO, "buf =");
      logHexdump(log, LOG_ARGS, LOG_INFO, (char*) buf, 16);

      AES_cbc_encrypt(buf, outBuf, 16, &aesKey, ivec, 1);

      logPrint(log, LOG_ARGS, LOG_INFO, "outBuf =");
      logHexdump(log, LOG_ARGS, LOG_INFO, (char*) outBuf, 16);

      int res = write(outFD, outBuf, 16);

      if (res == -1)
      {
         logPrint(log, LOG_ARGS, LOG_ERR, "write: %s", strerror(errno));
         logExit(log, LOG_ARGS, EXIT_FAILURE);
      }
      else if (res < 16)
      {
         logPrint(log, LOG_ARGS, LOG_WARN, "Unexpectedly wrote < 16 bytes");
      }
   }

   if ((close(outFD)) == -1)
   {
      logPrint(log, LOG_ARGS, LOG_ERR, "close: %s", strerror(errno));
      logExit(log, LOG_ARGS, EXIT_FAILURE);
   }
}
输出(在GDB中运行):


编辑2:

CFLAG已更改:

CFLAG= -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -m64 -DL_ENDIAN -O0 -ggdb -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
注意
-O0-ggdb
。回溯是相同的:

(gdb) bt
#0  _x86_64_AES_encrypt_compact () at aes-x86_64.s:170
#1  0x0000000000402b6b in AES_cbc_encrypt () at aes-x86_64.s:1614
#2  0x00007fffffffe0a0 in ?? ()
#3  0x000080007dfc19a0 in ?? ()
#4  0x00007fffffffe050 in ?? ()
#5  0x0000000000635080 in ?? ()
#6  0x00007fffffffe1a0 in ?? ()
#7  0x0000000000000010 in ?? ()
#8  0x00007ffff7bdf9a0 in ?? ()
#9  0x00007fffffffe1b0 in ?? ()
#10 0x00007fff00000001 in ?? ()
#11 0x00007ffff7bdf4c8 in ?? ()
#12 0x00007fffffffda40 in ?? ()
#13 0x0000000000000000 in ?? ()

编辑:MCVE示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/aes.h>

unsigned char input[] = {0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
                         0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
                         0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
                         0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};

int main()
{
   unsigned char ivec[16];
   /* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
   unsigned char outBuf[16];

   int outFD;

   if ((outFD = open("out.bin", O_WRONLY)) == -1)
   {
      perror("open");
      return EXIT_FAILURE;
   }

   memset(ivec, 0, 16);

   unsigned char* ivec2 = ivec + 8;
   unsigned long* ivec3 = (unsigned long*) ivec2;
   *ivec3 = (unsigned long) 0xfd0;

   AES_KEY aesKey;
   char* myKey = "Pampers baby-dry";
   int res;

   if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
   {
      fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
      return EXIT_FAILURE;
   }

   for (int i = 0; i < 32; i += 16)
   {
      printf("ivec = ");

      for (int j = 0; j < 16; j++)
         printf("%.02hhx ", ivec[j]);

      putchar('\n');

      printf("input = ");

      for (int j = i; j < (i + 16); j++)
         printf("%.02hhx ", input[j]);

      putchar('\n');

      AES_cbc_encrypt(&input[i], outBuf, 16, &aesKey, ivec, 1);

      printf("outBuf = ");

      for (int j = 0; j < 16; j++)
         printf("%.02hhx ", outBuf[j]);

      putchar('\n');

      int res = write(outFD, outBuf, 16);

      if (res == -1)
      {
         perror("write");
         return EXIT_FAILURE;
      }
      else if (res < 16)
      {
         printf("Warning: unexpectedly wrote < 16 bytes");
      }
   }

   if ((close(outFD)) == -1)
   {
      perror("close");
      return EXIT_FAILURE;
   }

   return EXIT_SUCCESS;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
无符号字符输入[]={0x4du,0x69u,0x64u,0x6eu,0x69u,0x67u,0x68u,0x74u,
0x5fu、0x4du、0x61u、0x72u、0x6cu、0x69u、0x6eu、0x05u、,
0x52u、0x69u、0x63u、0x68u、0x61u、0x72u、0x64u、0x52u、,
0x69u、0x63u、0x68u、0x61u、0x72u、0x64u、0x06u、0x07u};
int main()
{
无符号字符ivec[16];
/*ivec[0..7]是IV,ivec[8..15]是big endian计数器*/
无符号字符f[16];
国际输出;
如果((outpd=open(“out.bin”,O_WRONLY))=-1)
{
佩罗(“公开”);
返回退出失败;
}
memset(ivec,0,16);
无符号字符*ivec2=ivec+8;
无符号长*ivec3=(无符号长*)ivec2;
*ivec3=(无符号长)0xfd0;
AES_键aesKey;
char*myKey=“帮宝适婴儿干粮”;
国际关系;
如果(!(res=AES\u set\u encrypt\u key((unsigned char*)myKey,16,&aesKey)))
{
fprintf(stderr,“AES设置加密密钥:返回%d”,res);
返回退出失败;
}
对于(int i=0;i<32;i+=16)
{
printf(“ivec=”);
对于(int j=0;j<16;j++)
printf(“%.02hhx”,ivec[j]);
putchar('\n');
printf(“input=”);
对于(int j=i;j<(i+16);j++)
printf(“%.02hhx”,输入[j]);
putchar('\n');
AES_cbc_encrypt(和输入[i],EXPUFF,16和aesKey,ivec,1);
printf(“exputf=”);
对于(int j=0;j<16;j++)
printf(“%.02hhx”,f[j]);
putchar('\n');
int res=写入(outpd,exputf,16);
如果(res==-1)
{
佩罗(“书面”);
返回退出失败;
}
否则如果(res<16)
{
printf(“警告:意外写入<16字节”);
}
}
如果((关闭(输出))=-1)
{
perror(“关闭”);
返回退出失败;
}
返回退出成功;
}

所以这里有几个主要的bug。我将检查我捕获的所有代码,但可能还有更多,因为我没有进行彻底的代码检查

  • 您在任何地方都使用sentinel值(即
    16
    整数文本。使用预处理器宏或更好的
    const int
    替换它们)
  • 输出缓冲区需要至少与输入缓冲区一样大,并且应该向上舍入到块大小的最近倍数,再加上一个块
  • 您正在循环输入数据的每个元素,并试图一次加密一个字节。除非您在AES之上实现一些模糊的层,否则这是错误的。迭代数据块,而不是单个字节。循环是完全不必要的
  • 输入数据缓冲区似乎大于输出数据缓冲区。在当前实现中,我认为最后16个字节将被截断/丢失,因为输入缓冲区有32个字节的数据,而输出缓冲区是
    16
    字节。在您的特定示例中,输入应为
    32
    字节,输出应为
    32+1
  • 除了循环是不必要的之外,经过一些修改,它将运行(错误,损坏数据),并最终访问无效内存(即:指向输入缓冲区的末尾,并告诉加密函数在该点之后请求16字节的数据)
  • 我提供了一个更新的代码列表和示例输出,应该可以让您走上正确的轨道

    祝你好运

    修改的代码清单

    样本输出

    崩溃发生后,当您在GDB中发出
    bt
    (back/stack trace)命令时会发生什么情况?@Dogbert更新的问题尝试通过
    -O0-ggdb
    编译您的应用程序和OpenSSL以禁用优化、启用调试等@Dogbert Done,尽管它似乎没有任何影响。嗯,没有更多的堆栈转储信息,除非有更了解代码的人可以评论,否则我们有点盲目。你能在这里或在pastebin上发布一个完整的最小工作示例吗。我可以在本地构建和测试它。为什么输出缓冲区需要比输入缓冲区大一个字节?这是特定于实现的还是仅仅是AES?还有,第4点,为什么我要迭代每个字节?for循环使用16的增量索引
    输入
    ,并将其传递给encrypt函数。这就是为什么输出缓冲区是16字节,只是为了测试加密一行中的两个输入,以及为什么16字节是硬编码的。它不是一个功能程序,只是一个测试。感谢您为我进行测试。更正:输出被四舍五入到块大小的最近倍数。我的
    +1
    不正确,没有必要。我明白你现在的意思,增量大小为
    16
    。看起来很奇怪,你实际上是在销毁第一组加密数据。即使这不是一个生产计划,你也应该养成一贯的风格指导和最佳实践的习惯。这会让生活更轻松。如果这充分回答了你的问题,请考虑把这个问题标记为“接受”,通过复选标记。
    CFLAG= -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -m64 -DL_ENDIAN -O0 -ggdb -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
    
    (gdb) bt
    #0  _x86_64_AES_encrypt_compact () at aes-x86_64.s:170
    #1  0x0000000000402b6b in AES_cbc_encrypt () at aes-x86_64.s:1614
    #2  0x00007fffffffe0a0 in ?? ()
    #3  0x000080007dfc19a0 in ?? ()
    #4  0x00007fffffffe050 in ?? ()
    #5  0x0000000000635080 in ?? ()
    #6  0x00007fffffffe1a0 in ?? ()
    #7  0x0000000000000010 in ?? ()
    #8  0x00007ffff7bdf9a0 in ?? ()
    #9  0x00007fffffffe1b0 in ?? ()
    #10 0x00007fff00000001 in ?? ()
    #11 0x00007ffff7bdf4c8 in ?? ()
    #12 0x00007fffffffda40 in ?? ()
    #13 0x0000000000000000 in ?? ()
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <openssl/aes.h>
    
    unsigned char input[] = {0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
                             0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
                             0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
                             0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};
    
    int main()
    {
       unsigned char ivec[16];
       /* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
       unsigned char outBuf[16];
    
       int outFD;
    
       if ((outFD = open("out.bin", O_WRONLY)) == -1)
       {
          perror("open");
          return EXIT_FAILURE;
       }
    
       memset(ivec, 0, 16);
    
       unsigned char* ivec2 = ivec + 8;
       unsigned long* ivec3 = (unsigned long*) ivec2;
       *ivec3 = (unsigned long) 0xfd0;
    
       AES_KEY aesKey;
       char* myKey = "Pampers baby-dry";
       int res;
    
       if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
       {
          fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
          return EXIT_FAILURE;
       }
    
       for (int i = 0; i < 32; i += 16)
       {
          printf("ivec = ");
    
          for (int j = 0; j < 16; j++)
             printf("%.02hhx ", ivec[j]);
    
          putchar('\n');
    
          printf("input = ");
    
          for (int j = i; j < (i + 16); j++)
             printf("%.02hhx ", input[j]);
    
          putchar('\n');
    
          AES_cbc_encrypt(&input[i], outBuf, 16, &aesKey, ivec, 1);
    
          printf("outBuf = ");
    
          for (int j = 0; j < 16; j++)
             printf("%.02hhx ", outBuf[j]);
    
          putchar('\n');
    
          int res = write(outFD, outBuf, 16);
    
          if (res == -1)
          {
             perror("write");
             return EXIT_FAILURE;
          }
          else if (res < 16)
          {
             printf("Warning: unexpectedly wrote < 16 bytes");
          }
       }
    
       if ((close(outFD)) == -1)
       {
          perror("close");
          return EXIT_FAILURE;
       }
    
       return EXIT_SUCCESS;
    }
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <openssl/aes.h>
    
    #define BLOCK_SIZE  (128)
    
    unsigned char input[BLOCK_SIZE] = {
        0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
        0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
        0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
        0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};
    
    int main()
    {
        unsigned char ivec[BLOCK_SIZE];
        /* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
        unsigned char outBuf[BLOCK_SIZE+1];
    
        int outFD;
    
        if ((outFD = open("out.bin", O_CREAT | O_RDWR)) == -1)
        {
            perror("open");
            return EXIT_FAILURE;
        }
    
        memset(ivec, 0, BLOCK_SIZE);
    
        unsigned char* ivec2 = ivec + 8;
        unsigned long* ivec3 = (unsigned long*) ivec2;
        *ivec3 = (unsigned long) 0xfd0;
    
        AES_KEY aesKey;
        char* myKey = "Pampers baby-dry";
        int res;
    
        if ((res = AES_set_encrypt_key((unsigned char*) myKey, BLOCK_SIZE, &aesKey)) < 0)
        {
            fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
            return EXIT_FAILURE;
        }
    
        int i = 0;
        //for (int i = 0; i < 32; i += BLOCK_SIZE)
        {
            printf("ivec = ");
    
            for (int j = 0; j < BLOCK_SIZE; j++)
                printf("%.02hhx ", ivec[j]);
    
            putchar('\n');
    
            printf("input = ");
    
            for (int j = i; j < (i + BLOCK_SIZE); j++)
                printf("%.02hhx ", input[j]);
    
            putchar('\n');
            putchar('\n');
            putchar('\n');
            putchar('\n');
    
            AES_cbc_encrypt(input, outBuf, BLOCK_SIZE, &aesKey, ivec, AES_ENCRYPT);
    
            printf("outBuf = ");
    
            for (int j = 0; j < BLOCK_SIZE; j++)
                printf("%.02hhx ", outBuf[j]);
    
            putchar('\n');
    
            int res = write(outFD, outBuf, BLOCK_SIZE);
    
            if (res == -1)
            {
                perror("write");
                return EXIT_FAILURE;
            }
            else if (res < BLOCK_SIZE)
            {
                printf("Warning: unexpectedly wrote < %d bytes.\n", BLOCK_SIZE);
            }
        }
    
        if ((close(outFD)) == -1)
        {
            perror("close");
            return EXIT_FAILURE;
        }
    
        return EXIT_SUCCESS;
    }
    
    gcc -O0 -ggdb test.c --std=c99 -lssl -lcrypto && ./a.out 
    
    ivec = 00 00 00 00 00 00 00 00 d0 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
    input = 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 52 69 63 68 61 72 64 52 69 63 68 61 72 64 06 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
    
    
    
    outBuf = 81 ee 91 c0 9f f6 40 db 3c 6d 32 dd 5e 86 6f f8 4e 7b aa 15 38 36 b8 20 bc 04 bd 4f 6c 53 0e 02 72 c2 b7 e8 79 35 f2 b2 e1 c1 6e 1e 3b 1e 75 81 6a 56 43 d8 9d 9c 4c 1e 04 bd 99 29 3a 55 c9 a4 90 48 20 13 5e 51 4a 0c 4b 35 bc db da 54 f1 2b 66 f6 1b 1a 42 25 33 30 0e 35 87 9d 4b 1f d5 3a 5d 3a 8e 8c c8 48 c0 52 72 c0 4e b3 b8 f5 37 03 1c 87 15 61 3b 64 2b 06 5e 12 8f c7 b5 21 98 06