【问题标题】:Assistance with openssl blowfish simple example inserting garbage characters协助openssl河豚插入垃圾字符的简单示例
【发布时间】:2010-11-02 21:18:06
【问题描述】:

如果您有一个使用 openssl 加密文件的好例子,它比我遇到的问题要好,我将不胜感激。

更新:作者是正确的。在我没有分配的东西上使用 memset 让我想起 strtok 在非堆栈变量上窒息。

更新 2: 使用 malloc 停止核心转储。更新了代码。控制 Hs 仍然出现。更新代码以反映这一点。

Update3: 示例中的循环结构不正确。我不确定后续读取如何大于初始读取的大小。

Update4:我想我找到了。解密循环有一个 olen += tlen 并且缓冲区应该丢弃那组位。 :( 不是。

Update99988: 我已经放弃了这里的所有希望。我想我需要扔掉这个例子,而是从 Openssl 书中的一些内容开始。在解密中间层缓冲区时,预先附加了 ^H,但由于传入了一个指针,我开始怀疑对齐问题。

我想我可能会从一个坏例子开始比从头开始更糟糕。我不得不做一些更正(原文在下面的代码中注释)。原作者在错误传递地址时遇到了一些问题。作者使用 1024 和 1032 不同大小的缓冲区让我心烦意乱,但我认为这与 8 位种子和链式加密调用有关。

我在(控制 Hs)中得到了垃圾字符,并且像解密这样的核心转储正在破坏堆栈。我对加密、openssl 还很陌生,而且我对 gdb 也不是很熟悉。

我已尽一切努力简化这一点

  1. gcc --version 报告 4.3.2
  2. 打开 SUSE 11

compile.sh

gcc -g -o blowfish blowfish.c -lcrypto

run.sh

ulimit -c unlimited
./blowfish example.txt encrypted_example decrypted_example
echo diff example.txt decrypted_example
diff example.txt decrypted_example

clean.sh

rm -rf blowfish encrypted_example decrypted_example core

example.txt

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis 
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in 
culpa qui officia deserunt mollit anim id est laborum.

Hydrogen H
Helium H
Lithium L
Beryllium B
Boron B
Carbon C
Nitrogen N
Oxygen O
Fluorine F
Neon N
Sodium N
Magnesium M
Aluminium A
Silicon S
Phosphorus P
Sulfur S
Chlorine C
Argon A
Potassium K
Calcium C
Scandium S
Titanium T
Vanadium V
Chromium C
Manganese M
Iron F
Cobalt C
Nickel N
Copper C
Zinc Z
Gallium G
Germanium G
Arsenic A
Selenium S
Bromine B
Krypton K
Rubidium R
Strontium S
Yttrium Y
Zirconium Z
Niobium N
Molybdenum M
Technetium T
Ruthenium R
Rhodium R
Palladium P
Silver A
Cadmium C
Indium I
Tin S
Antimony S
Tellurium T
Iodine I
Xenon X
Caesium C
Barium B
Lanthanum L
Cerium C
Praseodymium P
Neodymium N
Promethium P
Samarium S
Europium E
Gadolinium G
Terbium T
Dysprosium D
Holmium H
Erbium E
Thulium T
Ytterbium Y
Lutetium L
Hafnium H
Tantalum T
Tungsten W
Rhenium R
Osmium O
Iridium I
Platinum P
Gold A
Mercury H
Thallium T
Lead P
Bismuth B
Polonium P
Astatine A
Radon R
Francium F
Radium R
Actinium A
Thorium T
Protactinium P
Uranium U
Neptunium N
Plutonium P
Americium A
Curium C
Berkelium B
Californium C
Einsteinium E
Fermium F
Mendelevium M
Nobelium N
Lawrencium L
Rutherfordium R
Dubnium D
Seaborgium S
Bohrium B
Hassium H
Meitnerium M
Darmstadtium D
Roentgenium R
Ununbium U
Ununtrium U
Ununquadium U
Ununpentium U
Ununhexium U
Ununseptium U
Ununoctium U

BAD CODE WARNING BAD CODE USE CODE FROM SELECTED ANSWER blowfish.c

#include <openssl/blowfish.h>
#include <openssl/evp.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#define IP_SIZE 1024
#define OP_SIZE 1032
unsigned char key[16];
unsigned char iv[8];

int
generate_key ()
{
  int i, j, fd;
  if ((fd = open ("/dev/random", O_RDONLY)) == -1)
    perror ("open error");

  if ((read (fd, key, 16)) == -1)
    perror ("read key error");

  if ((read (fd, iv, 8)) == -1)
    perror ("read iv error");

  printf ("128 bit key:\n");
  for (i = 0; i < 16; i++)
    printf ("%4d ", key[i]);

  printf ("\nInitialization vector\n");
  for (i = 0; i < 8; i++)
    printf ("%4d ", iv[i]);
  printf ("\n");


  close (fd);
  return 0;
}

int
decrypt (int infd, int outfd)
{
  char *inbuff, *outbuf;
  int olen, tlen, n;
  EVP_CIPHER_CTX ctx;
  EVP_CIPHER_CTX_init (&ctx);
  EVP_DecryptInit (&ctx, EVP_bf_cbc (), key, iv);

  outbuf = (unsigned char *) malloc ( sizeof(unsigned char) * IP_SIZE );
  inbuff = (unsigned char *) malloc ( sizeof(unsigned char) * OP_SIZE );

  /* keep reading until a break */
  for (;;)
    {
      memset(inbuff,'\0', OP_SIZE);
      if ((n = read (infd, inbuff, OP_SIZE)) == -1)
    {
      perror ("read error");
      break;
    }
      else if (n == 0)
    break;

      memset(outbuf,'\0', IP_SIZE);

      if (EVP_DecryptUpdate (&ctx, outbuf, &olen, inbuff, n) != 1)
    {
      printf ("error in decrypt update\n");
      return 0;
    }

      if (EVP_DecryptFinal (&ctx, outbuf + olen, &tlen) != 1)
    {
      printf ("error in decrypt final\n");
      return 0;
    }
      olen += tlen;
      if ((n = write (outfd, outbuf, olen)) == -1)
    perror ("write error");
    }

  EVP_CIPHER_CTX_cleanup (&ctx);
  return 1;
}

int
encrypt (int infd, int outfd)
{
  char *inbuff, *outbuf;

  int olen, tlen, n;
  EVP_CIPHER_CTX ctx;
  EVP_CIPHER_CTX_init (&ctx);
  EVP_EncryptInit (&ctx, EVP_bf_cbc (), key, iv);

  outbuf = (unsigned char *) malloc ( sizeof(unsigned char) * OP_SIZE );
  inbuff = (unsigned char *) malloc ( sizeof(unsigned char) * IP_SIZE );

  for (;;)
    {
      memset(inbuff,'\0', IP_SIZE);

      if ((n = read (infd, inbuff, IP_SIZE)) == -1)
    {
      perror ("read error");
      break;
    }
      else if (n == 0)
    break;

      if (EVP_EncryptUpdate (&ctx, outbuf, &olen, inbuff, n) != 1)
    {
      printf ("error in encrypt update\n");
      return 0;
    }

      if (EVP_EncryptFinal (&ctx, outbuf + olen, &tlen) != 1)
    {
      printf ("error in encrypt final\n");
      return 0;
    }
      olen += tlen;
      if ((n = write (outfd, outbuf, olen)) == -1)
    perror ("write error");
    }
  EVP_CIPHER_CTX_cleanup (&ctx);
  return 1;
}

int
main (int argc, char *argv[])
{
  int flags1 = 0, flags2 = 0, outfd, infd, decfd;
  mode_t mode;
  char choice, temp;
  int done = 0, n, olen;

  memset(key,'\0', 16);
  memset(iv,'\0', 8);
  memset(&mode, '\0', sizeof(mode));

  flags1 = flags1 | O_RDONLY;
  flags2 = flags2 | O_RDONLY;
  flags2 = flags2 | O_WRONLY;
  flags2 = flags2 | O_CREAT;

  mode = mode | S_IRUSR;
  mode = mode | S_IWUSR;

  generate_key ();

  if ((infd = open (argv[1], flags1, mode)) == -1)
    perror ("open input file error");

  if ((outfd = open (argv[2], flags2, mode)) == -1)
    perror ("open output file error");

  encrypt (infd, outfd);

  close (infd);
  close (outfd);

  if ((outfd = open (argv[2], flags1, mode)) == -1)
    perror ("open output file error");

  if ((decfd = open (argv[3], flags2, mode)) == -1)
    perror ("open output file error");

  /* After much head scratching reusing the out as an in is correct here */
  decrypt (outfd, decfd);

  close (outfd);
  fsync (decfd);
  close (decfd);

  return 0;
}

【问题讨论】:

  • 如何计算 OP_SIZE?

标签: c openssl corruption


【解决方案1】:

错误在于调用 EVP_DecryptFinal 和 EVP_EncryptFinal 的方式。这些函数应该在 for 循环结束时调用,最后添加 olen 并再次写入 tlen 的部分是复制输出。以下是最终的工作版本:

#include <openssl/blowfish.h>
#include <openssl/evp.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#define IP_SIZE 1024
#define OP_SIZE 1024 + EVP_MAX_BLOCK_LENGTH
unsigned char   key[16];
unsigned char   iv[8];

int
generate_key()
{
    int             i, fd;
    if ((fd = open("/dev/random", O_RDONLY)) == -1)
        perror("open error");

    if ((read(fd, key, 16)) == -1)
        perror("read key error");

    if ((read(fd, iv, 8)) == -1)
        perror("read iv error");

    printf("128 bit key:\n");
    for (i = 0; i < 16; i++)
        printf("%4d ", key[i]);

    printf("\nInitialization vector\n");
    for (i = 0; i < 8; i++)
        printf("%4d ", iv[i]);
    printf("\n");


    close(fd);
    return 0;
}

int
do_decrypt(int infd, int outfd)
{
    unsigned char           *inbuff, *outbuf;
    int             olen=0, tlen=0, n=0;
    EVP_CIPHER_CTX  ctx;
    EVP_CIPHER_CTX_init(&ctx);
    EVP_DecryptInit(&ctx, EVP_bf_cbc(), key, iv);

    outbuf = (unsigned char *) malloc(sizeof(unsigned char) * OP_SIZE);
    inbuff = (unsigned char *) malloc(sizeof(unsigned char) * IP_SIZE);

    /* keep reading until a break */
    for (;;) {
        memset(inbuff, 0, IP_SIZE);
        if ((n = read(infd, inbuff, IP_SIZE)) == -1) {
            perror("read error");
            break;
        } else if (n == 0)
            break;

        memset(outbuf, 0, OP_SIZE);

        if (EVP_DecryptUpdate(&ctx, outbuf, &olen, inbuff, n) != 1) {
            printf("error in decrypt update\n");
            return 0;
        }
        if ((n = write(outfd, outbuf, olen)) == -1)
            perror("write error");
    }

    tlen=0;
    if (EVP_DecryptFinal(&ctx, outbuf + olen, &tlen) != 1) {
        perror("error in decrypt final");
        return 0;
    }

    if ((n = write(outfd, outbuf+olen, tlen)) == -1)
        perror("write error");

    EVP_CIPHER_CTX_cleanup(&ctx);
    return 1;
}

int
do_encrypt(int infd, int outfd)
{
    unsigned char           *inbuff, *outbuf;

    int             olen=0, tlen=0, n=0;
    EVP_CIPHER_CTX  ctx;
    EVP_CIPHER_CTX_init(&ctx);
    EVP_EncryptInit(&ctx, EVP_bf_cbc(), key, iv);

    outbuf = (unsigned char *) malloc(sizeof(unsigned char) * OP_SIZE);
    inbuff = (unsigned char *) malloc(sizeof(unsigned char) * IP_SIZE);

    for (;;) {
        memset(inbuff, 0, IP_SIZE);

        if ((n = read(infd, inbuff, IP_SIZE)) == -1) {
            perror("read error");
            break;
        } else if (n == 0)
            break;

        if (EVP_EncryptUpdate(&ctx, outbuf, &olen, inbuff, n) != 1) {
            printf("error in encrypt update\n");
            return 0;
        }

        if ((n = write(outfd, outbuf, olen)) == -1)
            perror("write error");
    }
    tlen=0;
    if (EVP_EncryptFinal(&ctx, outbuf + olen, &tlen) != 1) {
        printf("error in encrypt final\n");
        return 0;
    }

    if ((n = write(outfd, outbuf+olen, tlen)) == -1)
        perror("write error");

    EVP_CIPHER_CTX_cleanup(&ctx);
    return 1;
}

int
main(int argc, char *argv[])
{
    int             flags1 = 0, flags2 = 0, outfd, infd;
    mode_t          mode;

    memset(key, 0, 16);
    memset(iv, 0, 8);
    memset(&mode, 0, sizeof(mode));

    flags1 = flags1 | O_RDONLY;
    flags2 = flags2 | O_RDONLY;
    flags2 = flags2 | O_WRONLY;
    flags2 = flags2 | O_CREAT;

    mode = mode | S_IRUSR;
    mode = mode | S_IWUSR;


    generate_key();


    if ((infd = open(argv[1], flags1, mode)) == -1)
        perror("open input file error");

    if ((outfd = open(argv[2], flags2, mode)) == -1)
        perror("open output file error");

    do_encrypt(infd, outfd);

    close(infd);
    fsync(outfd);
    close(outfd);

    if ((infd = open(argv[2], flags1, mode)) == -1)
        perror("open output file error");

    if ((outfd = open(argv[3], flags2, mode)) == -1)
        perror("open output file error");

    do_decrypt(infd, outfd);

    close(infd);
    fsync(infd);
    close(outfd);

    return 0;
}

【讨论】:

  • 我对此表示严重怀疑。如果这是真的,最后的位数我们会写两次。
  • 根据我对块密码的理解,这是有道理的。 *Final 函数用于不是块大小倍数的数据的最后一位。此外,您在循环内执行 *Final 函数调用的事实是解密文件中出现垃圾字符的原因。在我的测试中,这解决了问题
  • 我之前的回答并不完全正确。最后的编辑是一个完整的工作版本,基于您问题中的代码(带有修复和一些清理)。
  • 现在看。我需要休息几天。
  • 我不太明白如何在解密阶段单独处理部分缓冲区以供最终处理,除非常规解密在没有完整缓冲区的情况下会很有趣。
【解决方案2】:

既然你说错误似乎出现在解密阶段,我会怀疑以下几行:

if (EVP_DecryptUpdate (&ctx, outbuf, &olen, inbuff, n) != 1)
...

if (EVP_DecryptFinal (&ctx, outbuf + olen, &tlen) != 1)
...

outbuf 分配的内存与解密函数将放入其中的内容相比有多大?你确定outbuf + olen 不会带你越过缓冲区的末尾吗?

【讨论】:

  • 很难判断它是否在加密或解密时损坏。 #define IP_SIZE 1024 #define OP_SIZE 1032 char outbuf[OP_SIZE]; char inbuff[IP_SIZE];
  • 我可以对我没有分配的东西做 memset 吗?
  • 嗯,这可能解释了作者在他的 bzero 命令中使用 &outbuf 的原因...打算尝试分配而不是堆栈变量。
  • 您可以在可以写入的任何有效内存区域上执行 memset - 我怀疑您或解密函数正在写入数组末尾
  • 很遗憾,我家里没有 Purify。什么是开源等效的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-25
  • 2021-11-05
  • 1970-01-01
  • 1970-01-01
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多