/src/trezor-firmware/crypto/base58.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * Copyright (c) 2012-2014 Luke Dashjr |
3 | | * Copyright (c) 2013-2014 Pavol Rusnak |
4 | | * |
5 | | * Permission is hereby granted, free of charge, to any person obtaining |
6 | | * a copy of this software and associated documentation files (the "Software"), |
7 | | * to deal in the Software without restriction, including without limitation |
8 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
9 | | * and/or sell copies of the Software, and to permit persons to whom the |
10 | | * Software is furnished to do so, subject to the following conditions: |
11 | | * |
12 | | * The above copyright notice and this permission notice shall be included |
13 | | * in all copies or substantial portions of the Software. |
14 | | * |
15 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
16 | | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES |
19 | | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
20 | | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
21 | | * OTHER DEALINGS IN THE SOFTWARE. |
22 | | */ |
23 | | |
24 | | #include "base58.h" |
25 | | #include <stdbool.h> |
26 | | #include <string.h> |
27 | | #include "memzero.h" |
28 | | #include "ripemd160.h" |
29 | | #include "sha2.h" |
30 | | |
31 | | const char b58digits_ordered[] = |
32 | | "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; |
33 | | const int8_t b58digits_map[] = { |
34 | | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
35 | | -1, -1, -1, -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, 0, 1, 2, 3, 4, 5, 6, 7, |
37 | | 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, |
38 | | 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, |
39 | | -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, |
40 | | 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, |
41 | | }; |
42 | | |
43 | | typedef uint64_t b58_maxint_t; |
44 | | typedef uint32_t b58_almostmaxint_t; |
45 | 0 | #define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) |
46 | | static const b58_almostmaxint_t b58_almostmaxint_mask = |
47 | | ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); |
48 | | |
49 | | // Decodes a null-terminated Base58 string `b58` to binary and writes the result |
50 | | // at the end of the buffer `bin` of size `*binszp`. On success `*binszp` is set |
51 | | // to the number of valid bytes at the end of the buffer. |
52 | 0 | bool b58tobin(void *bin, size_t *binszp, const char *b58) { |
53 | 0 | size_t binsz = *binszp; |
54 | |
|
55 | 0 | if (binsz == 0) { |
56 | 0 | return false; |
57 | 0 | } |
58 | | |
59 | 0 | const unsigned char *b58u = (const unsigned char *)b58; |
60 | 0 | unsigned char *binu = bin; |
61 | 0 | size_t outisz = |
62 | 0 | (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t); |
63 | 0 | b58_almostmaxint_t outi[outisz]; |
64 | 0 | b58_maxint_t t = 0; |
65 | 0 | b58_almostmaxint_t c = 0; |
66 | 0 | size_t i = 0, j = 0; |
67 | 0 | uint8_t bytesleft = binsz % sizeof(b58_almostmaxint_t); |
68 | 0 | b58_almostmaxint_t zeromask = |
69 | 0 | bytesleft ? (b58_almostmaxint_mask << (bytesleft * 8)) : 0; |
70 | 0 | unsigned zerocount = 0; |
71 | |
|
72 | 0 | size_t b58sz = strlen(b58); |
73 | |
|
74 | 0 | memzero(outi, sizeof(outi)); |
75 | | |
76 | | // Leading zeros, just count |
77 | 0 | for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount; |
78 | |
|
79 | 0 | for (; i < b58sz; ++i) { |
80 | 0 | if (b58u[i] & 0x80) |
81 | | // High-bit set on invalid digit |
82 | 0 | return false; |
83 | 0 | if (b58digits_map[b58u[i]] == -1) |
84 | | // Invalid base58 digit |
85 | 0 | return false; |
86 | 0 | c = (unsigned)b58digits_map[b58u[i]]; |
87 | 0 | for (j = outisz; j--;) { |
88 | 0 | t = ((b58_maxint_t)outi[j]) * 58 + c; |
89 | 0 | c = t >> b58_almostmaxint_bits; |
90 | 0 | outi[j] = t & b58_almostmaxint_mask; |
91 | 0 | } |
92 | 0 | if (c) |
93 | | // Output number too big (carry to the next int32) |
94 | 0 | return false; |
95 | 0 | if (outi[0] & zeromask) |
96 | | // Output number too big (last int32 filled too far) |
97 | 0 | return false; |
98 | 0 | } |
99 | | |
100 | 0 | j = 0; |
101 | 0 | if (bytesleft) { |
102 | 0 | for (i = bytesleft; i > 0; --i) { |
103 | 0 | *(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff; |
104 | 0 | } |
105 | 0 | ++j; |
106 | 0 | } |
107 | |
|
108 | 0 | for (; j < outisz; ++j) { |
109 | 0 | for (i = sizeof(*outi); i > 0; --i) { |
110 | 0 | *(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff; |
111 | 0 | } |
112 | 0 | } |
113 | | |
114 | | // locate the most significant byte |
115 | 0 | binu = bin; |
116 | 0 | for (i = 0; i < binsz; ++i) { |
117 | 0 | if (binu[i]) break; |
118 | 0 | } |
119 | | |
120 | | // prepend the correct number of null-bytes |
121 | 0 | if (zerocount > i) { |
122 | | /* result too large */ |
123 | 0 | return false; |
124 | 0 | } |
125 | 0 | *binszp = binsz - i + zerocount; |
126 | |
|
127 | 0 | return true; |
128 | 0 | } |
129 | | |
130 | | int b58check(const void *bin, size_t binsz, HasherType hasher_type, |
131 | 0 | const char *base58str) { |
132 | 0 | unsigned char buf[32] = {0}; |
133 | 0 | const uint8_t *binc = bin; |
134 | 0 | unsigned i = 0; |
135 | 0 | if (binsz < 4) return -4; |
136 | 0 | hasher_Raw(hasher_type, bin, binsz - 4, buf); |
137 | 0 | if (memcmp(&binc[binsz - 4], buf, 4)) return -1; |
138 | | |
139 | | // Check number of zeros is correct AFTER verifying checksum (to avoid |
140 | | // possibility of accessing base58str beyond the end) |
141 | 0 | for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { |
142 | 0 | } // Just finding the end of zeros, nothing to do in loop |
143 | 0 | if (binc[i] == '\0' || base58str[i] == '1') return -3; |
144 | | |
145 | 0 | return binc[0]; |
146 | 0 | } |
147 | | |
148 | 0 | bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { |
149 | 0 | const uint8_t *bin = data; |
150 | 0 | int carry = 0; |
151 | 0 | size_t i = 0, j = 0, high = 0, zcount = 0; |
152 | 0 | size_t size = 0; |
153 | |
|
154 | 0 | while (zcount < binsz && !bin[zcount]) ++zcount; |
155 | |
|
156 | 0 | size = (binsz - zcount) * 138 / 100 + 1; |
157 | 0 | uint8_t buf[size]; |
158 | 0 | memzero(buf, size); |
159 | |
|
160 | 0 | for (i = zcount, high = size - 1; i < binsz; ++i, high = j) { |
161 | 0 | for (carry = bin[i], j = size - 1; (j > high) || carry; --j) { |
162 | 0 | carry += 256 * buf[j]; |
163 | 0 | buf[j] = carry % 58; |
164 | 0 | carry /= 58; |
165 | 0 | if (!j) { |
166 | | // Otherwise j wraps to maxint which is > high |
167 | 0 | break; |
168 | 0 | } |
169 | 0 | } |
170 | 0 | } |
171 | |
|
172 | 0 | for (j = 0; j < size && !buf[j]; ++j) |
173 | 0 | ; |
174 | |
|
175 | 0 | if (*b58sz <= zcount + size - j) { |
176 | 0 | *b58sz = zcount + size - j + 1; |
177 | 0 | return false; |
178 | 0 | } |
179 | | |
180 | 0 | if (zcount) memset(b58, '1', zcount); |
181 | 0 | for (i = zcount; j < size; ++i, ++j) b58[i] = b58digits_ordered[buf[j]]; |
182 | 0 | b58[i] = '\0'; |
183 | 0 | *b58sz = i + 1; |
184 | |
|
185 | 0 | return true; |
186 | 0 | } |
187 | | |
188 | | int base58_encode_check(const uint8_t *data, int datalen, |
189 | 0 | HasherType hasher_type, char *str, int strsize) { |
190 | 0 | if (datalen > 128) { |
191 | 0 | return 0; |
192 | 0 | } |
193 | 0 | uint8_t buf[datalen + 32]; |
194 | 0 | memset(buf, 0, sizeof(buf)); |
195 | 0 | uint8_t *hash = buf + datalen; |
196 | 0 | memcpy(buf, data, datalen); |
197 | 0 | hasher_Raw(hasher_type, data, datalen, hash); |
198 | 0 | size_t res = strsize; |
199 | 0 | bool success = b58enc(str, &res, buf, datalen + 4); |
200 | 0 | memzero(buf, sizeof(buf)); |
201 | 0 | return success ? res : 0; |
202 | 0 | } |
203 | | |
204 | | int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, |
205 | 0 | int datalen) { |
206 | 0 | if (datalen > 128) { |
207 | 0 | return 0; |
208 | 0 | } |
209 | 0 | uint8_t d[datalen + 4]; |
210 | 0 | memset(d, 0, sizeof(d)); |
211 | 0 | size_t res = datalen + 4; |
212 | 0 | if (b58tobin(d, &res, str) != true) { |
213 | 0 | return 0; |
214 | 0 | } |
215 | 0 | uint8_t *nd = d + datalen + 4 - res; |
216 | 0 | if (b58check(nd, res, hasher_type, str) < 0) { |
217 | 0 | return 0; |
218 | 0 | } |
219 | 0 | memcpy(data, nd, res - 4); |
220 | 0 | return res - 4; |
221 | 0 | } |