]>
git.ipfire.org Git - people/ms/strongswan.git/blob - src/libfreeswan/ttodata.c
2 * convert from text form of arbitrary data (e.g., keys) to binary
3 * Copyright (C) 2000 Henry Spencer.
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Library General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 * License for more details.
18 /* converters and misc */
19 static int unhex(const char *, char *, size_t);
20 static int unb64(const char *, char *, size_t);
21 static int untext(const char *, char *, size_t);
22 static const char *badch(const char *, int, char *, size_t);
24 /* internal error codes for converters */
25 #define SHORT (-2) /* internal buffer too short */
26 #define BADPAD (-3) /* bad base64 padding */
27 #define BADCH0 (-4) /* invalid character 0 */
28 #define BADCH1 (-5) /* invalid character 1 */
29 #define BADCH2 (-6) /* invalid character 2 */
30 #define BADCH3 (-7) /* invalid character 3 */
31 #define BADOFF(code) (BADCH0-(code))
34 - ttodatav - convert text to data, with verbose error reports
35 * If some of this looks slightly odd, it's because it has changed
36 * repeatedly (from the original atodata()) without a major rewrite.
38 const char * /* NULL on success, else literal or errp */
39 ttodatav(src
, srclen
, base
, dst
, dstlen
, lenp
, errp
, errlen
, flags
)
41 size_t srclen
; /* 0 means apply strlen() */
42 int base
; /* 0 means figure it out */
43 char *dst
; /* need not be valid if dstlen is 0 */
45 size_t *lenp
; /* where to record length (NULL is nowhere) */
46 char *errp
; /* error buffer */
50 size_t ingroup
; /* number of input bytes converted at once */
51 char buf
[4]; /* output from conversion */
52 int nbytes
; /* size of output */
53 int (*decode
)(const char *, char *, size_t);
63 dst
= buf
; /* point it somewhere valid */
68 return "input too short to be valid";
70 return "input does not begin with format prefix";
85 return "unknown format prefix";
99 if(flags
& TTODATAV_IGNORESPACE
) {
110 return "unknown base";
116 char stage
[4]; /* staging area for group */
119 /* Grab ingroup characters into stage,
120 * squeezing out blanks if we are supposed to ignore them.
122 for (sl
= 0; sl
< ingroup
; src
++, srclen
--) {
124 return "input ends in mid-byte, perhaps truncated";
125 else if (!(skipSpace
&& (*src
== ' ' || *src
== '\t')))
129 nbytes
= (*decode
)(stage
, buf
, sizeof(buf
));
135 return badch(stage
, nbytes
, errp
, errlen
);
137 return "internal buffer too short (\"can't happen\")";
139 return "bad (non-zero) padding at end of base64 input";
142 return "unknown internal error";
143 for (i
= 0; i
< nbytes
; i
++) {
148 while (srclen
>= 1 && skipSpace
&& (*src
== ' ' || *src
== '\t')){
152 if (underscoreok
&& srclen
> 1 && *src
== '_') {
153 /* srclen > 1 means not last character */
160 return "no data bytes specified by input";
167 - ttodata - convert text to data
169 const char * /* NULL on success, else literal */
170 ttodata(src
, srclen
, base
, dst
, dstlen
, lenp
)
172 size_t srclen
; /* 0 means apply strlen() */
173 int base
; /* 0 means figure it out */
174 char *dst
; /* need not be valid if dstlen is 0 */
176 size_t *lenp
; /* where to record length (NULL is nowhere) */
178 return ttodatav(src
, srclen
, base
, dst
, dstlen
, lenp
, (char *)NULL
,
179 (size_t)0, TTODATAV_SPACECOUNTS
);
183 - atodata - convert ASCII to data
184 * backward-compatibility interface
186 size_t /* 0 for failure, true length for success */
187 atodata(src
, srclen
, dst
, dstlen
)
196 err
= ttodata(src
, srclen
, 0, dst
, dstlen
, &len
);
203 - atobytes - convert ASCII to data bytes
204 * another backward-compatibility interface
207 atobytes(src
, srclen
, dst
, dstlen
, lenp
)
214 return ttodata(src
, srclen
, 0, dst
, dstlen
, lenp
);
218 - unhex - convert two ASCII hex digits to byte
220 static int /* number of result bytes, or error code */
221 unhex(src
, dst
, dstlen
)
222 const char *src
; /* known to be full length */
224 size_t dstlen
; /* not large enough is a failure */
228 static char hex
[] = "0123456789abcdef";
233 p
= strchr(hex
, *src
);
235 p
= strchr(hex
, tolower(*src
));
238 byte
= (p
- hex
) << 4;
241 p
= strchr(hex
, *src
);
243 p
= strchr(hex
, tolower(*src
));
253 - unb64 - convert four ASCII base64 digits to three bytes
254 * Note that a base64 digit group is padded out with '=' if it represents
255 * less than three bytes: one byte is dd==, two is ddd=, three is dddd.
257 static int /* number of result bytes, or error code */
258 unb64(src
, dst
, dstlen
)
259 const char *src
; /* known to be full length */
266 static char base64
[] =
267 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
272 p
= strchr(base64
, *src
++);
276 byte1
= (p
- base64
) << 2; /* first six bits */
278 p
= strchr(base64
, *src
++);
283 byte2
= p
- base64
; /* next six: two plus four */
284 *dst
++ = byte1
| (byte2
>> 4);
285 byte1
= (byte2
& 0xf) << 4;
287 p
= strchr(base64
, *src
++);
289 if (*(src
-1) == '=' && *src
== '=') {
290 if (byte1
!= 0) /* bad padding */
297 byte2
= p
- base64
; /* next six: four plus two */
298 *dst
++ = byte1
| (byte2
>> 2);
299 byte1
= (byte2
& 0x3) << 6;
301 p
= strchr(base64
, *src
++);
303 if (*(src
-1) == '=') {
304 if (byte1
!= 0) /* bad padding */
310 byte2
= p
- base64
; /* last six */
311 *dst
++ = byte1
| byte2
;
317 - untext - convert one ASCII character to byte
319 static int /* number of result bytes, or error code */
320 untext(src
, dst
, dstlen
)
321 const char *src
; /* known to be full length */
323 size_t dstlen
; /* not large enough is a failure */
333 - badch - produce a nice complaint about an unknown character
335 * If the compiler complains that the array bigenough[] has a negative
336 * size, that means the TTODATAV_BUF constant has been set too small.
338 static const char * /* literal or errp */
339 badch(src
, errcode
, errp
, errlen
)
342 char *errp
; /* might be NULL */
345 static const char pre
[] = "unknown character (`";
346 static const char suf
[] = "') in input";
348 # define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
350 char bigenough
[TTODATAV_BUF
- REQD
]; /* see above */
354 if (errp
== NULL
|| errlen
< REQD
)
355 return "unknown character in input";
357 ch
= *(src
+ BADOFF(errcode
));
363 buf
[1] = ((ch
& 0700) >> 6) + '0';
364 buf
[2] = ((ch
& 0070) >> 3) + '0';
365 buf
[3] = ((ch
& 0007) >> 0) + '0';
370 return (const char *)errp
;
380 static void check(struct artab
*r
, char *buf
, size_t n
, err_t oops
, int *status
);
381 static void regress(char *pgm
);
382 static void hexout(const char *s
, size_t len
, FILE *f
);
385 - main - convert first argument to hex, or run regression
388 main(int argc
, char *argv
[])
401 fprintf(stderr
, "Usage: %s {0x<hex>|0s<base64>|-r}\n", pgm
);
405 if (strcmp(argv
[1], "-r") == 0) {
406 regress(pgm
); /* should not return */
407 fprintf(stderr
, "%s: regress() returned?!?\n", pgm
);
411 oops
= ttodatav(argv
[1], 0, 0, buf
, sizeof(buf
), &n
,
412 err
, sizeof(err
), TTODATAV_IGNORESPACE
);
414 fprintf(stderr
, "%s: ttodata error `%s' in `%s'\n", pgm
,
419 if (n
> sizeof(buf
)) {
420 p
= (char *)malloc((size_t)n
);
423 "%s: unable to malloc %d bytes for result\n",
427 oops
= ttodata(argv
[1], 0, 0, p
, n
, &n
);
429 fprintf(stderr
, "%s: error `%s' in ttodata retry?!?\n",
435 hexout(p
, n
, stdout
);
438 i
= datatot(buf
, n
, 'h', buf2
, sizeof(buf2
));
440 fprintf(stderr
, "%s: datatot reports error in `%s'\n", pgm
,
445 if (i
> sizeof(buf2
)) {
446 p2
= (char *)malloc((size_t)i
);
449 "%s: unable to malloc %d bytes for result\n",
453 i
= datatot(buf
, n
, 'h', p2
, i
);
455 fprintf(stderr
, "%s: error in datatoa retry?!?\n", pgm
);
466 - hexout - output an arbitrary-length string in hex
477 for (i
= 0; i
< len
; i
++)
478 fprintf(f
, "%02x", (unsigned char)s
[i
]);
483 # define IGNORESPACE_BIAS 1000
484 char *ascii
; /* NULL for end */
485 char *data
; /* NULL for error expected */
491 { 0, "0xab", "\xab", },
492 { 0, "0xabc", NULL
, },
493 { 0, "0xabcd", "\xab\xcd", },
494 { 0, "0x0123456789", "\x01\x23\x45\x67\x89", },
495 { 0, "0x01x", NULL
, },
496 { 0, "0xabcdef", "\xab\xcd\xef", },
497 { 0, "0xABCDEF", "\xab\xcd\xef", },
498 { 0, "0XaBc0eEd81f", "\xab\xc0\xee\xd8\x1f", },
499 { 0, "0XaBc0_eEd8", "\xab\xc0\xee\xd8", },
500 { 0, "0XaBc0_", NULL
, },
501 { 0, "0X_aBc0", NULL
, },
502 { 0, "0Xa_Bc0", NULL
, },
503 { 16, "aBc0eEd8", "\xab\xc0\xee\xd8", },
506 { 0, "0sBA", NULL
, },
507 { 0, "0sCBA", NULL
, },
508 { 0, "0sDCBA", "\x0c\x20\x40", },
509 { 0, "0SDCBA", "\x0c\x20\x40", },
510 { 0, "0sDA==", "\x0c", },
511 { 0, "0sDC==", NULL
, },
512 { 0, "0sDCA=", "\x0c\x20", },
513 { 0, "0sDCB=", NULL
, },
514 { 0, "0sDCAZ", "\x0c\x20\x19", },
515 { 0, "0sDCAa", "\x0c\x20\x1a", },
516 { 0, "0sDCAz", "\x0c\x20\x33", },
517 { 0, "0sDCA0", "\x0c\x20\x34", },
518 { 0, "0sDCA9", "\x0c\x20\x3d", },
519 { 0, "0sDCA+", "\x0c\x20\x3e", },
520 { 0, "0sDCA/", "\x0c\x20\x3f", },
521 { 0, "0sAbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
522 { IGNORESPACE_BIAS
+ 0, "0s AbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
523 { IGNORESPACE_BIAS
+ 0, "0sA braCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
524 { IGNORESPACE_BIAS
+ 0, "0sAb raCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
525 { IGNORESPACE_BIAS
+ 0, "0sAbr aCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
526 { IGNORESPACE_BIAS
+ 0, "0sAbra Cadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
527 { IGNORESPACE_BIAS
+ 0, "0sAbraC adabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
528 { IGNORESPACE_BIAS
+ 0, "0sAbraCa dabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
529 { IGNORESPACE_BIAS
+ 0, "0sAbraCad abra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
530 { IGNORESPACE_BIAS
+ 0, "0sAbraCada bra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
531 { IGNORESPACE_BIAS
+ 0, "0sAbraCadab ra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
532 { IGNORESPACE_BIAS
+ 0, "0sAbraCadabr a+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
533 { IGNORESPACE_BIAS
+ 0, "0sAbraCadabra +", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
534 { IGNORESPACE_BIAS
+ 0, "0sAbraCadabra+ ", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
536 { 0, "0tabc_xyz", "abc_xyz", },
537 { 256, "abc_xyz", "abc_xyz", },
542 char *data
; /* input; NULL for end */
544 int buflen
; /* -1 means big buffer */
545 int outlen
; /* -1 means strlen(ascii)+1 */
546 char *ascii
; /* NULL for error expected */
548 { "", 'x', -1, -1, NULL
, },
549 { "", 'X', -1, -1, NULL
, },
550 { "", 'n', -1, -1, NULL
, },
551 { "0", 'x', -1, -1, "0x30", },
552 { "0", 'x', 0, 5, "---", },
553 { "0", 'x', 1, 5, "", },
554 { "0", 'x', 2, 5, "0", },
555 { "0", 'x', 3, 5, "0x", },
556 { "0", 'x', 4, 5, "0x3", },
557 { "0", 'x', 5, 5, "0x30", },
558 { "0", 'x', 6, 5, "0x30", },
559 { "\xab\xcd", 'x', -1, -1, "0xabcd", },
560 { "\x01\x23\x45\x67\x89", 'x', -1, -1, "0x0123456789", },
561 { "\xab\xcd\xef", 'x', -1, -1, "0xabcdef", },
562 { "\xab\xc0\xee\xd8\x1f", 'x', -1, -1, "0xabc0eed81f", },
563 { "\x01\x02", 'h', -1, -1, "0x0102", },
564 { "\x01\x02\x03\x04\x05\x06", 'h', -1, -1, "0x01020304_0506", },
565 { "\xab\xc0\xee\xd8\x1f", 16, -1, -1, "abc0eed81f", },
566 { "\x0c\x20\x40", 's', -1, -1, "0sDCBA", },
567 { "\x0c\x20\x40", 's', 0, 7, "---", },
568 { "\x0c\x20\x40", 's', 1, 7, "", },
569 { "\x0c\x20\x40", 's', 2, 7, "0", },
570 { "\x0c\x20\x40", 's', 3, 7, "0s", },
571 { "\x0c\x20\x40", 's', 4, 7, "0sD", },
572 { "\x0c\x20\x40", 's', 5, 7, "0sDC", },
573 { "\x0c\x20\x40", 's', 6, 7, "0sDCB", },
574 { "\x0c\x20\x40", 's', 7, 7, "0sDCBA", },
575 { "\x0c\x20\x40", 's', 8, 7, "0sDCBA", },
576 { "\x0c", 's', -1, -1, "0sDA==", },
577 { "\x0c\x20", 's', -1, -1, "0sDCA=", },
578 { "\x0c\x20\x19", 's', -1, -1, "0sDCAZ", },
579 { "\x0c\x20\x1a", 's', -1, -1, "0sDCAa", },
580 { "\x0c\x20\x33", 's', -1, -1, "0sDCAz", },
581 { "\x0c\x20\x34", 's', -1, -1, "0sDCA0", },
582 { "\x0c\x20\x3d", 's', -1, -1, "0sDCA9", },
583 { "\x0c\x20\x3e", 's', -1, -1, "0sDCA+", },
584 { "\x0c\x20\x3f", 's', -1, -1, "0sDCA/", },
585 { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+", },
586 { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+", },
587 { NULL
, 'x', -1, -1, NULL
, },
591 - regress - regression-test ttodata() and datatot()
594 check(r
, buf
, n
, oops
, status
)
601 if (oops
!= NULL
&& r
->data
== NULL
)
602 {} /* error expected */
603 else if (oops
!= NULL
) {
604 printf("`%s' gave error `%s', expecting %d `", r
->ascii
,
605 oops
, strlen(r
->data
));
606 hexout(r
->data
, strlen(r
->data
), stdout
);
609 } else if (r
->data
== NULL
) {
610 printf("`%s' gave %d `", r
->ascii
, n
);
611 hexout(buf
, n
, stdout
);
612 printf("', expecting error\n");
614 } else if (n
!= strlen(r
->data
)) {
615 printf("length wrong in `%s': got %d `", r
->ascii
, n
);
616 hexout(buf
, n
, stdout
);
617 printf("', expecting %d `", strlen(r
->data
));
618 hexout(r
->data
, strlen(r
->data
), stdout
);
621 } else if (memcmp(buf
, r
->data
, n
) != 0) {
622 printf("`%s' gave %d `", r
->ascii
, n
);
623 hexout(buf
, n
, stdout
);
624 printf("', expecting %d `", strlen(r
->data
));
625 hexout(r
->data
, strlen(r
->data
), stdout
);
632 static void /* should not return at all, in fact */
642 for (r
= atodatatab
; r
->ascii
!= NULL
; r
++) {
646 if ((base
== 0 || base
== IGNORESPACE_BIAS
+ 0) && r
->ascii
[0] == '0') {
647 switch (r
->ascii
[1]) {
663 if (base
>= IGNORESPACE_BIAS
) {
664 base
= base
- IGNORESPACE_BIAS
;
665 check(r
, buf
, n
, ttodatav(r
->ascii
, 0, base
, buf
, sizeof(buf
), &n
, NULL
, 0, TTODATAV_IGNORESPACE
), &status
);
667 check(r
, buf
, n
, ttodatav(r
->ascii
+2, 0, xbase
, buf
, sizeof(buf
), &n
, NULL
, 0, TTODATAV_IGNORESPACE
), &status
);
669 check(r
, buf
, n
, ttodata(r
->ascii
, 0, base
, buf
, sizeof(buf
), &n
), &status
);
670 if (base
== 64 || xbase
== 64)
671 check(r
, buf
, n
, ttodatav(r
->ascii
, 0, base
, buf
, sizeof(buf
), &n
, NULL
, 0, TTODATAV_IGNORESPACE
), &status
);
673 check(r
, buf
, n
, ttodata(r
->ascii
+2, 0, xbase
, buf
, sizeof(buf
), &n
), &status
);
674 if (base
== 64 || xbase
== 64)
675 check(r
, buf
, n
, ttodatav(r
->ascii
+2, 0, xbase
, buf
, sizeof(buf
), &n
, NULL
, 0, TTODATAV_IGNORESPACE
), &status
);
679 for (dr
= datatoatab
; dr
->data
!= NULL
; dr
++) {
683 n
= datatot(dr
->data
, strlen(dr
->data
), dr
->format
, buf
,
684 (dr
->buflen
== -1) ? sizeof(buf
) : dr
->buflen
);
685 should
= (dr
->ascii
== NULL
) ? 0 : strlen(dr
->ascii
) + 1;
686 if (dr
->outlen
!= -1)
688 if (n
== 0 && dr
->ascii
== NULL
)
689 {} /* error expected */
692 hexout(dr
->data
, strlen(dr
->data
), stdout
);
693 printf("' %c gave error, expecting %d `%s'\n",
694 dr
->format
, should
, dr
->ascii
);
696 } else if (dr
->ascii
== NULL
) {
698 hexout(dr
->data
, strlen(dr
->data
), stdout
);
699 printf("' %c gave %d `%.*s', expecting error\n",
700 dr
->format
, n
, (int)n
, buf
);
702 } else if (n
!= should
) {
703 printf("length wrong in `");
704 hexout(dr
->data
, strlen(dr
->data
), stdout
);
705 printf("': got %d `%s'", n
, buf
);
706 printf(", expecting %d `%s'\n", should
, dr
->ascii
);
708 } else if (strcmp(buf
, dr
->ascii
) != 0) {
710 hexout(dr
->data
, strlen(dr
->data
), stdout
);
711 printf("' gave %d `%s'", n
, buf
);
712 printf(", expecting %d `%s'\n", should
, dr
->ascii
);
720 #endif /* TTODATA_MAIN */