diff options
Diffstat (limited to 'src/lib/libcrypto/ec/ec2_smpl.c')
| -rw-r--r-- | src/lib/libcrypto/ec/ec2_smpl.c | 351 |
1 files changed, 337 insertions, 14 deletions
diff --git a/src/lib/libcrypto/ec/ec2_smpl.c b/src/lib/libcrypto/ec/ec2_smpl.c index e0e59c7d82..03deae6674 100644 --- a/src/lib/libcrypto/ec/ec2_smpl.c +++ b/src/lib/libcrypto/ec/ec2_smpl.c | |||
| @@ -71,20 +71,10 @@ | |||
| 71 | 71 | ||
| 72 | #include "ec_lcl.h" | 72 | #include "ec_lcl.h" |
| 73 | 73 | ||
| 74 | #ifndef OPENSSL_NO_EC2M | ||
| 75 | |||
| 76 | #ifdef OPENSSL_FIPS | ||
| 77 | #include <openssl/fips.h> | ||
| 78 | #endif | ||
| 79 | |||
| 80 | 74 | ||
| 81 | const EC_METHOD *EC_GF2m_simple_method(void) | 75 | const EC_METHOD *EC_GF2m_simple_method(void) |
| 82 | { | 76 | { |
| 83 | #ifdef OPENSSL_FIPS | ||
| 84 | return fips_ec_gf2m_simple_method(); | ||
| 85 | #else | ||
| 86 | static const EC_METHOD ret = { | 77 | static const EC_METHOD ret = { |
| 87 | EC_FLAGS_DEFAULT_OCT, | ||
| 88 | NID_X9_62_characteristic_two_field, | 78 | NID_X9_62_characteristic_two_field, |
| 89 | ec_GF2m_simple_group_init, | 79 | ec_GF2m_simple_group_init, |
| 90 | ec_GF2m_simple_group_finish, | 80 | ec_GF2m_simple_group_finish, |
| @@ -103,7 +93,9 @@ const EC_METHOD *EC_GF2m_simple_method(void) | |||
| 103 | 0 /* get_Jprojective_coordinates_GFp */, | 93 | 0 /* get_Jprojective_coordinates_GFp */, |
| 104 | ec_GF2m_simple_point_set_affine_coordinates, | 94 | ec_GF2m_simple_point_set_affine_coordinates, |
| 105 | ec_GF2m_simple_point_get_affine_coordinates, | 95 | ec_GF2m_simple_point_get_affine_coordinates, |
| 106 | 0,0,0, | 96 | ec_GF2m_simple_set_compressed_coordinates, |
| 97 | ec_GF2m_simple_point2oct, | ||
| 98 | ec_GF2m_simple_oct2point, | ||
| 107 | ec_GF2m_simple_add, | 99 | ec_GF2m_simple_add, |
| 108 | ec_GF2m_simple_dbl, | 100 | ec_GF2m_simple_dbl, |
| 109 | ec_GF2m_simple_invert, | 101 | ec_GF2m_simple_invert, |
| @@ -126,7 +118,6 @@ const EC_METHOD *EC_GF2m_simple_method(void) | |||
| 126 | 0 /* field_set_to_one */ }; | 118 | 0 /* field_set_to_one */ }; |
| 127 | 119 | ||
| 128 | return &ret; | 120 | return &ret; |
| 129 | #endif | ||
| 130 | } | 121 | } |
| 131 | 122 | ||
| 132 | 123 | ||
| @@ -414,6 +405,340 @@ int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_ | |||
| 414 | return ret; | 405 | return ret; |
| 415 | } | 406 | } |
| 416 | 407 | ||
| 408 | |||
| 409 | /* Calculates and sets the affine coordinates of an EC_POINT from the given | ||
| 410 | * compressed coordinates. Uses algorithm 2.3.4 of SEC 1. | ||
| 411 | * Note that the simple implementation only uses affine coordinates. | ||
| 412 | * | ||
| 413 | * The method is from the following publication: | ||
| 414 | * | ||
| 415 | * Harper, Menezes, Vanstone: | ||
| 416 | * "Public-Key Cryptosystems with Very Small Key Lengths", | ||
| 417 | * EUROCRYPT '92, Springer-Verlag LNCS 658, | ||
| 418 | * published February 1993 | ||
| 419 | * | ||
| 420 | * US Patents 6,141,420 and 6,618,483 (Vanstone, Mullin, Agnew) describe | ||
| 421 | * the same method, but claim no priority date earlier than July 29, 1994 | ||
| 422 | * (and additionally fail to cite the EUROCRYPT '92 publication as prior art). | ||
| 423 | */ | ||
| 424 | int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point, | ||
| 425 | const BIGNUM *x_, int y_bit, BN_CTX *ctx) | ||
| 426 | { | ||
| 427 | BN_CTX *new_ctx = NULL; | ||
| 428 | BIGNUM *tmp, *x, *y, *z; | ||
| 429 | int ret = 0, z0; | ||
| 430 | |||
| 431 | /* clear error queue */ | ||
| 432 | ERR_clear_error(); | ||
| 433 | |||
| 434 | if (ctx == NULL) | ||
| 435 | { | ||
| 436 | ctx = new_ctx = BN_CTX_new(); | ||
| 437 | if (ctx == NULL) | ||
| 438 | return 0; | ||
| 439 | } | ||
| 440 | |||
| 441 | y_bit = (y_bit != 0) ? 1 : 0; | ||
| 442 | |||
| 443 | BN_CTX_start(ctx); | ||
| 444 | tmp = BN_CTX_get(ctx); | ||
| 445 | x = BN_CTX_get(ctx); | ||
| 446 | y = BN_CTX_get(ctx); | ||
| 447 | z = BN_CTX_get(ctx); | ||
| 448 | if (z == NULL) goto err; | ||
| 449 | |||
| 450 | if (!BN_GF2m_mod_arr(x, x_, group->poly)) goto err; | ||
| 451 | if (BN_is_zero(x)) | ||
| 452 | { | ||
| 453 | if (!BN_GF2m_mod_sqrt_arr(y, &group->b, group->poly, ctx)) goto err; | ||
| 454 | } | ||
| 455 | else | ||
| 456 | { | ||
| 457 | if (!group->meth->field_sqr(group, tmp, x, ctx)) goto err; | ||
| 458 | if (!group->meth->field_div(group, tmp, &group->b, tmp, ctx)) goto err; | ||
| 459 | if (!BN_GF2m_add(tmp, &group->a, tmp)) goto err; | ||
| 460 | if (!BN_GF2m_add(tmp, x, tmp)) goto err; | ||
| 461 | if (!BN_GF2m_mod_solve_quad_arr(z, tmp, group->poly, ctx)) | ||
| 462 | { | ||
| 463 | unsigned long err = ERR_peek_last_error(); | ||
| 464 | |||
| 465 | if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NO_SOLUTION) | ||
| 466 | { | ||
| 467 | ERR_clear_error(); | ||
| 468 | ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT); | ||
| 469 | } | ||
| 470 | else | ||
| 471 | ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB); | ||
| 472 | goto err; | ||
| 473 | } | ||
| 474 | z0 = (BN_is_odd(z)) ? 1 : 0; | ||
| 475 | if (!group->meth->field_mul(group, y, x, z, ctx)) goto err; | ||
| 476 | if (z0 != y_bit) | ||
| 477 | { | ||
| 478 | if (!BN_GF2m_add(y, y, x)) goto err; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | |||
| 482 | if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err; | ||
| 483 | |||
| 484 | ret = 1; | ||
| 485 | |||
| 486 | err: | ||
| 487 | BN_CTX_end(ctx); | ||
| 488 | if (new_ctx != NULL) | ||
| 489 | BN_CTX_free(new_ctx); | ||
| 490 | return ret; | ||
| 491 | } | ||
| 492 | |||
| 493 | |||
| 494 | /* Converts an EC_POINT to an octet string. | ||
| 495 | * If buf is NULL, the encoded length will be returned. | ||
| 496 | * If the length len of buf is smaller than required an error will be returned. | ||
| 497 | */ | ||
| 498 | size_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form, | ||
| 499 | unsigned char *buf, size_t len, BN_CTX *ctx) | ||
| 500 | { | ||
| 501 | size_t ret; | ||
| 502 | BN_CTX *new_ctx = NULL; | ||
| 503 | int used_ctx = 0; | ||
| 504 | BIGNUM *x, *y, *yxi; | ||
| 505 | size_t field_len, i, skip; | ||
| 506 | |||
| 507 | if ((form != POINT_CONVERSION_COMPRESSED) | ||
| 508 | && (form != POINT_CONVERSION_UNCOMPRESSED) | ||
| 509 | && (form != POINT_CONVERSION_HYBRID)) | ||
| 510 | { | ||
| 511 | ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_INVALID_FORM); | ||
| 512 | goto err; | ||
| 513 | } | ||
| 514 | |||
| 515 | if (EC_POINT_is_at_infinity(group, point)) | ||
| 516 | { | ||
| 517 | /* encodes to a single 0 octet */ | ||
| 518 | if (buf != NULL) | ||
| 519 | { | ||
| 520 | if (len < 1) | ||
| 521 | { | ||
| 522 | ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL); | ||
| 523 | return 0; | ||
| 524 | } | ||
| 525 | buf[0] = 0; | ||
| 526 | } | ||
| 527 | return 1; | ||
| 528 | } | ||
| 529 | |||
| 530 | |||
| 531 | /* ret := required output buffer length */ | ||
| 532 | field_len = (EC_GROUP_get_degree(group) + 7) / 8; | ||
| 533 | ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len; | ||
| 534 | |||
| 535 | /* if 'buf' is NULL, just return required length */ | ||
| 536 | if (buf != NULL) | ||
| 537 | { | ||
| 538 | if (len < ret) | ||
| 539 | { | ||
| 540 | ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL); | ||
| 541 | goto err; | ||
| 542 | } | ||
| 543 | |||
| 544 | if (ctx == NULL) | ||
| 545 | { | ||
| 546 | ctx = new_ctx = BN_CTX_new(); | ||
| 547 | if (ctx == NULL) | ||
| 548 | return 0; | ||
| 549 | } | ||
| 550 | |||
| 551 | BN_CTX_start(ctx); | ||
| 552 | used_ctx = 1; | ||
| 553 | x = BN_CTX_get(ctx); | ||
| 554 | y = BN_CTX_get(ctx); | ||
| 555 | yxi = BN_CTX_get(ctx); | ||
| 556 | if (yxi == NULL) goto err; | ||
| 557 | |||
| 558 | if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err; | ||
| 559 | |||
| 560 | buf[0] = form; | ||
| 561 | if ((form != POINT_CONVERSION_UNCOMPRESSED) && !BN_is_zero(x)) | ||
| 562 | { | ||
| 563 | if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err; | ||
| 564 | if (BN_is_odd(yxi)) buf[0]++; | ||
| 565 | } | ||
| 566 | |||
| 567 | i = 1; | ||
| 568 | |||
| 569 | skip = field_len - BN_num_bytes(x); | ||
| 570 | if (skip > field_len) | ||
| 571 | { | ||
| 572 | ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); | ||
| 573 | goto err; | ||
| 574 | } | ||
| 575 | while (skip > 0) | ||
| 576 | { | ||
| 577 | buf[i++] = 0; | ||
| 578 | skip--; | ||
| 579 | } | ||
| 580 | skip = BN_bn2bin(x, buf + i); | ||
| 581 | i += skip; | ||
| 582 | if (i != 1 + field_len) | ||
| 583 | { | ||
| 584 | ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); | ||
| 585 | goto err; | ||
| 586 | } | ||
| 587 | |||
| 588 | if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID) | ||
| 589 | { | ||
| 590 | skip = field_len - BN_num_bytes(y); | ||
| 591 | if (skip > field_len) | ||
| 592 | { | ||
| 593 | ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); | ||
| 594 | goto err; | ||
| 595 | } | ||
| 596 | while (skip > 0) | ||
| 597 | { | ||
| 598 | buf[i++] = 0; | ||
| 599 | skip--; | ||
| 600 | } | ||
| 601 | skip = BN_bn2bin(y, buf + i); | ||
| 602 | i += skip; | ||
| 603 | } | ||
| 604 | |||
| 605 | if (i != ret) | ||
| 606 | { | ||
| 607 | ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); | ||
| 608 | goto err; | ||
| 609 | } | ||
| 610 | } | ||
| 611 | |||
| 612 | if (used_ctx) | ||
| 613 | BN_CTX_end(ctx); | ||
| 614 | if (new_ctx != NULL) | ||
| 615 | BN_CTX_free(new_ctx); | ||
| 616 | return ret; | ||
| 617 | |||
| 618 | err: | ||
| 619 | if (used_ctx) | ||
| 620 | BN_CTX_end(ctx); | ||
| 621 | if (new_ctx != NULL) | ||
| 622 | BN_CTX_free(new_ctx); | ||
| 623 | return 0; | ||
| 624 | } | ||
| 625 | |||
| 626 | |||
| 627 | /* Converts an octet string representation to an EC_POINT. | ||
| 628 | * Note that the simple implementation only uses affine coordinates. | ||
| 629 | */ | ||
| 630 | int ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | ||
| 631 | const unsigned char *buf, size_t len, BN_CTX *ctx) | ||
| 632 | { | ||
| 633 | point_conversion_form_t form; | ||
| 634 | int y_bit; | ||
| 635 | BN_CTX *new_ctx = NULL; | ||
| 636 | BIGNUM *x, *y, *yxi; | ||
| 637 | size_t field_len, enc_len; | ||
| 638 | int ret = 0; | ||
| 639 | |||
| 640 | if (len == 0) | ||
| 641 | { | ||
| 642 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL); | ||
| 643 | return 0; | ||
| 644 | } | ||
| 645 | form = buf[0]; | ||
| 646 | y_bit = form & 1; | ||
| 647 | form = form & ~1U; | ||
| 648 | if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) | ||
| 649 | && (form != POINT_CONVERSION_UNCOMPRESSED) | ||
| 650 | && (form != POINT_CONVERSION_HYBRID)) | ||
| 651 | { | ||
| 652 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 653 | return 0; | ||
| 654 | } | ||
| 655 | if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) | ||
| 656 | { | ||
| 657 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 658 | return 0; | ||
| 659 | } | ||
| 660 | |||
| 661 | if (form == 0) | ||
| 662 | { | ||
| 663 | if (len != 1) | ||
| 664 | { | ||
| 665 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 666 | return 0; | ||
| 667 | } | ||
| 668 | |||
| 669 | return EC_POINT_set_to_infinity(group, point); | ||
| 670 | } | ||
| 671 | |||
| 672 | field_len = (EC_GROUP_get_degree(group) + 7) / 8; | ||
| 673 | enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len; | ||
| 674 | |||
| 675 | if (len != enc_len) | ||
| 676 | { | ||
| 677 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 678 | return 0; | ||
| 679 | } | ||
| 680 | |||
| 681 | if (ctx == NULL) | ||
| 682 | { | ||
| 683 | ctx = new_ctx = BN_CTX_new(); | ||
| 684 | if (ctx == NULL) | ||
| 685 | return 0; | ||
| 686 | } | ||
| 687 | |||
| 688 | BN_CTX_start(ctx); | ||
| 689 | x = BN_CTX_get(ctx); | ||
| 690 | y = BN_CTX_get(ctx); | ||
| 691 | yxi = BN_CTX_get(ctx); | ||
| 692 | if (yxi == NULL) goto err; | ||
| 693 | |||
| 694 | if (!BN_bin2bn(buf + 1, field_len, x)) goto err; | ||
| 695 | if (BN_ucmp(x, &group->field) >= 0) | ||
| 696 | { | ||
| 697 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 698 | goto err; | ||
| 699 | } | ||
| 700 | |||
| 701 | if (form == POINT_CONVERSION_COMPRESSED) | ||
| 702 | { | ||
| 703 | if (!EC_POINT_set_compressed_coordinates_GF2m(group, point, x, y_bit, ctx)) goto err; | ||
| 704 | } | ||
| 705 | else | ||
| 706 | { | ||
| 707 | if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err; | ||
| 708 | if (BN_ucmp(y, &group->field) >= 0) | ||
| 709 | { | ||
| 710 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 711 | goto err; | ||
| 712 | } | ||
| 713 | if (form == POINT_CONVERSION_HYBRID) | ||
| 714 | { | ||
| 715 | if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err; | ||
| 716 | if (y_bit != BN_is_odd(yxi)) | ||
| 717 | { | ||
| 718 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 719 | goto err; | ||
| 720 | } | ||
| 721 | } | ||
| 722 | |||
| 723 | if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err; | ||
| 724 | } | ||
| 725 | |||
| 726 | if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */ | ||
| 727 | { | ||
| 728 | ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE); | ||
| 729 | goto err; | ||
| 730 | } | ||
| 731 | |||
| 732 | ret = 1; | ||
| 733 | |||
| 734 | err: | ||
| 735 | BN_CTX_end(ctx); | ||
| 736 | if (new_ctx != NULL) | ||
| 737 | BN_CTX_free(new_ctx); | ||
| 738 | return ret; | ||
| 739 | } | ||
| 740 | |||
| 741 | |||
| 417 | /* Computes a + b and stores the result in r. r could be a or b, a could be b. | 742 | /* Computes a + b and stores the result in r. r could be a or b, a could be b. |
| 418 | * Uses algorithm A.10.2 of IEEE P1363. | 743 | * Uses algorithm A.10.2 of IEEE P1363. |
| 419 | */ | 744 | */ |
| @@ -715,5 +1040,3 @@ int ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, | |||
| 715 | { | 1040 | { |
| 716 | return BN_GF2m_mod_div(r, a, b, &group->field, ctx); | 1041 | return BN_GF2m_mod_div(r, a, b, &group->field, ctx); |
| 717 | } | 1042 | } |
| 718 | |||
| 719 | #endif | ||
