1 /* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
2 /*======================================================================
3 Copyright (C) 2004,2005,2009,2013 Walter Doekes <walter+tthsum@wjd.nu>
4 This file is part of tthsum.
5 
6 tthsum is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 tthsum is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with tthsum.  If not, see <http://www.gnu.org/licenses/>.
18 ======================================================================*/
19 #include "base32.h"
20 
21 #include "endian.h"
22 #include <assert.h>
23 
24 #if BYTE_ORDER == BIG_ENDIAN
25 #    include <stdlib.h>
26 #    include <string.h>
27 #endif /* BYTE_ORDER == BIG_ENDIAN */
28 
29 #ifdef USE_TEXTS
30 #   include "texts.h"
31 #endif
32 
33 
34 static const int8_t base32_table[] = {
35     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
36     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
37     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
38     -1,-1,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
39     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
40     15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
41     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
42     15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
43     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
44     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
45     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
46     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
47     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
48     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
49     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
50     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
51 };
52 
53 static const unsigned char base32_alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
54 
uint64tobase32(char * dest,const uint64_t * src,unsigned len)55 int uint64tobase32(char* dest, const uint64_t* src, unsigned len) {
56 #if BYTE_ORDER == BIG_ENDIAN
57     int i;
58     uint8_t* tmp;
59     len *= 8;
60     if ((tmp = (uint8_t*)malloc(len)) == NULL) {
61 #ifdef USE_TEXTS
62 	set_error("malloc", ERROR_FROM_OS);
63 #endif /* USE_TEXTS */
64 	return -1;
65     }
66     for (i = 0; i < len; ++i)
67 	tmp[i ^ 7] = ((uint8_t*)src)[i];
68     i = uint8tobase32(dest, tmp, len);
69     free(tmp);
70     return i;
71 #else /* BYTE_ORDER != BIG_ENDIAN */
72     return uint8tobase32(dest, (const uint8_t*)src, len * 8);
73 #endif /* BYTE_ORDER != BIG_ENDIAN */
74 }
75 
uint8tobase32(char * dest,const uint8_t * src,unsigned len)76 int uint8tobase32(char* dest, const uint8_t* src, unsigned len) {
77     unsigned index = 0;
78     uint8_t word;
79     const uint8_t* srce = src + len;
80     while (src != srce) {
81 	/* Spanning byte boundary? */
82 	if (index > 3) {
83 	    word = (*src & (0xFF >> index));
84 	    index = (index + 5) % 8;
85 	    word <<= index;
86 	    if (src + 1 != srce)
87 		word |= *(src + 1) >> (8 - index);
88 	    ++src;
89 	} else {
90 	    word = (*src >> (8 - (index + 5))) & 0x1F;
91 	    index = (index + 5) % 8;
92 	    if (index == 0)
93 		++src;
94 	}
95 	assert(word < 32);
96 	*dest++ = base32_alpha[word];
97     }
98     *dest = '\0';
99     return 0;
100 }
101 
base32touint64(uint64_t * dest,const char * src,unsigned len)102 int base32touint64(uint64_t* dest, const char* src, unsigned len) {
103 #if BYTE_ORDER == BIG_ENDIAN
104     int ret, i;
105     uint8_t* tmp;
106     len *= 8;
107     if ((tmp = (uint8_t*)malloc(len)) == NULL) {
108 #ifdef USE_TEXTS
109 	set_error("malloc", ERROR_FROM_OS);
110 #endif /* USE_TEXTS */
111 	return -1;
112     }
113     memset(tmp, 0, len); /* dest must be initialized to zeroes */
114     ret = base32touint8(tmp, src, len);
115     for (i = 0; i < len; ++i)
116 	((uint8_t*)dest)[i ^ 7] = tmp[i];
117     free(tmp);
118     return ret;
119 #else /* BYTE_ORDER != BIG_ENDIAN */
120     return base32touint8((uint8_t*)dest, src, len * 8);
121 #endif /* BYTE_ORDER != BIG_ENDIAN */
122 }
123 
base32touint8(uint8_t * dest,const char * src,unsigned len)124 int base32touint8(uint8_t* dest, const char* src, unsigned len) {
125     unsigned index = 0;
126     int8_t tmp;
127     const uint8_t* deste = dest + len;
128     for (; dest != deste; ++src) {
129 	if ((tmp = base32_table[(unsigned)*src]) == -1) {
130 #ifdef USE_TEXTS
131 	    set_error("base32touint8", BASE32_INVALID_CHARACTER);
132 #endif /* USE_TEXTS */
133 	    return -1;
134 	}
135 	if (index <= 3) {
136 	    index = (index + 5) % 8;
137 	    if (index == 0)
138 		*dest++ |= tmp;
139 	    else
140 		*dest |= tmp << (8 - index);
141 	} else {
142 	    index = (index + 5) % 8;
143 	    *dest++ |= (tmp >> index);
144 	    *dest |= tmp << (8 - index);
145 	}
146     }
147     return 0;
148 }
149