如何在c中使用另一个十六进制字符串xor十六进制字符串

时间:2016-09-04 20:20:19

标签: c string

CODE FIXED

示例:

argv[1] = "ABCDEF0123456789" 
argv[2] = "FEDCBA9876543210"

desired output: "5511559955115599"

我正在尝试与计算器相同 - > hex xor hex = new hex< - 发送2个xor字符串并将它们xor转换为新的xored十六进制字符串。

代码似乎正在吞噬存储在变量中的数据,那么为什么每个xored char都被复制到一个新的十六进制字符串中?它只打印第一个xored字节。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>

const char* quads[] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" };

const char * chrTObin(unsigned char c) {
  if(c >= '0' && c <= '9') return quads[     c - '0'];
  if(c >= 'A' && c <= 'F') return quads[10 + c - 'A'];
  if(c >= 'a' && c <= 'f') return quads[10 + c - 'a'];
  return NULL;
  //return -1;
}

char* xorHash(char* chrXOR1, char* chrXOR2) {

    int x;
    int xPos;

    int intXOR1 = strlen(chrXOR1);


    char strBin1[4];
    char strBin2[4];
    char strBin[8];
    char strXORED[4];
    char newXOR[128];

    strcpy(newXOR, "");

    for(x = 0; x < intXOR1; x++) {

        strcpy(strBin, "");
        strcat(strBin, chrTObin(chrXOR1[x]));
        strcat(strBin, chrTObin(chrXOR2[x]));

        strcpy(strXORED, "");

        if(strlen(strBin) == 8) {
            for(xPos = 0; xPos < 4; xPos++) {
                if(strBin[xPos] == strBin[xPos+4]) {
                    strcat(strXORED, "0");
                } else {
                    strcat(strXORED, "1");
                }
            }
        }

        if(strcmp(strXORED, "0000") == 0) {
            strcat(newXOR, "0");
        } else if(strcmp(strXORED, "0001") == 0) {
            strcat(newXOR, "1");
        } else if(strcmp(strXORED, "0010") == 0) {
            strcat(newXOR, "2");
        } else if(strcmp(strXORED, "0011") == 0) {
            strcat(newXOR, "3");
        } else if(strcmp(strXORED, "0100") == 0) {
            strcat(newXOR, "4");
        } else if(strcmp(strXORED, "0101") == 0) {
            strcat(newXOR, "5");
        } else if(strcmp(strXORED, "0110") == 0) {
            strcat(newXOR, "6");
        } else if(strcmp(strXORED, "0111") == 0) {
            strcat(newXOR, "7");
        } else if(strcmp(strXORED, "1000") == 0) {
            strcat(newXOR, "8");
        } else if(strcmp(strXORED, "1001") == 0) {
            strcat(newXOR, "9");
        } else if(strcmp(strXORED, "1010") == 0) {
            strcat(newXOR, "A");
        } else if(strcmp(strXORED, "1011") == 0) {
            strcat(newXOR, "B");
        } else if(strcmp(strXORED, "1100") == 0) {
            strcat(newXOR, "C");
        } else if(strcmp(strXORED, "1101") == 0) {
            strcat(newXOR, "D");
        } else if(strcmp(strXORED, "1110") == 0) {
            strcat(newXOR, "E");
        } else if(strcmp(strXORED, "1111") == 0) {
            strcat(newXOR, "F");
        }

    }

    return newXOR;

}

int main(int argc, char* argv[]) {

    if(argc != 3){
        printf("Usage:\n");
        printf("xor HEX1 HEX2\n");
        return 0;
    }

    if(strlen(argv[1]) == strlen(argv[2])) {

        char oneXOR[128];
        char twoXOR[128];
        char newXOR[128];

        strcpy(oneXOR, argv[1]);
        strcpy(twoXOR, argv[2]);
        strcpy(newXOR, "");

        printf("XOR: %s %s\n", oneXOR, twoXOR);
        strcpy(newXOR, xorHash(oneXOR, twoXOR));
        printf("RESULT: %s\n", newXOR);

    }

    return 0;
}

1 个答案:

答案 0 :(得分:1)

我认为你需要以完全不同的方式进行这个过程。我认为没有理由使用quads和16路if / else if / … / else是可怕的(至少它应该是使用quads的循环)。但是,这真的没必要。

鉴于您正在处理用户输入并且用户是恶意的,代码需要处理数据中不是十六进制数字的字符,以及字符串上不匹配的长度,等等。这比操作代码创建了更多的错误检查代码,但这并不是那么罕见。

#include "stderr.h"
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

typedef unsigned char Uchar;

static inline int hexval(Uchar c)
{
    assert(isxdigit(c));
    if (isdigit(c))
        return c - '0';
    else if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    else if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    else    // Only used if assert is disabled with -DNDEBUG
        return -1;
}

static const Uchar hexdigits[] = "0123456789ABCDEF";
static inline Uchar hexdigit(int hexval)
{
    assert(hexval >= 0 && hexval < 16);
    return hexdigits[hexval];
}

static int xor_hex_strings(const char *h1, const char *h2, char *x3)
{
    assert(strlen(h1) == strlen(h2));
    const Uchar *s1 = (Uchar *)h1;
    const Uchar *s2 = (Uchar *)h2;
    while (*s1 != '\0')
    {
        Uchar u1 = *s1++;
        Uchar u2 = *s2++;
        assert(isxdigit(u1));
        assert(isxdigit(u2));
        *x3++ = hexdigit(hexval(u1) ^ hexval(u2));
    }
    *x3 = '\0';
    return 0;
}

static void check_hex(const char *hexstr)
{
    const Uchar *s = (Uchar *)hexstr;
    while (*s != '\0')
    {
        Uchar c = *s++;
        if (!isxdigit(c))
            err_error("Character %c in '%s' is not a hex digit\n", c, hexstr);
    }
}

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    if (argc != 3)
        err_usage("hex-string1 hex-string2");
    size_t len1 = strlen(argv[1]);
    size_t len2 = strlen(argv[2]);
    if (len1 != len2)
        err_error("hex strings are not the same length (%zu for '%s' vs %zu for '%s')\n",
                  len1, argv[1], len2, argv[2]);
    check_hex(argv[1]);
    check_hex(argv[2]);

    char xor[len1 + 1];
    if (xor_hex_strings(argv[1], argv[2], xor) != 0)
        return 1;

    printf("%s\n%s\n%s\n", argv[1], argv[2], xor);
    return 0;
}

err_*()函数在stderr.h中声明并在stderr.c中实现,并使错误报告更容易(至少对我来说,但后来我写了它们)。您可以在https://github.com/jleffler/soq/tree/master/src/libsoq中的GitHub上找到代码。 hexval()hexdigit()中的断言几乎是多余的 - 使用它们的代码可确保断言检测到的问题不会出现。 OTOH,如果代码是从这个上下文中提取的,那些断言可能会保护天真的用户(程序员)。

代码将十六进制字符串的每个字母转换为相应的数字,然后对数字使用xor,并将结果转换回十六进制数字。您可以考虑使用sscanf()sprintf()一次处理更多字节,但是在错误报告中会丢失一些精度。很难有意义地报告出现了什么问题。

示例测试脚本:

cat <<'EOF' |
0123456789abcdef FEDCBA9876543210
123456789abcdef0 FEDCBA9876543210
23456789abcdef01 FEDCBA9876543210
3456789abcdef012 FEDCBA9876543210
456789abcdef0123 FEDCBA9876543210
56789abcdef01234 FEDCBA9876543210
6789abcdef012345 FEDCBA9876543210
789abcdef0123456 FEDCBA9876543210
89abcdef01234567 FEDCBA9876543210
9abcdef012345678 FEDCBA9876543210
abcdef0123456789 FEDCBA9876543210
bcdef0123456789a FEDCBA9876543210
cdef0123456789ab FEDCBA9876543210
def0123456789abc FEDCBA9876543210
ef0123456789abcd FEDCBA9876543210
f0123456789abcde FEDCBA9876543210
EOF

while read a b
do
    xr53 "$a" "$b"
    echo "----------------"
done

示例测试脚本的输出:

0123456789abcdef
FEDCBA9876543210
FFFFFFFFFFFFFFFF
----------------
123456789abcdef0
FEDCBA9876543210
ECE8ECE0ECE8ECE0
----------------
23456789abcdef01
FEDCBA9876543210
DD99DD11DD99DD11
----------------
3456789abcdef012
FEDCBA9876543210
CA8AC202CA8AC202
----------------
456789abcdef0123
FEDCBA9876543210
BBBB3333BBBB3333
----------------
56789abcdef01234
FEDCBA9876543210
A8A42024A8A42024
----------------
6789abcdef012345
FEDCBA9876543210
9955115599551155
----------------
789abcdef0123456
FEDCBA9876543210
8646064686460646
----------------
89abcdef01234567
FEDCBA9876543210
7777777777777777
----------------
9abcdef012345678
FEDCBA9876543210
6460646864606468
----------------
abcdef0123456789
FEDCBA9876543210
5511559955115599
----------------
bcdef0123456789a
FEDCBA9876543210
42024A8A42024A8A
----------------
cdef0123456789ab
FEDCBA9876543210
3333BBBB3333BBBB
----------------
def0123456789abc
FEDCBA9876543210
202CA8AC202CA8AC
----------------
ef0123456789abcd
FEDCBA9876543210
11DD99DD11DD99DD
----------------
f0123456789abcde
FEDCBA9876543210
0ECE8ECE0ECE8ECE
----------------

测试很重要。我以某种方式设法将十六进制数字字符串输错为"0123456789ABCEDF",但测试表明存在问题 - 0 ^ E的输出应该是E,而不是D,并且反之亦然。