【问题标题】:converted Hexadecimal to Binary string, printed as Garbage Symbols将十六进制转换为二进制字符串,打印为垃圾符号
【发布时间】:2020-12-06 09:09:34
【问题描述】:

我正在尝试将十六进制字符串转换为二进制,稍后将传递给加密库(openssl AES EVP_xx),所以我想我只需要一个带有 nul 终止符的二进制字符串。

我使用了Josch 演示的第二个测试 他的测试用例非常强大,所以我最终使用了查找表。 我只是更改了输入变量并添加了打印,但总是打印垃圾。

我只添加了以下内容:

  • malloc(期望的二进制字符串长度 + 1)

  • 在循环结束时设置 nul 终止符。 AFAIK 当字符串不是空终止时返回这些垃圾字符。

      #include <string.h>
      #include <stdio.h>
      #include <stdlib.h> 
    
      /* the resulting binary string is half the size of the input hex string
      * because every two hex characters map to one byte */
    
      unsigned char base16_decoding_table1[256] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
    
      int main(int argc,  char **argv){
    
      int TESTDATALEN=strlen(( char*) argv[1]);
    
      //char *result=malloc((TESTDATALEN/2)+1);
      int mallocLen=(TESTDATALEN%2) ? ((TESTDATALEN+3)/2) : ((TESTDATALEN/2)+1);
      unsigned char *result=malloc(mallocLen);
      *result='\0';
    
      int i;
      unsigned char cur;
      unsigned char val;
    
      for (i = 0; i < TESTDATALEN; i++) {
          cur = argv[1][i];
          val = base16_decoding_table1[(int)cur];
    
      /* even characters are the first half, odd characters the second half
              * of the current output byte */
          if (i%2 == 0) {
                  result[i/2] = val << 4;
              } else {
                  result[i/2] |= val;
              }
          }
      result[mallocLen] = '\0';
    
      printf ("Binary value: %s\n", result);
      //for (i = 0; i < TESTDATALEN/2; i++) printf ("%02hhx", result[i]); 
      //putchar ('\n');
    
      free(result);
    
      return 0;
    
      }
    

如果相关,我可能会在上下文中添加更多内容;出于性能原因,我无法触摸 strcat,因为十六进制到二进制只是加密中的一个步骤,它在数千(或数百万)个输入上执行,单个字段可以达到 8kb,因此也不能使用 strtol 并且必须这样做它在字符串中,

当前输出为:

hex2bin1.6.2 abc123def789

��#�

虽然此值的二进制等效项是: 101010111100000100100011110111101111011110001001

目标是将此转换代码返回的二进制字符串提供给 openssl AES EVP 加密例程,该例程接受并返回二进制输入。

提前致谢

【问题讨论】:

  • 嗯,您的代码看起来像working well
  • 这里至少有两个基本错误。一是您的输出缓冲区太小(当输入字符串的长度为奇数时,它会减一)。其次是char可能已签名,所以base_decoding_table[(int)cur]可能超出范围。从风格上讲,你做了很多漫无目的的演员表。如果您提供一个失败的硬编码示例字符串以及您期望的输出,您的问题也会更好。
  • #include "base_encoding_table.h" 但问题中没有提供。这也可能是问题的根源。
  • 为什么是printf ("Binary value: %s\n", result); 而不是for (i = 0; i &lt; TESTDATALEN/2; i++) printf ("%02hhx", result[i]); putchar ('\n');result 可能是 char 类型并以 nul 结尾——但它肯定不包含 ASCII 字符值......
  • @MikeCAT 感谢您的测试,输出仍然是符号,我需要 0 和 1;我在最后添加了更好的解释

标签: c


【解决方案1】:

好的。让我们理清头绪。您最大的误解是result 的内容将是一个可使用puts()printf() 使用"%s" 转换说明符打印的字符串。结果中的值不是 ASCII 值,它们是在 base16_decoding_table1[] 上查找的整数值。它不包含 ASCII 字符值。如果它确实包含字符值,则初始化程序中的每个元素都将用单引号括起来,例如'0','0','0',... 和索引条目 65-70 将是 'A','B','C','D','E','F',... 请参阅 ASCII Table & Description

正如评论中提到的,所有数字都以二进制形式存储在内存中。当您查看integer 值具有十进制值、八进制值或十六进制值时,这些只是内存中相同二进制位的不同视图。如果要查看实际的二进制位,只需直接从内存中输出该位的表示即可。

有很多方法可以做到这一点,但可以通过以下方式完成'0's 和'1' 的简单未填充二进制输出,对应于内存中的二进制0s 和1s:

 /** unpadded binary representation of 'v'. */
void binprn (const unsigned long v)
{
    if (!v)  { putchar ('0'); return; };

    size_t sz = sizeof v * CHAR_BIT;
    unsigned long rem = 0;

    while (sz--)
        if ((rem = v >> sz))
            putchar ((rem & 1) ? '1' : '0');
}

现在您只需将hex 输入作为程序参数,将其转换为存储值,然后输出该数字的二进制表示。由于您正在处理无符号数字,因此strtoul() 函数是一种简单的方法来获取十六进制字符输入并将其转换为内存中存储的无符号值。您在下面的更新代码中指出了这一点:

(编辑:如果TESTDATALEN奇数或1设置结果大小,并且注释大小结果每字节包含2个字符,奇数TESTDATALEN的输出字节将补零.)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>      /* for errno for strtoul validation */
#include <limits.h>     /* for CHAR_BIT */

/* the resulting binary string is half the size of the input hex string
 * because every two hex characters map to one byte */

unsigned char base16_decoding_table1[256] = {
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

/** unpadded binary representation of 'v'. */
void binprn (const unsigned long v)
{
    if (!v)  { putchar ('0'); return; };

    size_t sz = sizeof v * CHAR_BIT;
    unsigned long rem = 0;

    while (sz--)
        if ((rem = v >> sz))
            putchar ((rem & 1) ? '1' : '0');
}

int main(int argc, char **argv){
    
    if (argc < 2)       /* validate 1 argument given */
        return 1;
    
    size_t  TESTDATALEN = strlen(argv[1]),
            resultsz = TESTDATALEN / 2 + TESTDATALEN % 2; /* must have 1 char */
    
    unsigned char *result = calloc (resultsz, 1);   /* initialize result all 0 */
    
    errno = 0;          /* zero errno before call to strtoul */
    
    char *endptr;       /* end-pointer for strtoul validation */
    size_t i;
    int cur;
    unsigned char val;
    unsigned long value = strtoul (argv[1], &endptr, 16);   /* convert input */
    
    if (endptr == argv[1]) {    /* check if no digits converted */
        fputs ("error: invalid hex format - no digits converted.\n", stderr);
        return 1;
    }
    else if (errno) {           /* check for under/overflow */
        fputs ("error: overflow in conversion to hex.\n", stderr);
        return 1;
    }

    for (i = 0; i < TESTDATALEN; i++) {
        cur = argv[1][i];

        val = base16_decoding_table1[cur];
    
        /* even characters are the first half, odd characters the second half
         * of the current output byte */
        if (i % 2 == 0)
            result[i/2] = val << 4;
        else
            result[i/2] |= val;
    }
    
    printf ("hex value: %lx\nresult   : ", value);  /* output stored value */
    
    for (i = 0; i < resultsz; i++)                  /* output bytes in result */
        printf ("%02hhx", result[i]);
    putchar ('\n');
    
    fputs ("binary   : ", stdout);                  /* output binary of value */
    binprn (value);
    putchar ('\n');
    
    free(result);
}

使用/输出示例

现在,当您为有效的十六进制数字提供字符表示时,您将获得 value 输出中存储内容的十六进制表示,然后是 result 中存储的字节,然后是 @ 中存储的二进制表示987654344@ 和result 中的字节形式,例如

$ ./bin/base16decode aaff
hex value: aaff
result   : aaff
binary   : 1010101011111111

检查一下,如果您还有其他问题,请告诉我。

【讨论】:

    猜你喜欢
    • 2019-08-23
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 2014-08-03
    • 2015-06-21
    • 2014-10-24
    • 2012-03-04
    相关资源
    最近更新 更多