Reputation: 21
CODE FIXED
Example:
argv[1] = "ABCDEF0123456789"
argv[2] = "FEDCBA9876543210"
desired output: "5511559955115599"
I am trying to do same as calculator -> hex xor hex = new hex <- send 2 xor strings and xor them into a new xored hex string.
The code seems to be eating away the data stored in the variables, so why is every xored char copied into a new hex string? It only prints the first xored byte.
#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;
}
Upvotes: 1
Views: 2756
Reputation: 754440
I think you need to go about the process a wholly different way. I see no reason to use the quads
and the 16-way if / else if / … / else
is horrid (at least it should be a loop using quads
). However, that's really unnecessary.
Given that you're dealing with user input and users are malicious, the code needs to deal with characters that aren't hex digits in the data, and mismatched lengths on the strings, and so on. That creates more error checking code than operational code, but that's not all that uncommon.
#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;
}
The err_*()
functions are declared in stderr.h
and implemented in stderr.c
and make error reporting much easier (at least for me, but then I wrote them). You can find the code on GitHub in https://github.com/jleffler/soq/tree/master/src/libsoq. The assertions in hexval()
and hexdigit()
are almost superfluous — the code using them ensures that the problems the assertions detect don't arise. OTOH, if the code were extracted from this context, those assertions might protect the naïve user (programmer).
The code converts each letter of the hex strings into the corresponding number and then uses xor
on the numbers, and converts the result back to a hex digit. You could consider using sscanf()
and sprintf()
to process more bytes at a time, but you lose some of the precision in the error reporting. It is harder to report what went wrong meaningfully.
Sample test script:
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
Output from sample test script:
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
----------------
The testing was important. I somehow managed to mistype the hex digit string as "0123456789ABCEDF"
, but the tests showed that there was a problem — the output of 0 ^ E
should be E
, not D
, and vice versa.
Upvotes: 1