2
* crypto.c : cryptographic routines
4
* ====================================================================
5
* Licensed to the Apache Software Foundation (ASF) under one
6
* or more contributor license agreements. See the NOTICE file
7
* distributed with this work for additional information
8
* regarding copyright ownership. The ASF licenses this file
9
* to you under the Apache License, Version 2.0 (the
10
* "License"); you may not use this file except in compliance
11
* with the License. You may obtain a copy of the License at
13
* http://www.apache.org/licenses/LICENSE-2.0
15
* Unless required by applicable law or agreed to in writing,
16
* software distributed under the License is distributed on an
17
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18
* KIND, either express or implied. See the License for the
19
* specific language governing permissions and limitations
21
* ====================================================================
26
#ifdef SVN_HAVE_CRYPTO
27
#include <apr_random.h>
28
#include <apr_crypto.h>
29
#endif /* SVN_HAVE_CRYPTO */
31
#include "svn_types.h"
32
#include "svn_checksum.h"
34
#include "svn_private_config.h"
35
#include "private/svn_atomic.h"
38
/* 1000 iterations is the recommended minimum, per RFC 2898, section 4.2. */
39
#define NUM_ITERATIONS 1000
42
/* Size (in bytes) of the random data we'll prepend to encrypted data. */
43
#define RANDOM_PREFIX_LEN 4
46
/* A structure for containing Subversion's cryptography-related bits
47
(so we can avoid passing around APR-isms outside this module). */
48
struct svn_crypto__ctx_t {
49
#ifdef SVN_HAVE_CRYPTO
50
apr_crypto_t *crypto; /* APR cryptography context. */
53
/* ### For now, we will use apr_generate_random_bytes(). If we need
54
### more strength, then we can set this member using
55
### apr_random_standard_new(), then use
56
### apr_generate_random_bytes() to generate entropy for seeding
57
### apr_random_t. See httpd/server/core.c:ap_init_rng() */
60
#else /* SVN_HAVE_CRYPTO */
61
int unused_but_required_to_satisfy_c_compilers;
62
#endif /* SVN_HAVE_CRYPTO */
67
/*** Helper Functions ***/
68
#ifdef SVN_HAVE_CRYPTO
71
/* One-time initialization of the cryptography subsystem. */
72
static volatile svn_atomic_t crypto_init_state = 0;
75
#define CRYPTO_INIT(scratch_pool) \
76
SVN_ERR(svn_atomic__init_once(&crypto_init_state, \
77
crypto_init, NULL, (scratch_pool)))
80
/* Initialize the APR cryptography subsystem (if available), using
81
ANY_POOL's ancestor root pool for the registration of cleanups,
83
/* Don't call this function directly! Use svn_atomic__init_once(). */
85
crypto_init(void *baton, apr_pool_t *any_pool)
87
/* NOTE: this function will locate the topmost ancestor of ANY_POOL
88
for its cleanup handlers. We don't have to worry about ANY_POOL
90
apr_status_t apr_err = apr_crypto_init(any_pool);
92
return svn_error_wrap_apr(apr_err,
93
_("Failed to initialize cryptography "
100
/* If APU_ERR is non-NULL, create and return a Subversion error using
101
APR_ERR and APU_ERR. */
103
err_from_apu_err(apr_status_t apr_err,
104
const apu_err_t *apu_err)
107
return svn_error_createf(apr_err, NULL,
108
_("code (%d), reason (\"%s\"), msg (\"%s\")"),
110
apu_err->reason ? apu_err->reason : "",
111
apu_err->msg ? apu_err->msg : "");
116
/* Generate a Subversion error which describes the state reflected by
117
APR_ERR and any crypto errors registered with CTX. */
119
crypto_error_create(svn_crypto__ctx_t *ctx,
120
apr_status_t apr_err,
123
const apu_err_t *apu_err;
124
apr_status_t rv = apr_crypto_error(&apu_err, ctx->crypto);
127
/* Ugh. The APIs are a bit slippery, so be wary. */
128
if (apr_err == APR_SUCCESS)
129
apr_err = APR_EGENERAL;
131
if (rv == APR_SUCCESS)
132
child = err_from_apu_err(apr_err, apu_err);
134
child = svn_error_wrap_apr(rv, _("Fetching error from APR"));
136
return svn_error_create(apr_err, child, msg);
140
/* Set RAND_BYTES to a block of bytes containing random data RAND_LEN
141
long and allocated from RESULT_POOL. */
143
get_random_bytes(const unsigned char **rand_bytes,
144
svn_crypto__ctx_t *ctx,
146
apr_pool_t *result_pool)
148
apr_status_t apr_err;
149
unsigned char *bytes;
151
bytes = apr_palloc(result_pool, rand_len);
152
apr_err = apr_generate_random_bytes(bytes, rand_len);
153
if (apr_err != APR_SUCCESS)
154
return svn_error_wrap_apr(apr_err, _("Error obtaining random data"));
161
/* Return an svn_string_t allocated from RESULT_POOL, with its .data
162
and .len members set to DATA and LEN, respective.
164
WARNING: No lifetime management of DATA is offered here, so you
165
probably want to ensure that that information is allocated in a
166
sufficiently long-lived pool (such as, for example, RESULT_POOL). */
167
static const svn_string_t *
168
wrap_as_string(const unsigned char *data,
170
apr_pool_t *result_pool)
172
svn_string_t *s = apr_palloc(result_pool, sizeof(*s));
174
s->data = (const char *)data; /* better already be in RESULT_POOL */
180
#endif /* SVN_HAVE_CRYPTO */
184
/*** Semi-public APIs ***/
186
/* Return TRUE iff Subversion's cryptographic support is available. */
187
svn_boolean_t svn_crypto__is_available(void)
189
#ifdef SVN_HAVE_CRYPTO
191
#else /* SVN_HAVE_CRYPTO */
193
#endif /* SVN_HAVE_CRYPTO */
197
/* Set CTX to a Subversion cryptography context allocated from
200
svn_crypto__context_create(svn_crypto__ctx_t **ctx,
201
apr_pool_t *result_pool)
203
#ifdef SVN_HAVE_CRYPTO
204
apr_status_t apr_err;
205
const apu_err_t *apu_err = NULL;
206
apr_crypto_t *apr_crypto;
207
const apr_crypto_driver_t *driver;
209
CRYPTO_INIT(result_pool);
211
/* Load the crypto driver.
213
### TODO: For the sake of flexibility, should we use
214
### APU_CRYPTO_RECOMMENDED_DRIVER instead of hard coding
217
NOTE: Potential bugs in get_driver() imply we might get
218
APR_SUCCESS and NULL. Sigh. Just be a little more careful in
219
error generation here. */
220
apr_err = apr_crypto_get_driver(&driver, "openssl", NULL, &apu_err,
222
if (apr_err != APR_SUCCESS)
223
return svn_error_create(apr_err, err_from_apu_err(apr_err, apu_err),
224
_("OpenSSL crypto driver error"));
226
return svn_error_create(APR_EGENERAL,
227
err_from_apu_err(APR_EGENERAL, apu_err),
228
_("Bad return value while loading crypto "
231
apr_err = apr_crypto_make(&apr_crypto, driver, NULL, result_pool);
232
if (apr_err != APR_SUCCESS || apr_crypto == NULL)
233
return svn_error_create(apr_err, NULL,
234
_("Error creating OpenSSL crypto context"));
236
/* Allocate and initialize our crypto context. */
237
*ctx = apr_palloc(result_pool, sizeof(**ctx));
238
(*ctx)->crypto = apr_crypto;
241
#else /* SVN_HAVE_CRYPTO */
242
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
243
"Cryptographic support is not available");
244
#endif /* SVN_HAVE_CRYPTO */
249
svn_crypto__encrypt_password(const svn_string_t **ciphertext,
250
const svn_string_t **iv,
251
const svn_string_t **salt,
252
svn_crypto__ctx_t *ctx,
253
const char *password,
254
const svn_string_t *master,
255
apr_pool_t *result_pool,
256
apr_pool_t *scratch_pool)
258
#ifdef SVN_HAVE_CRYPTO
259
svn_error_t *err = SVN_NO_ERROR;
260
const unsigned char *salt_vector;
261
const unsigned char *iv_vector;
263
apr_crypto_key_t *key = NULL;
264
apr_status_t apr_err;
265
const unsigned char *prefix;
266
apr_crypto_block_t *block_ctx = NULL;
267
apr_size_t block_size;
268
unsigned char *assembled;
269
apr_size_t password_len, assembled_len = 0;
270
apr_size_t result_len;
271
unsigned char *result;
272
apr_size_t ignored_result_len = 0;
274
SVN_ERR_ASSERT(ctx != NULL);
276
/* Generate the salt. */
278
SVN_ERR(get_random_bytes(&salt_vector, ctx, SALT_LEN, result_pool));
280
/* Initialize the passphrase. */
281
apr_err = apr_crypto_passphrase(&key, &iv_len,
282
master->data, master->len,
283
salt_vector, SALT_LEN,
284
APR_KEY_AES_256, APR_MODE_CBC,
285
FALSE /* doPad */, NUM_ITERATIONS,
288
if (apr_err != APR_SUCCESS)
289
return svn_error_trace(crypto_error_create(
291
_("Error creating derived key")));
293
return svn_error_create(APR_EGENERAL, NULL,
294
_("Error creating derived key"));
296
return svn_error_create(APR_EGENERAL, NULL,
297
_("Unexpected IV length returned"));
299
/* Generate the proper length IV. */
300
SVN_ERR(get_random_bytes(&iv_vector, ctx, iv_len, result_pool));
302
/* Initialize block encryption. */
303
apr_err = apr_crypto_block_encrypt_init(&block_ctx, &iv_vector, key,
304
&block_size, scratch_pool);
305
if ((apr_err != APR_SUCCESS) || (! block_ctx))
306
return svn_error_trace(crypto_error_create(
308
_("Error initializing block encryption")));
310
/* Generate a 4-byte prefix. */
311
SVN_ERR(get_random_bytes(&prefix, ctx, RANDOM_PREFIX_LEN, scratch_pool));
313
/* Combine our prefix, original password, and appropriate padding.
314
We won't bother padding if the prefix and password combined
315
perfectly align on the block boundary. If they don't,
316
however, we'll drop a NUL byte after the password and pad with
317
random stuff after that to the block boundary. */
318
password_len = strlen(password);
319
assembled_len = RANDOM_PREFIX_LEN + password_len;
320
if ((assembled_len % block_size) == 0)
322
assembled = apr_palloc(scratch_pool, assembled_len);
323
memcpy(assembled, prefix, RANDOM_PREFIX_LEN);
324
memcpy(assembled + RANDOM_PREFIX_LEN, password, password_len);
328
const unsigned char *padding;
329
apr_size_t pad_len = block_size - (assembled_len % block_size) - 1;
331
SVN_ERR(get_random_bytes(&padding, ctx, pad_len, scratch_pool));
332
assembled_len = assembled_len + 1 + pad_len;
333
assembled = apr_palloc(scratch_pool, assembled_len);
334
memcpy(assembled, prefix, RANDOM_PREFIX_LEN);
335
memcpy(assembled + RANDOM_PREFIX_LEN, password, password_len);
336
*(assembled + RANDOM_PREFIX_LEN + password_len) = '\0';
337
memcpy(assembled + RANDOM_PREFIX_LEN + password_len + 1,
341
/* Get the length that we need to allocate. */
342
apr_err = apr_crypto_block_encrypt(NULL, &result_len, assembled,
343
assembled_len, block_ctx);
344
if (apr_err != APR_SUCCESS)
346
err = crypto_error_create(ctx, apr_err,
347
_("Error fetching result length"));
351
/* Allocate our result buffer. */
352
result = apr_palloc(result_pool, result_len);
354
/* Encrypt the block. */
355
apr_err = apr_crypto_block_encrypt(&result, &result_len, assembled,
356
assembled_len, block_ctx);
357
if (apr_err != APR_SUCCESS)
359
err = crypto_error_create(ctx, apr_err,
360
_("Error during block encryption"));
364
/* Finalize the block encryption. Since we padded everything, this should
365
not produce any more encrypted output. */
366
apr_err = apr_crypto_block_encrypt_finish(NULL,
369
if (apr_err != APR_SUCCESS)
371
err = crypto_error_create(ctx, apr_err,
372
_("Error finalizing block encryption"));
376
*ciphertext = wrap_as_string(result, result_len, result_pool);
377
*iv = wrap_as_string(iv_vector, iv_len, result_pool);
378
*salt = wrap_as_string(salt_vector, SALT_LEN, result_pool);
381
apr_crypto_block_cleanup(block_ctx);
383
#else /* SVN_HAVE_CRYPTO */
384
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
385
"Cryptographic support is not available");
386
#endif /* SVN_HAVE_CRYPTO */
391
svn_crypto__decrypt_password(const char **plaintext,
392
svn_crypto__ctx_t *ctx,
393
const svn_string_t *ciphertext,
394
const svn_string_t *iv,
395
const svn_string_t *salt,
396
const svn_string_t *master,
397
apr_pool_t *result_pool,
398
apr_pool_t *scratch_pool)
400
#ifdef SVN_HAVE_CRYPTO
401
svn_error_t *err = SVN_NO_ERROR;
402
apr_status_t apr_err;
403
apr_crypto_block_t *block_ctx = NULL;
404
apr_size_t block_size, iv_len;
405
apr_crypto_key_t *key = NULL;
406
unsigned char *result;
407
apr_size_t result_len = 0, final_len = 0;
409
/* Initialize the passphrase. */
410
apr_err = apr_crypto_passphrase(&key, &iv_len,
411
master->data, master->len,
412
(unsigned char *)salt->data, salt->len,
413
APR_KEY_AES_256, APR_MODE_CBC,
414
FALSE /* doPad */, NUM_ITERATIONS,
415
ctx->crypto, scratch_pool);
416
if (apr_err != APR_SUCCESS)
417
return svn_error_trace(crypto_error_create(
419
_("Error creating derived key")));
421
return svn_error_create(APR_EGENERAL, NULL,
422
_("Error creating derived key"));
424
return svn_error_create(APR_EGENERAL, NULL,
425
_("Unexpected IV length returned"));
426
if (iv_len != iv->len)
427
return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
428
_("Provided IV has incorrect length"));
430
apr_err = apr_crypto_block_decrypt_init(&block_ctx, &block_size,
431
(unsigned char *)iv->data,
433
if ((apr_err != APR_SUCCESS) || (! block_ctx))
434
return svn_error_trace(crypto_error_create(
436
_("Error initializing block decryption")));
438
apr_err = apr_crypto_block_decrypt(NULL, &result_len,
439
(unsigned char *)ciphertext->data,
440
ciphertext->len, block_ctx);
441
if (apr_err != APR_SUCCESS)
443
err = crypto_error_create(ctx, apr_err,
444
_("Error fetching result length"));
448
result = apr_palloc(scratch_pool, result_len);
449
apr_err = apr_crypto_block_decrypt(&result, &result_len,
450
(unsigned char *)ciphertext->data,
451
ciphertext->len, block_ctx);
452
if (apr_err != APR_SUCCESS)
454
err = crypto_error_create(ctx, apr_err,
455
_("Error during block decryption"));
459
apr_err = apr_crypto_block_decrypt_finish(result + result_len, &final_len,
461
if (apr_err != APR_SUCCESS)
463
err = crypto_error_create(ctx, apr_err,
464
_("Error finalizing block decryption"));
468
/* Copy the non-random bits of the resulting plaintext, skipping the
469
prefix and ignoring any trailing padding. */
470
*plaintext = apr_pstrndup(result_pool,
471
(const char *)(result + RANDOM_PREFIX_LEN),
472
result_len + final_len - RANDOM_PREFIX_LEN);
475
apr_crypto_block_cleanup(block_ctx);
477
#else /* SVN_HAVE_CRYPTO */
478
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
479
"Cryptographic support is not available");
480
#endif /* SVN_HAVE_CRYPTO */
485
svn_crypto__generate_secret_checktext(const svn_string_t **ciphertext,
486
const svn_string_t **iv,
487
const svn_string_t **salt,
488
const char **checktext,
489
svn_crypto__ctx_t *ctx,
490
const svn_string_t *master,
491
apr_pool_t *result_pool,
492
apr_pool_t *scratch_pool)
494
#ifdef SVN_HAVE_CRYPTO
495
svn_error_t *err = SVN_NO_ERROR;
496
const unsigned char *salt_vector;
497
const unsigned char *iv_vector;
498
const unsigned char *stuff_vector;
500
apr_crypto_key_t *key = NULL;
501
apr_status_t apr_err;
502
apr_crypto_block_t *block_ctx = NULL;
503
apr_size_t block_size;
504
apr_size_t result_len;
505
unsigned char *result;
506
apr_size_t ignored_result_len = 0;
507
apr_size_t stuff_len;
508
svn_checksum_t *stuff_sum;
510
SVN_ERR_ASSERT(ctx != NULL);
512
/* Generate the salt. */
513
SVN_ERR(get_random_bytes(&salt_vector, ctx, SALT_LEN, result_pool));
515
/* Initialize the passphrase. */
516
apr_err = apr_crypto_passphrase(&key, &iv_len,
517
master->data, master->len,
518
salt_vector, SALT_LEN,
519
APR_KEY_AES_256, APR_MODE_CBC,
520
FALSE /* doPad */, NUM_ITERATIONS,
523
if (apr_err != APR_SUCCESS)
524
return svn_error_trace(crypto_error_create(
526
_("Error creating derived key")));
528
return svn_error_create(APR_EGENERAL, NULL,
529
_("Error creating derived key"));
531
return svn_error_create(APR_EGENERAL, NULL,
532
_("Unexpected IV length returned"));
534
/* Generate the proper length IV. */
535
SVN_ERR(get_random_bytes(&iv_vector, ctx, iv_len, result_pool));
537
/* Initialize block encryption. */
538
apr_err = apr_crypto_block_encrypt_init(&block_ctx, &iv_vector, key,
539
&block_size, scratch_pool);
540
if ((apr_err != APR_SUCCESS) || (! block_ctx))
541
return svn_error_trace(crypto_error_create(
543
_("Error initializing block encryption")));
545
/* Generate a blob of random data, block-aligned per the
546
requirements of the encryption algorithm, but with a minimum size
548
#define MIN_STUFF_LEN 32
549
if (MIN_STUFF_LEN % block_size)
550
stuff_len = MIN_STUFF_LEN + (block_size - (MIN_STUFF_LEN % block_size));
552
stuff_len = MIN_STUFF_LEN;
553
SVN_ERR(get_random_bytes(&stuff_vector, ctx, stuff_len, scratch_pool));
555
/* ### FIXME: This should be a SHA-256. */
556
SVN_ERR(svn_checksum(&stuff_sum, svn_checksum_sha1, stuff_vector,
557
stuff_len, scratch_pool));
559
/* Get the length that we need to allocate. */
560
apr_err = apr_crypto_block_encrypt(NULL, &result_len, stuff_vector,
561
stuff_len, block_ctx);
562
if (apr_err != APR_SUCCESS)
564
err = crypto_error_create(ctx, apr_err,
565
_("Error fetching result length"));
569
/* Allocate our result buffer. */
570
result = apr_palloc(result_pool, result_len);
572
/* Encrypt the block. */
573
apr_err = apr_crypto_block_encrypt(&result, &result_len, stuff_vector,
574
stuff_len, block_ctx);
575
if (apr_err != APR_SUCCESS)
577
err = crypto_error_create(ctx, apr_err,
578
_("Error during block encryption"));
582
/* Finalize the block encryption. Since we padded everything, this should
583
not produce any more encrypted output. */
584
apr_err = apr_crypto_block_encrypt_finish(NULL,
587
if (apr_err != APR_SUCCESS)
589
err = crypto_error_create(ctx, apr_err,
590
_("Error finalizing block encryption"));
594
*ciphertext = wrap_as_string(result, result_len, result_pool);
595
*iv = wrap_as_string(iv_vector, iv_len, result_pool);
596
*salt = wrap_as_string(salt_vector, SALT_LEN, result_pool);
597
*checktext = svn_checksum_to_cstring(stuff_sum, result_pool);
600
apr_crypto_block_cleanup(block_ctx);
602
#else /* SVN_HAVE_CRYPTO */
603
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
604
"Cryptographic support is not available");
605
#endif /* SVN_HAVE_CRYPTO */
610
svn_crypto__verify_secret(svn_boolean_t *is_valid,
611
svn_crypto__ctx_t *ctx,
612
const svn_string_t *master,
613
const svn_string_t *ciphertext,
614
const svn_string_t *iv,
615
const svn_string_t *salt,
616
const char *checktext,
617
apr_pool_t *scratch_pool)
619
#ifdef SVN_HAVE_CRYPTO
620
svn_error_t *err = SVN_NO_ERROR;
621
apr_status_t apr_err;
622
apr_crypto_block_t *block_ctx = NULL;
623
apr_size_t block_size, iv_len;
624
apr_crypto_key_t *key = NULL;
625
unsigned char *result;
626
apr_size_t result_len = 0, final_len = 0;
627
svn_checksum_t *result_sum;
631
/* Initialize the passphrase. */
632
apr_err = apr_crypto_passphrase(&key, &iv_len,
633
master->data, master->len,
634
(unsigned char *)salt->data, salt->len,
635
APR_KEY_AES_256, APR_MODE_CBC,
636
FALSE /* doPad */, NUM_ITERATIONS,
637
ctx->crypto, scratch_pool);
638
if (apr_err != APR_SUCCESS)
639
return svn_error_trace(crypto_error_create(
641
_("Error creating derived key")));
643
return svn_error_create(APR_EGENERAL, NULL,
644
_("Error creating derived key"));
646
return svn_error_create(APR_EGENERAL, NULL,
647
_("Unexpected IV length returned"));
648
if (iv_len != iv->len)
649
return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
650
_("Provided IV has incorrect length"));
652
apr_err = apr_crypto_block_decrypt_init(&block_ctx, &block_size,
653
(unsigned char *)iv->data,
655
if ((apr_err != APR_SUCCESS) || (! block_ctx))
656
return svn_error_trace(crypto_error_create(
658
_("Error initializing block decryption")));
660
apr_err = apr_crypto_block_decrypt(NULL, &result_len,
661
(unsigned char *)ciphertext->data,
662
ciphertext->len, block_ctx);
663
if (apr_err != APR_SUCCESS)
665
err = crypto_error_create(ctx, apr_err,
666
_("Error fetching result length"));
670
result = apr_palloc(scratch_pool, result_len);
671
apr_err = apr_crypto_block_decrypt(&result, &result_len,
672
(unsigned char *)ciphertext->data,
673
ciphertext->len, block_ctx);
674
if (apr_err != APR_SUCCESS)
676
err = crypto_error_create(ctx, apr_err,
677
_("Error during block decryption"));
681
apr_err = apr_crypto_block_decrypt_finish(result + result_len, &final_len,
683
if (apr_err != APR_SUCCESS)
685
err = crypto_error_create(ctx, apr_err,
686
_("Error finalizing block decryption"));
690
/* ### FIXME: This should be a SHA-256. */
691
SVN_ERR(svn_checksum(&result_sum, svn_checksum_sha1, result,
692
result_len + final_len, scratch_pool));
694
*is_valid = strcmp(checktext,
695
svn_checksum_to_cstring(result_sum, scratch_pool)) == 0;
698
apr_crypto_block_cleanup(block_ctx);
700
#else /* SVN_HAVE_CRYPTO */
702
return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
703
"Cryptographic support is not available");
704
#endif /* SVN_HAVE_CRYPTO */