/src/gdal/port/cpl_sha256.cpp
Line | Count | Source |
1 | | /* CPL_SHA256* functions derived from |
2 | | * http://code.google.com/p/ulib/source/browse/trunk/src/base/sha256sum.c?r=39 |
3 | | */ |
4 | | |
5 | | /* The MIT License |
6 | | |
7 | | Copyright (C) 2011 Zilong Tan (tzlloch@gmail.com) |
8 | | Copyright (C) 2015 Even Rouault <even.rouault at spatialys.com> |
9 | | |
10 | | Permission is hereby granted, free of charge, to any person obtaining |
11 | | a copy of this software and associated documentation files (the |
12 | | "Software"), to deal in the Software without restriction, including |
13 | | without limitation the rights to use, copy, modify, merge, publish, |
14 | | distribute, sublicense, and/or sell copies of the Software, and to |
15 | | permit persons to whom the Software is furnished to do so, subject to |
16 | | the following conditions: |
17 | | |
18 | | The above copyright notice and this permission notice shall be |
19 | | included in all copies or substantial portions of the Software. |
20 | | |
21 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
22 | | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
23 | | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
24 | | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
25 | | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
26 | | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
27 | | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
28 | | SOFTWARE. |
29 | | */ |
30 | | |
31 | | /* |
32 | | * Original code (for SHA256 computation only) is derived from the author: |
33 | | * Allan Saddi |
34 | | */ |
35 | | |
36 | | #include <string.h> |
37 | | #include "cpl_conv.h" |
38 | | #include "cpl_error.h" |
39 | | #include "cpl_sha256.h" |
40 | | #include "cpl_string.h" |
41 | | |
42 | 11.8M | #define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) |
43 | 430M | #define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) |
44 | | |
45 | 46.5M | #define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) |
46 | 46.5M | #define Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) |
47 | 46.5M | #define SIGMA0(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22)) |
48 | 46.5M | #define SIGMA1(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25)) |
49 | 34.9M | #define sigma0(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ ((x) >> 3)) |
50 | 34.9M | #define sigma1(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ ((x) >> 10)) |
51 | | |
52 | | #define DO_ROUND() \ |
53 | 46.5M | { \ |
54 | 46.5M | GUInt32 t1 = h + SIGMA1(e) + Ch(e, f, g) + *(Kp++) + *(W++); \ |
55 | 46.5M | GUInt32 t2 = SIGMA0(a) + Maj(a, b, c); \ |
56 | 46.5M | h = g; \ |
57 | 46.5M | g = f; \ |
58 | 46.5M | f = e; \ |
59 | 46.5M | e = d + t1; \ |
60 | 46.5M | d = c; \ |
61 | 46.5M | c = b; \ |
62 | 46.5M | b = a; \ |
63 | 46.5M | a = t1 + t2; \ |
64 | 46.5M | } |
65 | | |
66 | | constexpr GUInt32 K[64] = { |
67 | | 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, |
68 | | 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0xd807aa98U, 0x12835b01U, |
69 | | 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, |
70 | | 0xc19bf174U, 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, |
71 | | 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, 0x983e5152U, |
72 | | 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U, |
73 | | 0x06ca6351U, 0x14292967U, 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU, |
74 | | 0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U, |
75 | | 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, |
76 | | 0xd6990624U, 0xf40e3585U, 0x106aa070U, 0x19a4c116U, 0x1e376c08U, |
77 | | 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, |
78 | | 0x682e6ff3U, 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, |
79 | | 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U}; |
80 | | |
81 | | #ifdef WORDS_BIGENDIAN |
82 | | |
83 | | #define BYTESWAP(x) (x) |
84 | | #define BYTESWAP64(x) (x) |
85 | | |
86 | | #else // WORDS_BIGENDIAN |
87 | | |
88 | | #define BYTESWAP(x) \ |
89 | 11.8M | ((ROTR((x), 8) & 0xff00ff00U) | (ROTL((x), 8) & 0x00ff00ffU)) |
90 | 16.6k | #define BYTESWAP64(x) _byteswap64(x) |
91 | | |
92 | | static inline GUInt64 _byteswap64(GUInt64 x) |
93 | 16.6k | { |
94 | 16.6k | GUInt32 a = static_cast<GUInt32>(x >> 32); |
95 | 16.6k | GUInt32 b = static_cast<GUInt32>(x); |
96 | 16.6k | return (static_cast<GUInt64>(BYTESWAP(b)) << 32) | |
97 | 16.6k | static_cast<GUInt64>(BYTESWAP(a)); |
98 | 16.6k | } |
99 | | |
100 | | #endif /* !(WORDS_BIGENDIAN) */ |
101 | | |
102 | | constexpr GByte padding[64] = { |
103 | | 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
104 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
105 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
106 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
107 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
108 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
109 | | |
110 | | void CPL_SHA256Init(CPL_SHA256Context *sc) |
111 | 16.6k | { |
112 | 16.6k | sc->totalLength = 0; |
113 | 16.6k | sc->hash[0] = 0x6a09e667U; |
114 | 16.6k | sc->hash[1] = 0xbb67ae85U; |
115 | 16.6k | sc->hash[2] = 0x3c6ef372U; |
116 | 16.6k | sc->hash[3] = 0xa54ff53aU; |
117 | 16.6k | sc->hash[4] = 0x510e527fU; |
118 | 16.6k | sc->hash[5] = 0x9b05688cU; |
119 | 16.6k | sc->hash[6] = 0x1f83d9abU; |
120 | 16.6k | sc->hash[7] = 0x5be0cd19U; |
121 | 16.6k | sc->bufferLength = 0U; |
122 | 16.6k | } |
123 | | |
124 | | static GUInt32 burnStack(int size) |
125 | 107k | { |
126 | 107k | GByte buf[128]; |
127 | 107k | GUInt32 ret = 0; |
128 | | |
129 | 107k | memset(buf, static_cast<GByte>(size & 0xff), sizeof(buf)); |
130 | 13.8M | for (size_t i = 0; i < sizeof(buf); i++) |
131 | 13.7M | ret += ret * buf[i]; |
132 | 107k | size -= static_cast<int>(sizeof(buf)); |
133 | 107k | if (size > 0) |
134 | 71.5k | ret += burnStack(size); |
135 | 107k | return ret; |
136 | 107k | } |
137 | | |
138 | | CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW |
139 | | static void CPL_SHA256Guts(CPL_SHA256Context *sc, const GUInt32 *cbuf) |
140 | 727k | { |
141 | 727k | GUInt32 buf[64] = {}; |
142 | | |
143 | 727k | GUInt32 *W = buf; |
144 | | |
145 | 12.3M | for (int i = 15; i >= 0; i--) |
146 | 11.6M | { |
147 | 11.6M | *(W++) = BYTESWAP(*cbuf); |
148 | 11.6M | cbuf++; |
149 | 11.6M | } |
150 | | |
151 | 727k | GUInt32 *W16 = &buf[0]; |
152 | 727k | GUInt32 *W15 = &buf[1]; |
153 | 727k | GUInt32 *W7 = &buf[9]; |
154 | 727k | GUInt32 *W2 = &buf[14]; |
155 | | |
156 | 35.6M | for (int i = 47; i >= 0; i--) |
157 | 34.9M | { |
158 | 34.9M | *(W++) = sigma1(*W2) + *(W7++) + sigma0(*W15) + *(W16++); |
159 | 34.9M | W2++; |
160 | 34.9M | W15++; |
161 | 34.9M | } |
162 | | |
163 | 727k | GUInt32 a = sc->hash[0]; |
164 | 727k | GUInt32 b = sc->hash[1]; |
165 | 727k | GUInt32 c = sc->hash[2]; |
166 | 727k | GUInt32 d = sc->hash[3]; |
167 | 727k | GUInt32 e = sc->hash[4]; |
168 | 727k | GUInt32 f = sc->hash[5]; |
169 | 727k | GUInt32 g = sc->hash[6]; |
170 | 727k | GUInt32 h = sc->hash[7]; |
171 | | |
172 | 727k | const GUInt32 *Kp = K; |
173 | 727k | W = buf; |
174 | | |
175 | 727k | #ifndef CPL_SHA256_UNROLL |
176 | 727k | #define CPL_SHA256_UNROLL 1 |
177 | 727k | #endif /* !CPL_SHA256_UNROLL */ |
178 | | |
179 | 727k | #if CPL_SHA256_UNROLL == 1 |
180 | 47.2M | for (int i = 63; i >= 0; i--) |
181 | 46.5M | DO_ROUND(); |
182 | | #elif CPL_SHA256_UNROLL == 2 |
183 | | for (int i = 31; i >= 0; i--) |
184 | | { |
185 | | DO_ROUND(); |
186 | | DO_ROUND(); |
187 | | } |
188 | | #elif CPL_SHA256_UNROLL == 4 |
189 | | for (int i = 15; i >= 0; i--) |
190 | | { |
191 | | DO_ROUND(); |
192 | | DO_ROUND(); |
193 | | DO_ROUND(); |
194 | | DO_ROUND(); |
195 | | } |
196 | | #elif CPL_SHA256_UNROLL == 8 |
197 | | for (int i = 7; i >= 0; i--) |
198 | | { |
199 | | DO_ROUND(); |
200 | | DO_ROUND(); |
201 | | DO_ROUND(); |
202 | | DO_ROUND(); |
203 | | DO_ROUND(); |
204 | | DO_ROUND(); |
205 | | DO_ROUND(); |
206 | | DO_ROUND(); |
207 | | } |
208 | | #elif CPL_SHA256_UNROLL == 16 |
209 | | for (int i = 3; i >= 0; i--) |
210 | | { |
211 | | DO_ROUND(); |
212 | | DO_ROUND(); |
213 | | DO_ROUND(); |
214 | | DO_ROUND(); |
215 | | DO_ROUND(); |
216 | | DO_ROUND(); |
217 | | DO_ROUND(); |
218 | | DO_ROUND(); |
219 | | DO_ROUND(); |
220 | | DO_ROUND(); |
221 | | DO_ROUND(); |
222 | | DO_ROUND(); |
223 | | DO_ROUND(); |
224 | | DO_ROUND(); |
225 | | DO_ROUND(); |
226 | | DO_ROUND(); |
227 | | } |
228 | | #elif CPL_SHA256_UNROLL == 32 |
229 | | for (int i = 1; i >= 0; i--) |
230 | | { |
231 | | DO_ROUND(); |
232 | | DO_ROUND(); |
233 | | DO_ROUND(); |
234 | | DO_ROUND(); |
235 | | DO_ROUND(); |
236 | | DO_ROUND(); |
237 | | DO_ROUND(); |
238 | | DO_ROUND(); |
239 | | DO_ROUND(); |
240 | | DO_ROUND(); |
241 | | DO_ROUND(); |
242 | | DO_ROUND(); |
243 | | DO_ROUND(); |
244 | | DO_ROUND(); |
245 | | DO_ROUND(); |
246 | | DO_ROUND(); |
247 | | DO_ROUND(); |
248 | | DO_ROUND(); |
249 | | DO_ROUND(); |
250 | | DO_ROUND(); |
251 | | DO_ROUND(); |
252 | | DO_ROUND(); |
253 | | DO_ROUND(); |
254 | | DO_ROUND(); |
255 | | DO_ROUND(); |
256 | | DO_ROUND(); |
257 | | DO_ROUND(); |
258 | | DO_ROUND(); |
259 | | DO_ROUND(); |
260 | | DO_ROUND(); |
261 | | DO_ROUND(); |
262 | | DO_ROUND(); |
263 | | } |
264 | | #elif CPL_SHA256_UNROLL == 64 |
265 | | DO_ROUND(); |
266 | | DO_ROUND(); |
267 | | DO_ROUND(); |
268 | | DO_ROUND(); |
269 | | DO_ROUND(); |
270 | | DO_ROUND(); |
271 | | DO_ROUND(); |
272 | | DO_ROUND(); |
273 | | DO_ROUND(); |
274 | | DO_ROUND(); |
275 | | DO_ROUND(); |
276 | | DO_ROUND(); |
277 | | DO_ROUND(); |
278 | | DO_ROUND(); |
279 | | DO_ROUND(); |
280 | | DO_ROUND(); |
281 | | DO_ROUND(); |
282 | | DO_ROUND(); |
283 | | DO_ROUND(); |
284 | | DO_ROUND(); |
285 | | DO_ROUND(); |
286 | | DO_ROUND(); |
287 | | DO_ROUND(); |
288 | | DO_ROUND(); |
289 | | DO_ROUND(); |
290 | | DO_ROUND(); |
291 | | DO_ROUND(); |
292 | | DO_ROUND(); |
293 | | DO_ROUND(); |
294 | | DO_ROUND(); |
295 | | DO_ROUND(); |
296 | | DO_ROUND(); |
297 | | DO_ROUND(); |
298 | | DO_ROUND(); |
299 | | DO_ROUND(); |
300 | | DO_ROUND(); |
301 | | DO_ROUND(); |
302 | | DO_ROUND(); |
303 | | DO_ROUND(); |
304 | | DO_ROUND(); |
305 | | DO_ROUND(); |
306 | | DO_ROUND(); |
307 | | DO_ROUND(); |
308 | | DO_ROUND(); |
309 | | DO_ROUND(); |
310 | | DO_ROUND(); |
311 | | DO_ROUND(); |
312 | | DO_ROUND(); |
313 | | DO_ROUND(); |
314 | | DO_ROUND(); |
315 | | DO_ROUND(); |
316 | | DO_ROUND(); |
317 | | DO_ROUND(); |
318 | | DO_ROUND(); |
319 | | DO_ROUND(); |
320 | | DO_ROUND(); |
321 | | DO_ROUND(); |
322 | | DO_ROUND(); |
323 | | DO_ROUND(); |
324 | | DO_ROUND(); |
325 | | DO_ROUND(); |
326 | | DO_ROUND(); |
327 | | DO_ROUND(); |
328 | | DO_ROUND(); |
329 | | #else |
330 | | #error "CPL_SHA256_UNROLL must be 1, 2, 4, 8, 16, 32, or 64!" |
331 | | #endif |
332 | | |
333 | 727k | sc->hash[0] += a; |
334 | 727k | sc->hash[1] += b; |
335 | 727k | sc->hash[2] += c; |
336 | 727k | sc->hash[3] += d; |
337 | 727k | sc->hash[4] += e; |
338 | 727k | sc->hash[5] += f; |
339 | 727k | sc->hash[6] += g; |
340 | 727k | sc->hash[7] += h; |
341 | 727k | } |
342 | | |
343 | | void CPL_SHA256Update(CPL_SHA256Context *sc, const void *data, size_t len) |
344 | 51.9k | { |
345 | 51.9k | int needBurn = 0; |
346 | | |
347 | 51.9k | if (sc->bufferLength) |
348 | 33.8k | { |
349 | 33.8k | const GUInt32 bufferBytesLeft = 64U - sc->bufferLength; |
350 | | |
351 | 33.8k | GUInt32 bytesToCopy = bufferBytesLeft; |
352 | 33.8k | if (bytesToCopy > len) |
353 | 14.6k | bytesToCopy = static_cast<GUInt32>(len); |
354 | | |
355 | 33.8k | memcpy(&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy); |
356 | | |
357 | 33.8k | sc->totalLength += bytesToCopy * 8U; |
358 | | |
359 | 33.8k | sc->bufferLength += bytesToCopy; |
360 | 33.8k | data = static_cast<const GByte *>(data) + bytesToCopy; |
361 | 33.8k | len -= bytesToCopy; |
362 | | |
363 | 33.8k | if (sc->bufferLength == 64U) |
364 | 19.1k | { |
365 | 19.1k | CPL_SHA256Guts(sc, sc->buffer.words); |
366 | 19.1k | needBurn = 1; |
367 | 19.1k | sc->bufferLength = 0U; |
368 | 19.1k | } |
369 | 33.8k | } |
370 | | |
371 | 760k | while (len > 63U) |
372 | 708k | { |
373 | 708k | sc->totalLength += 512U; |
374 | | |
375 | 708k | CPL_SHA256Guts(sc, static_cast<const GUInt32 *>(data)); |
376 | 708k | needBurn = 1; |
377 | | |
378 | 708k | data = static_cast<const GByte *>(data) + 64U; |
379 | 708k | len -= 64U; |
380 | 708k | } |
381 | | |
382 | 51.9k | if (len) |
383 | 19.1k | { |
384 | 19.1k | memcpy(&sc->buffer.bytes[sc->bufferLength], data, len); |
385 | | |
386 | 19.1k | sc->totalLength += static_cast<GUInt32>(len) * 8U; |
387 | | |
388 | 19.1k | sc->bufferLength += static_cast<GUInt32>(len); |
389 | 19.1k | } |
390 | | |
391 | 51.9k | if (needBurn) |
392 | 35.7k | { |
393 | | // Clean stack state of CPL_SHA256Guts() |
394 | | |
395 | | // We add dummy side effects to avoid burnStack() to be |
396 | | // optimized away (#6157). |
397 | 35.7k | static GUInt32 accumulator = 0; |
398 | 35.7k | accumulator += burnStack( |
399 | 35.7k | static_cast<int>(sizeof(GUInt32[74]) + sizeof(GUInt32 *[6]) + |
400 | 35.7k | sizeof(int) + ((len % 2) ? sizeof(int) : 0))); |
401 | 35.7k | if (accumulator == 0xDEADBEEF) |
402 | 0 | fprintf(stderr, "%s", ""); /*ok*/ |
403 | 35.7k | } |
404 | 51.9k | } |
405 | | |
406 | | void CPL_SHA256Final(CPL_SHA256Context *sc, GByte hash[CPL_SHA256_HASH_SIZE]) |
407 | 16.6k | { |
408 | 16.6k | GUInt32 bytesToPad = 120U - sc->bufferLength; |
409 | 16.6k | if (bytesToPad > 64U) |
410 | 14.3k | bytesToPad -= 64U; |
411 | | |
412 | 16.6k | const GUInt64 lengthPad = BYTESWAP64(sc->totalLength); |
413 | | |
414 | 16.6k | CPL_SHA256Update(sc, padding, bytesToPad); |
415 | 16.6k | CPL_SHA256Update(sc, &lengthPad, 8U); |
416 | | |
417 | 16.6k | if (hash) |
418 | 16.6k | { |
419 | 150k | for (int i = 0; i < CPL_SHA256_HASH_WORDS; i++) |
420 | 133k | { |
421 | 133k | *reinterpret_cast<GUInt32 *>(hash) = BYTESWAP(sc->hash[i]); |
422 | 133k | hash += 4; |
423 | 133k | } |
424 | 16.6k | } |
425 | 16.6k | } |
426 | | |
427 | | void CPL_SHA256(const void *data, size_t len, GByte hash[CPL_SHA256_HASH_SIZE]) |
428 | 14.6k | { |
429 | 14.6k | CPL_SHA256Context sSHA256Ctxt; |
430 | 14.6k | CPL_SHA256Init(&sSHA256Ctxt); |
431 | 14.6k | CPL_SHA256Update(&sSHA256Ctxt, data, len); |
432 | 14.6k | CPL_SHA256Final(&sSHA256Ctxt, hash); |
433 | 14.6k | memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt)); |
434 | 14.6k | } |
435 | | |
436 | 0 | #define CPL_HMAC_SHA256_BLOCKSIZE 64U |
437 | | |
438 | | // See |
439 | | // https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Implementation |
440 | | void CPL_HMAC_SHA256(const void *pKey, size_t nKeyLen, const void *pabyMessage, |
441 | | size_t nMessageLen, GByte abyDigest[CPL_SHA256_HASH_SIZE]) |
442 | 0 | { |
443 | 0 | GByte abyPad[CPL_HMAC_SHA256_BLOCKSIZE] = {}; |
444 | 0 | if (nKeyLen > CPL_HMAC_SHA256_BLOCKSIZE) |
445 | 0 | { |
446 | 0 | CPL_SHA256(pKey, nKeyLen, abyPad); |
447 | 0 | } |
448 | 0 | else |
449 | 0 | { |
450 | 0 | memcpy(abyPad, pKey, nKeyLen); |
451 | 0 | } |
452 | | |
453 | | // Compute ipad. |
454 | 0 | for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++) |
455 | 0 | abyPad[i] = 0x36 ^ abyPad[i]; |
456 | |
|
457 | 0 | CPL_SHA256Context sSHA256Ctxt; |
458 | 0 | CPL_SHA256Init(&sSHA256Ctxt); |
459 | 0 | CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE); |
460 | 0 | CPL_SHA256Update(&sSHA256Ctxt, pabyMessage, nMessageLen); |
461 | 0 | CPL_SHA256Final(&sSHA256Ctxt, abyDigest); |
462 | | |
463 | | // Compute opad. |
464 | 0 | for (size_t i = 0; i < CPL_HMAC_SHA256_BLOCKSIZE; i++) |
465 | 0 | abyPad[i] = (0x36 ^ 0x5C) ^ abyPad[i]; |
466 | |
|
467 | 0 | CPL_SHA256Init(&sSHA256Ctxt); |
468 | 0 | CPL_SHA256Update(&sSHA256Ctxt, abyPad, CPL_HMAC_SHA256_BLOCKSIZE); |
469 | 0 | CPL_SHA256Update(&sSHA256Ctxt, abyDigest, CPL_SHA256_HASH_SIZE); |
470 | 0 | CPL_SHA256Final(&sSHA256Ctxt, abyDigest); |
471 | |
|
472 | 0 | memset(&sSHA256Ctxt, 0, sizeof(sSHA256Ctxt)); |
473 | 0 | memset(abyPad, 0, CPL_HMAC_SHA256_BLOCKSIZE); |
474 | 0 | } |
475 | | |
476 | | #ifdef HAVE_CRYPTOPP |
477 | | |
478 | | /* Begin of crypto++ headers */ |
479 | | #ifdef _MSC_VER |
480 | | #pragma warning(push) |
481 | | #pragma warning(disable : 4189) |
482 | | #pragma warning(disable : 4512) |
483 | | #pragma warning(disable : 4244) |
484 | | #endif |
485 | | |
486 | | #ifdef __GNUC__ |
487 | | #pragma GCC diagnostic push |
488 | | #pragma GCC diagnostic ignored "-Weffc++" |
489 | | #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" |
490 | | #pragma GCC diagnostic ignored "-Wold-style-cast" |
491 | | #pragma GCC diagnostic ignored "-Wshadow" |
492 | | #endif |
493 | | |
494 | | #ifdef USE_ONLY_CRYPTODLL_ALG |
495 | | #include "cryptopp/dll.h" |
496 | | #else |
497 | | #include "cryptopp/rsa.h" |
498 | | #include "cryptopp/queue.h" |
499 | | #endif |
500 | | |
501 | | #include "cryptopp/base64.h" |
502 | | #include "cryptopp/osrng.h" |
503 | | |
504 | | // Fix compatibility with Crypto++ |
505 | | #if CRYPTOPP_VERSION >= 600 |
506 | | typedef CryptoPP::byte cryptopp_byte; |
507 | | #else |
508 | | typedef byte cryptopp_byte; |
509 | | #endif |
510 | | |
511 | | #ifdef __GNUC__ |
512 | | #pragma GCC diagnostic pop |
513 | | #endif |
514 | | |
515 | | #ifdef _MSC_VER |
516 | | #pragma warning(pop) |
517 | | #endif |
518 | | |
519 | | #endif // HAVE_CRYPTOPP |
520 | | |
521 | | #ifdef HAVE_OPENSSL_CRYPTO |
522 | | |
523 | | #if defined(__GNUC__) |
524 | | #pragma GCC diagnostic push |
525 | | #pragma GCC diagnostic ignored "-Wold-style-cast" |
526 | | #ifdef HAVE_WFLAG_CAST_FUNCTION_TYPE |
527 | | #pragma GCC diagnostic ignored "-Wcast-function-type" |
528 | | #endif |
529 | | #endif |
530 | | |
531 | | #include <openssl/bio.h> |
532 | | #include <openssl/evp.h> |
533 | | #include <openssl/pem.h> |
534 | | |
535 | | #if defined(__GNUC__) |
536 | | #pragma GCC diagnostic pop |
537 | | #endif |
538 | | |
539 | | #endif |
540 | | |
541 | | /************************************************************************/ |
542 | | /* CPLOpenSSLNullPassphraseCallback() */ |
543 | | /************************************************************************/ |
544 | | |
545 | | #if defined(HAVE_OPENSSL_CRYPTO) |
546 | | static int CPLOpenSSLNullPassphraseCallback(char * /*buf*/, int /*size*/, |
547 | | int /*rwflag*/, void * /*u*/) |
548 | 0 | { |
549 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
550 | 0 | "A passphrase was required for this private key, " |
551 | 0 | "but this is not supported"); |
552 | 0 | return 0; |
553 | 0 | } |
554 | | |
555 | | #endif |
556 | | |
557 | | /************************************************************************/ |
558 | | /* CPL_RSA_SHA256_Sign() */ |
559 | | /************************************************************************/ |
560 | | |
561 | | GByte *CPL_RSA_SHA256_Sign(const char *pszPrivateKey, const void *pabyData, |
562 | | unsigned int nDataLen, unsigned int *pnSignatureLen) |
563 | 0 | { |
564 | 0 | *pnSignatureLen = 0; |
565 | |
|
566 | | #ifdef HAVE_CRYPTOPP |
567 | | if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "CRYPTOPP"), |
568 | | "CRYPTOPP")) |
569 | | { |
570 | | // See https://www.cryptopp.com/wiki/RSA_Cryptography |
571 | | // https://www.cryptopp.com/wiki/RSA_Signature_Schemes#RSA_Signature_Scheme_.28PKCS_v1.5.29 |
572 | | // https://www.cryptopp.com/wiki/Keys_and_Formats#PEM_Encoded_Keys |
573 | | |
574 | | CPLString osRSAPrivKey(pszPrivateKey); |
575 | | static std::string HEADER = "-----BEGIN PRIVATE KEY-----"; |
576 | | static std::string HEADER_RSA = "-----BEGIN RSA PRIVATE KEY-----"; |
577 | | static std::string HEADER_ENCRYPTED = |
578 | | "-----BEGIN ENCRYPTED PRIVATE KEY-----"; |
579 | | static std::string FOOTER = "-----END PRIVATE KEY-----"; |
580 | | |
581 | | size_t pos1, pos2; |
582 | | pos1 = osRSAPrivKey.find(HEADER); |
583 | | if (pos1 == std::string::npos) |
584 | | { |
585 | | if (osRSAPrivKey.find(HEADER_RSA) != std::string::npos) |
586 | | { |
587 | | CPLError(CE_Failure, CPLE_AppDefined, |
588 | | "'Traditional' PEM header found, whereas PKCS#8 is " |
589 | | "expected. You can use for example " |
590 | | "'openssl pkcs8 -topk8 -inform pem -in file.key " |
591 | | "-outform pem -nocrypt -out file.pem' to generate " |
592 | | "a compatible PEM file"); |
593 | | } |
594 | | else if (osRSAPrivKey.find(HEADER_ENCRYPTED) != std::string::npos) |
595 | | { |
596 | | CPLError(CE_Failure, CPLE_AppDefined, |
597 | | "Encrypted PEM header found. Only PKCS#8 unencrypted " |
598 | | "private keys are supported"); |
599 | | } |
600 | | else |
601 | | { |
602 | | CPLError(CE_Failure, CPLE_AppDefined, "PEM header not found"); |
603 | | } |
604 | | return nullptr; |
605 | | } |
606 | | |
607 | | pos2 = osRSAPrivKey.find(FOOTER, pos1 + 1); |
608 | | if (pos2 == std::string::npos) |
609 | | { |
610 | | CPLError(CE_Failure, CPLE_AppDefined, "PEM footer not found"); |
611 | | return nullptr; |
612 | | } |
613 | | |
614 | | // Strip header and footer to get the base64-only portion |
615 | | pos1 = pos1 + HEADER.size(); |
616 | | std::string osKeyB64 = osRSAPrivKey.substr(pos1, pos2 - pos1); |
617 | | |
618 | | // Base64 decode, place in a ByteQueue |
619 | | CryptoPP::ByteQueue queue; |
620 | | CryptoPP::Base64Decoder decoder; |
621 | | |
622 | | decoder.Attach(new CryptoPP::Redirector(queue)); |
623 | | decoder.Put(reinterpret_cast<const cryptopp_byte *>(osKeyB64.data()), |
624 | | osKeyB64.length()); |
625 | | decoder.MessageEnd(); |
626 | | |
627 | | CryptoPP::RSA::PrivateKey rsaPrivate; |
628 | | try |
629 | | { |
630 | | rsaPrivate.BERDecode(queue); |
631 | | } |
632 | | catch (const std::exception &e) |
633 | | { |
634 | | CPLError(CE_Failure, CPLE_AppDefined, |
635 | | "Exception while decoding private key: %s", e.what()); |
636 | | return nullptr; |
637 | | } |
638 | | |
639 | | // Check that we have consumed all bytes. |
640 | | if (!queue.IsEmpty()) |
641 | | { |
642 | | CPLError(CE_Failure, CPLE_AppDefined, |
643 | | "Invalid private key: extraneous trailing bytes"); |
644 | | return nullptr; |
645 | | } |
646 | | |
647 | | CryptoPP::AutoSeededRandomPool prng; |
648 | | bool valid = rsaPrivate.Validate(prng, 3); |
649 | | if (!valid) |
650 | | { |
651 | | CPLError(CE_Failure, CPLE_AppDefined, |
652 | | "Invalid private key: validation failed"); |
653 | | return nullptr; |
654 | | } |
655 | | |
656 | | std::string signature; |
657 | | try |
658 | | { |
659 | | typedef CryptoPP::RSASS<CryptoPP::PKCS1v15, |
660 | | CryptoPP::SHA256>::Signer |
661 | | RSASSA_PKCS1v15_SHA256_Signer; |
662 | | RSASSA_PKCS1v15_SHA256_Signer signer(rsaPrivate); |
663 | | |
664 | | std::string message; |
665 | | message.assign(static_cast<const char *>(pabyData), nDataLen); |
666 | | |
667 | | CryptoPP::StringSource stringSource( |
668 | | message, true, |
669 | | new CryptoPP::SignerFilter( |
670 | | prng, signer, new CryptoPP::StringSink(signature))); |
671 | | } |
672 | | catch (const std::exception &e) |
673 | | { |
674 | | CPLError(CE_Failure, CPLE_AppDefined, "Exception while signing: %s", |
675 | | e.what()); |
676 | | return nullptr; |
677 | | } |
678 | | |
679 | | *pnSignatureLen = static_cast<unsigned int>(signature.size()); |
680 | | GByte *pabySignature = |
681 | | static_cast<GByte *>(CPLMalloc(signature.size())); |
682 | | memcpy(pabySignature, signature.c_str(), signature.size()); |
683 | | return pabySignature; |
684 | | } |
685 | | #endif |
686 | |
|
687 | 0 | #if defined(HAVE_OPENSSL_CRYPTO) |
688 | 0 | if (EQUAL(CPLGetConfigOption("CPL_RSA_SHA256_Sign", "OPENSSL"), "OPENSSL")) |
689 | 0 | { |
690 | 0 | const EVP_MD *digest = EVP_sha256(); |
691 | 0 | if (digest == nullptr) |
692 | 0 | { |
693 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "EVP_sha256() failed"); |
694 | 0 | return nullptr; |
695 | 0 | } |
696 | | |
697 | | // Old versions expect a void*, newer a const void* |
698 | 0 | BIO *bio = BIO_new_mem_buf( |
699 | 0 | const_cast<void *>(static_cast<const void *>(pszPrivateKey)), |
700 | 0 | static_cast<int>(strlen(pszPrivateKey))); |
701 | 0 | if (bio == nullptr) |
702 | 0 | { |
703 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "BIO_new_mem_buf() failed"); |
704 | 0 | return nullptr; |
705 | 0 | } |
706 | 0 | EVP_PKEY *pkey = PEM_read_bio_PrivateKey( |
707 | 0 | bio, nullptr, CPLOpenSSLNullPassphraseCallback, nullptr); |
708 | 0 | BIO_free(bio); |
709 | 0 | if (pkey == nullptr) |
710 | 0 | { |
711 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
712 | 0 | "PEM_read_bio_PrivateKey() failed"); |
713 | 0 | return nullptr; |
714 | 0 | } |
715 | 0 | EVP_MD_CTX *md_ctx = EVP_MD_CTX_create(); |
716 | 0 | CPLAssert(md_ctx != nullptr); |
717 | 0 | int ret = EVP_SignInit(md_ctx, digest); |
718 | 0 | CPLAssert(ret == 1); |
719 | 0 | ret = EVP_SignUpdate(md_ctx, pabyData, nDataLen); |
720 | 0 | CPLAssert(ret == 1); |
721 | 0 | const int nPKeyLength = EVP_PKEY_size(pkey); |
722 | 0 | CPLAssert(nPKeyLength > 0); |
723 | 0 | GByte *abyBuffer = static_cast<GByte *>(CPLMalloc(nPKeyLength)); |
724 | 0 | ret = EVP_SignFinal(md_ctx, abyBuffer, pnSignatureLen, pkey); |
725 | 0 | if (ret != 1) |
726 | 0 | { |
727 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "EVP_SignFinal() failed"); |
728 | 0 | EVP_MD_CTX_destroy(md_ctx); |
729 | 0 | EVP_PKEY_free(pkey); |
730 | 0 | CPLFree(abyBuffer); |
731 | 0 | return nullptr; |
732 | 0 | } |
733 | | |
734 | 0 | EVP_MD_CTX_destroy(md_ctx); |
735 | 0 | EVP_PKEY_free(pkey); |
736 | 0 | return abyBuffer; |
737 | 0 | } |
738 | 0 | #endif |
739 | | |
740 | 0 | CPL_IGNORE_RET_VAL(pszPrivateKey); |
741 | 0 | CPL_IGNORE_RET_VAL(pabyData); |
742 | 0 | CPL_IGNORE_RET_VAL(nDataLen); |
743 | |
|
744 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
745 | 0 | "CPLRSASHA256Sign() not implemented: " |
746 | 0 | "GDAL must be built against libcrypto++ or libcrypto (openssl)"); |
747 | 0 | return nullptr; |
748 | 0 | } |