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 */