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