1/*++
2/* NAME
3/*	hex_code 3
4/* SUMMARY
5/*	encode/decode data, hexadecimal style
6/* SYNOPSIS
7/*	#include <hex_code.h>
8/*
9/*	VSTRING	*hex_encode(result, in, len)
10/*	VSTRING	*result;
11/*	const char *in;
12/*	ssize_t	len;
13/*
14/*	VSTRING	*hex_decode(result, in, len)
15/*	VSTRING	*result;
16/*	const char *in;
17/*	ssize_t	len;
18/* DESCRIPTION
19/*	hex_encode() takes a block of len bytes and encodes it as one
20/*      upper-case null-terminated string.  The result value is
21/*	the result argument.
22/*
23/*	hex_decode() performs the opposite transformation on
24/*	lower-case, upper-case or mixed-case input. The result
25/*	value is the result argument. The result is null terminated,
26/*	whether or not that makes sense.
27/* DIAGNOSTICS
28/*	hex_decode() returns a null pointer when the input contains
29/*	characters not in the hexadecimal alphabet.
30/* LICENSE
31/* .ad
32/* .fi
33/*	The Secure Mailer license must be distributed with this software.
34/* AUTHOR(S)
35/*	Wietse Venema
36/*	IBM T.J. Watson Research
37/*	P.O. Box 704
38/*	Yorktown Heights, NY 10598, USA
39/*--*/
40
41/* System library. */
42
43#include <sys_defs.h>
44#include <ctype.h>
45#include <string.h>
46
47/* Utility library. */
48
49#include <msg.h>
50#include <mymalloc.h>
51#include <vstring.h>
52#include <hex_code.h>
53
54/* Application-specific. */
55
56static const unsigned char hex_chars[] = "0123456789ABCDEF";
57
58#define UCHAR_PTR(x) ((const unsigned char *)(x))
59
60/* hex_encode - raw data to encoded */
61
62VSTRING *hex_encode(VSTRING *result, const char *in, ssize_t len)
63{
64    const unsigned char *cp;
65    int     ch;
66    ssize_t count;
67
68    VSTRING_RESET(result);
69    for (cp = UCHAR_PTR(in), count = len; count > 0; count--, cp++) {
70	ch = *cp;
71	VSTRING_ADDCH(result, hex_chars[(ch >> 4) & 0xf]);
72	VSTRING_ADDCH(result, hex_chars[ch & 0xf]);
73    }
74    VSTRING_TERMINATE(result);
75    return (result);
76}
77
78/* hex_decode - encoded data to raw */
79
80VSTRING *hex_decode(VSTRING *result, const char *in, ssize_t len)
81{
82    const unsigned char *cp;
83    ssize_t count;
84    unsigned int hex;
85    unsigned int bin;
86
87    VSTRING_RESET(result);
88    for (cp = UCHAR_PTR(in), count = len; count > 0; cp += 2, count -= 2) {
89	if (count < 2)
90	    return (0);
91	hex = cp[0];
92	if (hex >= '0' && hex <= '9')
93	    bin = (hex - '0') << 4;
94	else if (hex >= 'A' && hex <= 'F')
95	    bin = (hex - 'A' + 10) << 4;
96	else if (hex >= 'a' && hex <= 'f')
97	    bin = (hex - 'a' + 10) << 4;
98	else
99	    return (0);
100	hex = cp[1];
101	if (hex >= '0' && hex <= '9')
102	    bin |= (hex - '0');
103	else if (hex >= 'A' && hex <= 'F')
104	    bin |= (hex - 'A' + 10);
105	else if (hex >= 'a' && hex <= 'f')
106	    bin |= (hex - 'a' + 10);
107	else
108	    return (0);
109	VSTRING_ADDCH(result, bin);
110    }
111    VSTRING_TERMINATE(result);
112    return (result);
113}
114
115#ifdef TEST
116
117 /*
118  * Proof-of-concept test program: convert to hexadecimal and back.
119  */
120
121#define STR(x)	vstring_str(x)
122#define LEN(x)	VSTRING_LEN(x)
123
124int     main(int unused_argc, char **unused_argv)
125{
126    VSTRING *b1 = vstring_alloc(1);
127    VSTRING *b2 = vstring_alloc(1);
128    char   *test = "this is a test";
129
130#define DECODE(b,x,l) { \
131	if (hex_decode((b),(x),(l)) == 0) \
132	    msg_panic("bad hex: %s", (x)); \
133    }
134#define VERIFY(b,t) { \
135	if (strcmp((b), (t)) != 0) \
136	    msg_panic("bad test: %s", (b)); \
137    }
138
139    hex_encode(b1, test, strlen(test));
140    DECODE(b2, STR(b1), LEN(b1));
141    VERIFY(STR(b2), test);
142
143    hex_encode(b1, test, strlen(test));
144    hex_encode(b2, STR(b1), LEN(b1));
145    hex_encode(b1, STR(b2), LEN(b2));
146    DECODE(b2, STR(b1), LEN(b1));
147    DECODE(b1, STR(b2), LEN(b2));
148    DECODE(b2, STR(b1), LEN(b1));
149    VERIFY(STR(b2), test);
150
151    hex_encode(b1, test, strlen(test));
152    hex_encode(b2, STR(b1), LEN(b1));
153    hex_encode(b1, STR(b2), LEN(b2));
154    hex_encode(b2, STR(b1), LEN(b1));
155    hex_encode(b1, STR(b2), LEN(b2));
156    DECODE(b2, STR(b1), LEN(b1));
157    DECODE(b1, STR(b2), LEN(b2));
158    DECODE(b2, STR(b1), LEN(b1));
159    DECODE(b1, STR(b2), LEN(b2));
160    DECODE(b2, STR(b1), LEN(b1));
161    VERIFY(STR(b2), test);
162
163    vstring_free(b1);
164    vstring_free(b2);
165    return (0);
166}
167
168#endif
169