1/* 2 * crypto.c : cryptographic routines 3 * 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 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 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 20 * under the License. 21 * ==================================================================== 22 */ 23 24#include "crypto.h" 25 26#ifdef SVN_HAVE_CRYPTO 27#include <apr_random.h> 28#include <apr_crypto.h> 29#endif /* SVN_HAVE_CRYPTO */ 30 31#include "svn_types.h" 32#include "svn_checksum.h" 33 34#include "svn_private_config.h" 35#include "private/svn_atomic.h" 36 37 38/* 1000 iterations is the recommended minimum, per RFC 2898, section 4.2. */ 39#define NUM_ITERATIONS 1000 40 41 42/* Size (in bytes) of the random data we'll prepend to encrypted data. */ 43#define RANDOM_PREFIX_LEN 4 44 45 46/* A structure for containing Subversion's cryptography-related bits 47 (so we can avoid passing around APR-isms outside this module). */ 48struct svn_crypto__ctx_t { 49#ifdef SVN_HAVE_CRYPTO 50 apr_crypto_t *crypto; /* APR cryptography context. */ 51 52#if 0 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() */ 58 apr_random_t *rand; 59#endif /* 0 */ 60#else /* SVN_HAVE_CRYPTO */ 61 int unused_but_required_to_satisfy_c_compilers; 62#endif /* SVN_HAVE_CRYPTO */ 63}; 64 65 66 67/*** Helper Functions ***/ 68#ifdef SVN_HAVE_CRYPTO 69 70 71/* One-time initialization of the cryptography subsystem. */ 72static volatile svn_atomic_t crypto_init_state = 0; 73 74 75#define CRYPTO_INIT(scratch_pool) \ 76 SVN_ERR(svn_atomic__init_once(&crypto_init_state, \ 77 crypto_init, NULL, (scratch_pool))) 78 79 80/* Initialize the APR cryptography subsystem (if available), using 81 ANY_POOL's ancestor root pool for the registration of cleanups, 82 shutdowns, etc. */ 83/* Don't call this function directly! Use svn_atomic__init_once(). */ 84static svn_error_t * 85crypto_init(void *baton, apr_pool_t *any_pool) 86{ 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 89 being cleared. */ 90 apr_status_t apr_err = apr_crypto_init(any_pool); 91 if (apr_err) 92 return svn_error_wrap_apr(apr_err, 93 _("Failed to initialize cryptography " 94 "subsystem")); 95 96 return SVN_NO_ERROR; 97} 98 99 100/* If APU_ERR is non-NULL, create and return a Subversion error using 101 APR_ERR and APU_ERR. */ 102static svn_error_t * 103err_from_apu_err(apr_status_t apr_err, 104 const apu_err_t *apu_err) 105{ 106 if (apu_err) 107 return svn_error_createf(apr_err, NULL, 108 _("code (%d), reason (\"%s\"), msg (\"%s\")"), 109 apu_err->rc, 110 apu_err->reason ? apu_err->reason : "", 111 apu_err->msg ? apu_err->msg : ""); 112 return SVN_NO_ERROR; 113} 114 115 116/* Generate a Subversion error which describes the state reflected by 117 APR_ERR and any crypto errors registered with CTX. */ 118static svn_error_t * 119crypto_error_create(svn_crypto__ctx_t *ctx, 120 apr_status_t apr_err, 121 const char *msg) 122{ 123 const apu_err_t *apu_err; 124 apr_status_t rv = apr_crypto_error(&apu_err, ctx->crypto); 125 svn_error_t *child; 126 127 /* Ugh. The APIs are a bit slippery, so be wary. */ 128 if (apr_err == APR_SUCCESS) 129 apr_err = APR_EGENERAL; 130 131 if (rv == APR_SUCCESS) 132 child = err_from_apu_err(apr_err, apu_err); 133 else 134 child = svn_error_wrap_apr(rv, _("Fetching error from APR")); 135 136 return svn_error_create(apr_err, child, msg); 137} 138 139 140/* Set RAND_BYTES to a block of bytes containing random data RAND_LEN 141 long and allocated from RESULT_POOL. */ 142static svn_error_t * 143get_random_bytes(const unsigned char **rand_bytes, 144 svn_crypto__ctx_t *ctx, 145 apr_size_t rand_len, 146 apr_pool_t *result_pool) 147{ 148 apr_status_t apr_err; 149 unsigned char *bytes; 150 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")); 155 156 *rand_bytes = bytes; 157 return SVN_NO_ERROR; 158} 159 160 161/* Return an svn_string_t allocated from RESULT_POOL, with its .data 162 and .len members set to DATA and LEN, respective. 163 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). */ 167static const svn_string_t * 168wrap_as_string(const unsigned char *data, 169 apr_size_t len, 170 apr_pool_t *result_pool) 171{ 172 svn_string_t *s = apr_palloc(result_pool, sizeof(*s)); 173 174 s->data = (const char *)data; /* better already be in RESULT_POOL */ 175 s->len = len; 176 return s; 177} 178 179 180#endif /* SVN_HAVE_CRYPTO */ 181 182 183 184/*** Semi-public APIs ***/ 185 186/* Return TRUE iff Subversion's cryptographic support is available. */ 187svn_boolean_t svn_crypto__is_available(void) 188{ 189#ifdef SVN_HAVE_CRYPTO 190 return TRUE; 191#else /* SVN_HAVE_CRYPTO */ 192 return FALSE; 193#endif /* SVN_HAVE_CRYPTO */ 194} 195 196 197/* Set CTX to a Subversion cryptography context allocated from 198 RESULT_POOL. */ 199svn_error_t * 200svn_crypto__context_create(svn_crypto__ctx_t **ctx, 201 apr_pool_t *result_pool) 202{ 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; 208 209 CRYPTO_INIT(result_pool); 210 211 /* Load the crypto driver. 212 213 ### TODO: For the sake of flexibility, should we use 214 ### APU_CRYPTO_RECOMMENDED_DRIVER instead of hard coding 215 ### "openssl" here? 216 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, 221 result_pool); 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")); 225 if (driver == NULL) 226 return svn_error_create(APR_EGENERAL, 227 err_from_apu_err(APR_EGENERAL, apu_err), 228 _("Bad return value while loading crypto " 229 "driver")); 230 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")); 235 236 /* Allocate and initialize our crypto context. */ 237 *ctx = apr_palloc(result_pool, sizeof(**ctx)); 238 (*ctx)->crypto = apr_crypto; 239 240 return SVN_NO_ERROR; 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 */ 245} 246 247 248svn_error_t * 249svn_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) 257{ 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; 262 apr_size_t iv_len; 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; 273 274 SVN_ERR_ASSERT(ctx != NULL); 275 276 /* Generate the salt. */ 277#define SALT_LEN 8 278 SVN_ERR(get_random_bytes(&salt_vector, ctx, SALT_LEN, result_pool)); 279 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, 286 ctx->crypto, 287 scratch_pool); 288 if (apr_err != APR_SUCCESS) 289 return svn_error_trace(crypto_error_create( 290 ctx, apr_err, 291 _("Error creating derived key"))); 292 if (! key) 293 return svn_error_create(APR_EGENERAL, NULL, 294 _("Error creating derived key")); 295 if (iv_len == 0) 296 return svn_error_create(APR_EGENERAL, NULL, 297 _("Unexpected IV length returned")); 298 299 /* Generate the proper length IV. */ 300 SVN_ERR(get_random_bytes(&iv_vector, ctx, iv_len, result_pool)); 301 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( 307 ctx, apr_err, 308 _("Error initializing block encryption"))); 309 310 /* Generate a 4-byte prefix. */ 311 SVN_ERR(get_random_bytes(&prefix, ctx, RANDOM_PREFIX_LEN, scratch_pool)); 312 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) 321 { 322 assembled = apr_palloc(scratch_pool, assembled_len); 323 memcpy(assembled, prefix, RANDOM_PREFIX_LEN); 324 memcpy(assembled + RANDOM_PREFIX_LEN, password, password_len); 325 } 326 else 327 { 328 const unsigned char *padding; 329 apr_size_t pad_len = block_size - (assembled_len % block_size) - 1; 330 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, 338 padding, pad_len); 339 } 340 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) 345 { 346 err = crypto_error_create(ctx, apr_err, 347 _("Error fetching result length")); 348 goto cleanup; 349 } 350 351 /* Allocate our result buffer. */ 352 result = apr_palloc(result_pool, result_len); 353 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) 358 { 359 err = crypto_error_create(ctx, apr_err, 360 _("Error during block encryption")); 361 goto cleanup; 362 } 363 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, 367 &ignored_result_len, 368 block_ctx); 369 if (apr_err != APR_SUCCESS) 370 { 371 err = crypto_error_create(ctx, apr_err, 372 _("Error finalizing block encryption")); 373 goto cleanup; 374 } 375 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); 379 380 cleanup: 381 apr_crypto_block_cleanup(block_ctx); 382 return err; 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 */ 387} 388 389 390svn_error_t * 391svn_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) 399{ 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; 408 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( 418 ctx, apr_err, 419 _("Error creating derived key"))); 420 if (! key) 421 return svn_error_create(APR_EGENERAL, NULL, 422 _("Error creating derived key")); 423 if (iv_len == 0) 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")); 429 430 apr_err = apr_crypto_block_decrypt_init(&block_ctx, &block_size, 431 (unsigned char *)iv->data, 432 key, scratch_pool); 433 if ((apr_err != APR_SUCCESS) || (! block_ctx)) 434 return svn_error_trace(crypto_error_create( 435 ctx, apr_err, 436 _("Error initializing block decryption"))); 437 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) 442 { 443 err = crypto_error_create(ctx, apr_err, 444 _("Error fetching result length")); 445 goto cleanup; 446 } 447 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) 453 { 454 err = crypto_error_create(ctx, apr_err, 455 _("Error during block decryption")); 456 goto cleanup; 457 } 458 459 apr_err = apr_crypto_block_decrypt_finish(result + result_len, &final_len, 460 block_ctx); 461 if (apr_err != APR_SUCCESS) 462 { 463 err = crypto_error_create(ctx, apr_err, 464 _("Error finalizing block decryption")); 465 goto cleanup; 466 } 467 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); 473 474 cleanup: 475 apr_crypto_block_cleanup(block_ctx); 476 return err; 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 */ 481} 482 483 484svn_error_t * 485svn_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) 493{ 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; 499 apr_size_t iv_len; 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; 509 510 SVN_ERR_ASSERT(ctx != NULL); 511 512 /* Generate the salt. */ 513 SVN_ERR(get_random_bytes(&salt_vector, ctx, SALT_LEN, result_pool)); 514 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, 521 ctx->crypto, 522 scratch_pool); 523 if (apr_err != APR_SUCCESS) 524 return svn_error_trace(crypto_error_create( 525 ctx, apr_err, 526 _("Error creating derived key"))); 527 if (! key) 528 return svn_error_create(APR_EGENERAL, NULL, 529 _("Error creating derived key")); 530 if (iv_len == 0) 531 return svn_error_create(APR_EGENERAL, NULL, 532 _("Unexpected IV length returned")); 533 534 /* Generate the proper length IV. */ 535 SVN_ERR(get_random_bytes(&iv_vector, ctx, iv_len, result_pool)); 536 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( 542 ctx, apr_err, 543 _("Error initializing block encryption"))); 544 545 /* Generate a blob of random data, block-aligned per the 546 requirements of the encryption algorithm, but with a minimum size 547 of our choosing. */ 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)); 551 else 552 stuff_len = MIN_STUFF_LEN; 553 SVN_ERR(get_random_bytes(&stuff_vector, ctx, stuff_len, scratch_pool)); 554 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)); 558 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) 563 { 564 err = crypto_error_create(ctx, apr_err, 565 _("Error fetching result length")); 566 goto cleanup; 567 } 568 569 /* Allocate our result buffer. */ 570 result = apr_palloc(result_pool, result_len); 571 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) 576 { 577 err = crypto_error_create(ctx, apr_err, 578 _("Error during block encryption")); 579 goto cleanup; 580 } 581 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, 585 &ignored_result_len, 586 block_ctx); 587 if (apr_err != APR_SUCCESS) 588 { 589 err = crypto_error_create(ctx, apr_err, 590 _("Error finalizing block encryption")); 591 goto cleanup; 592 } 593 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); 598 599 cleanup: 600 apr_crypto_block_cleanup(block_ctx); 601 return err; 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 */ 606} 607 608 609svn_error_t * 610svn_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) 618{ 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; 628 629 *is_valid = FALSE; 630 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( 640 ctx, apr_err, 641 _("Error creating derived key"))); 642 if (! key) 643 return svn_error_create(APR_EGENERAL, NULL, 644 _("Error creating derived key")); 645 if (iv_len == 0) 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")); 651 652 apr_err = apr_crypto_block_decrypt_init(&block_ctx, &block_size, 653 (unsigned char *)iv->data, 654 key, scratch_pool); 655 if ((apr_err != APR_SUCCESS) || (! block_ctx)) 656 return svn_error_trace(crypto_error_create( 657 ctx, apr_err, 658 _("Error initializing block decryption"))); 659 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) 664 { 665 err = crypto_error_create(ctx, apr_err, 666 _("Error fetching result length")); 667 goto cleanup; 668 } 669 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) 675 { 676 err = crypto_error_create(ctx, apr_err, 677 _("Error during block decryption")); 678 goto cleanup; 679 } 680 681 apr_err = apr_crypto_block_decrypt_finish(result + result_len, &final_len, 682 block_ctx); 683 if (apr_err != APR_SUCCESS) 684 { 685 err = crypto_error_create(ctx, apr_err, 686 _("Error finalizing block decryption")); 687 goto cleanup; 688 } 689 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)); 693 694 *is_valid = strcmp(checktext, 695 svn_checksum_to_cstring(result_sum, scratch_pool)) == 0; 696 697 cleanup: 698 apr_crypto_block_cleanup(block_ctx); 699 return err; 700#else /* SVN_HAVE_CRYPTO */ 701 *is_valid = FALSE; 702 return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, 703 "Cryptographic support is not available"); 704#endif /* SVN_HAVE_CRYPTO */ 705} 706