1 /* vim: set expandtab ts=4 sw=4: */
2 /*
3 * You may redistribute this program and/or modify it under the terms of
4 * the GNU General Public License as published by the Free Software Foundation,
5 * either version 3 of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <https://www.gnu.org/licenses/>.
14 */
15 #ifndef Base32_H
16 #define Base32_H
17
18 #include <stdint.h>
19
20 /*
21 * Base32 encode or decode a byte array using the format defined in:
22 * http://dnscurve.org/in-implement.html
23 */
24
25 /** Returned by Base32_decode() if the input is not valid base32. */
26 #define Base32_BAD_INPUT -1
27
28 /** Returned by Base32_decode() or Base32_encode() if the output buffer is too small. */
29 #define Base32_TOO_BIG -2
30
31 /**
32 * Decode a base32 encoded number.
33 *
34 * @param output the place to put the decoded bytes.
35 * This may be modified even if there is a decoding error.
36 * @param outLength the length of the output array, if the decoded output is longer,
37 * Base32_TOO_BIG will be returned.
38 * @param in the buffer holding the base32 encoded number.
39 * @param inputLength the length of the input buffer.
40 * @return the length of the output if all goes well, Base32_BAD_INPUT if the input
41 * is not valid base32, or Base32_TOO_BIG if the output buffer is not large
42 * enough to handle the output.
43 */
Base32_decode(uint8_t * output,const uint32_t outLength,const uint8_t * in,const uint32_t inputLength)44 static inline int Base32_decode(uint8_t* output,
45 const uint32_t outLength,
46 const uint8_t* in,
47 const uint32_t inputLength)
48 {
49 // Maps ascii character inputs to the numbers
50 // Invalid characters are represented by 99
51 static const uint8_t numForAscii[] =
52 {
53 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
54 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
55 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
56 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,99,99,99,99,99,99,
57 99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
58 21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99,
59 99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
60 21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99
61 };
62
63 uint32_t outIndex = 0;
64 uint32_t inputIndex = 0;
65 uint32_t nextByte = 0;
66 uint32_t bits = 0;
67
68 while (inputIndex < inputLength) {
69 if (in[inputIndex] & 0x80) {
70 return Base32_BAD_INPUT;
71 }
72 const uint8_t b = numForAscii[in[inputIndex++]];
73 if (b > 31) {
74 return Base32_BAD_INPUT;
75 }
76
77 nextByte |= ((unsigned) b) << bits;
78 bits += 5;
79
80 if (bits >= 8) {
81 if (outIndex >= outLength) {
82 return Base32_TOO_BIG;
83 }
84 output[outIndex++] = nextByte;
85 bits -= 8;
86 nextByte >>= 8;
87 }
88 }
89
90 if (bits >= 5 || nextByte) {
91 return Base32_BAD_INPUT;
92 }
93
94 return outIndex;
95 }
96
97 /**
98 * Base32 encode a number.
99 *
100 * @param output the place to put the base32 encoded output.
101 * This may be modified even if there is a encoding error.
102 * @param outLength the length of the output array, if the encoded output is longer,
103 * Base32_TOO_BIG will be returned.
104 * @param in the buffer holding the bytes to encode.
105 * @param inputLength the length of the input buffer.
106 * @return the length of the output if all goes well,
107 * or Base32_TOO_BIG if the output buffer is not large enough to handle the output.
108 */
Base32_encode(uint8_t * output,const uint32_t outputLength,const uint8_t * in,const uint32_t inputLength)109 static inline int Base32_encode(uint8_t* output,
110 const uint32_t outputLength,
111 const uint8_t* in,
112 const uint32_t inputLength)
113 {
114 uint32_t outIndex = 0;
115 uint32_t inIndex = 0;
116 uint32_t work = 0;
117 uint32_t bits = 0;
118 static const uint8_t* kChars = (uint8_t*) "0123456789bcdfghjklmnpqrstuvwxyz";
119
120 while (inIndex < inputLength) {
121 work |= ((unsigned) in[inIndex++]) << bits;
122 bits += 8;
123
124 while (bits >= 5) {
125 if (outIndex >= outputLength) {
126 return Base32_TOO_BIG;
127 }
128 output[outIndex++] = kChars[work & 31];
129 bits -= 5;
130 work >>= 5;
131 }
132 }
133
134 if (bits) {
135 if (outIndex >= outputLength) {
136 return Base32_TOO_BIG;
137 }
138 output[outIndex++] = kChars[work & 31];
139 bits -= 5;
140 work >>= 5;
141 }
142
143 if (outIndex < outputLength) {
144 output[outIndex] = '\0';
145 }
146 return outIndex;
147 }
148
149 #endif
150