|
508 | 508 | return R_RET;
|
509 | 509 |
|
510 | 510 | }
|
| 511 | + |
| 512 | + |
| 513 | +#include "uECC.h" |
| 514 | +const struct uECC_Curve_t* ECC_curves[5] = {0,0,0,0,0}; |
| 515 | +typedef struct { |
| 516 | + REBCNT curve_type; |
| 517 | + uint8_t public[64]; |
| 518 | + uint8_t private[32]; |
| 519 | +} ECC_CTX; |
| 520 | + |
| 521 | +/*********************************************************************** |
| 522 | +** |
| 523 | +*/ REBNATIVE(ecdh) |
| 524 | +/* |
| 525 | +// ecdh: native [ |
| 526 | +// "Elliptic-curve Diffie-Hellman key exchange" |
| 527 | +// key [handle! none!] "Keypair to work with, may be NONE for /init refinement" |
| 528 | +// /init "Initialize ECC keypair." |
| 529 | +// type [word!] "One of supported curves: [secp256k1 secp256r1 secp224r1 secp192r1 secp160r1]" |
| 530 | +// /curve "Returns handles curve type" |
| 531 | +// /public "Returns public key as a binary" |
| 532 | +// /secret "Computes secret result using peer's public key" |
| 533 | +// public-key [binary!] "Peer's public key" |
| 534 | +// /release "Releases internal ECDH key resources" |
| 535 | +// ] |
| 536 | +***********************************************************************/ |
| 537 | +{ |
| 538 | + REBVAL *val_handle = D_ARG(1); |
| 539 | + REBOOL ref_init = D_REF(2); |
| 540 | + REBVAL *val_curve = D_ARG(3); |
| 541 | + REBOOL ref_type = D_REF(4); |
| 542 | + REBOOL ref_public = D_REF(5); |
| 543 | + REBOOL ref_secret = D_REF(6); |
| 544 | + REBVAL *val_public = D_ARG(7); |
| 545 | + REBOOL ref_release = D_REF(8); |
| 546 | + |
| 547 | + REBSER *ecc_ser = NULL; |
| 548 | + REBSER *bin = NULL; |
| 549 | + REBVAL *ret; |
| 550 | + REBCNT curve_type = 0; |
| 551 | + uECC_Curve curve = NULL; |
| 552 | + ECC_CTX *ecc = NULL; |
| 553 | + |
| 554 | + if (IS_HANDLE(val_handle)) { |
| 555 | + if (VAL_HANDLE_TYPE(val_handle) != SYM_ECDH || VAL_HANDLE_DATA(val_handle) == NULL) { |
| 556 | + Trap0(RE_INVALID_HANDLE); |
| 557 | + } |
| 558 | + ecc_ser = VAL_HANDLE_DATA(val_handle); |
| 559 | + ecc = (ECC_CTX*)SERIES_DATA(ecc_ser); |
| 560 | + curve_type = ecc->curve_type; |
| 561 | + } |
| 562 | + |
| 563 | + if (ref_init) { |
| 564 | + if(ecc_ser == NULL) { |
| 565 | + ecc_ser = Make_Series(sizeof(ECC_CTX), 1, FALSE); |
| 566 | + } |
| 567 | + ecc = (ECC_CTX*)SERIES_DATA(ecc_ser); |
| 568 | + CLEARS(ecc); |
| 569 | + curve_type = ecc->curve_type = VAL_WORD_CANON(val_curve); |
| 570 | + SET_HANDLE(val_handle, ecc_ser, SYM_ECDH, HANDLE_SERIES); |
| 571 | + } |
| 572 | + |
| 573 | + switch (curve_type) { |
| 574 | + case SYM_SECP256K1: |
| 575 | + curve = ECC_curves[4]; |
| 576 | + if(curve == NULL) { |
| 577 | + curve = uECC_secp256k1(); |
| 578 | + ECC_curves[4] = curve; |
| 579 | + } |
| 580 | + break; |
| 581 | + case SYM_SECP256R1: |
| 582 | + curve = ECC_curves[3]; |
| 583 | + if(curve == NULL) { |
| 584 | + curve = uECC_secp256r1(); |
| 585 | + ECC_curves[3] = curve; |
| 586 | + } |
| 587 | + break; |
| 588 | + case SYM_SECP224R1: |
| 589 | + curve = ECC_curves[2]; |
| 590 | + if(curve == NULL) { |
| 591 | + curve = uECC_secp224r1(); |
| 592 | + ECC_curves[2] = curve; |
| 593 | + } |
| 594 | + break; |
| 595 | + case SYM_SECP192R1: |
| 596 | + curve = ECC_curves[1]; |
| 597 | + if(curve == NULL) { |
| 598 | + curve = uECC_secp192r1(); |
| 599 | + ECC_curves[1] = curve; |
| 600 | + } |
| 601 | + break; |
| 602 | + case SYM_SECP160R1: |
| 603 | + curve = ECC_curves[0]; |
| 604 | + if(curve == NULL) { |
| 605 | + curve = uECC_secp160r1(); |
| 606 | + ECC_curves[0] = curve; |
| 607 | + } |
| 608 | + break; |
| 609 | + default: |
| 610 | + return R_NONE; |
| 611 | + } |
| 612 | + |
| 613 | + if (ref_init) { |
| 614 | + if(!uECC_make_key(ecc->public, ecc->private, curve)) { |
| 615 | + puts("failed to init ECDH key"); |
| 616 | + Trap0(RE_INVALID_HANDLE); //TODO: change to something better! |
| 617 | + } else return R_ARG1; |
| 618 | + } |
| 619 | + |
| 620 | + if (ref_secret) { |
| 621 | + if (IS_HANDLE(val_handle)) { |
| 622 | + bin = Make_Binary(32); |
| 623 | + if (!uECC_shared_secret(VAL_DATA(val_public), ecc->private, BIN_DATA(bin), curve)) { |
| 624 | + return R_NONE; |
| 625 | + } |
| 626 | + if(ref_release) { |
| 627 | + CLEARS(ecc); |
| 628 | + HANDLE_SET_FLAG(val_handle, HANDLE_RELEASABLE); |
| 629 | + } |
| 630 | + SET_BINARY(D_RET, bin); |
| 631 | + BIN_LEN(bin) = 32; |
| 632 | + return R_RET; |
| 633 | + } |
| 634 | + else { |
| 635 | + Trap0(RE_INVALID_HANDLE); |
| 636 | + return R_NONE; |
| 637 | + } |
| 638 | + } |
| 639 | + |
| 640 | + if (ref_public) { |
| 641 | + if (IS_HANDLE(val_handle)) { |
| 642 | + bin = Make_Binary(64); |
| 643 | + COPY_MEM(BIN_DATA(bin), ecc->public, 64); |
| 644 | + SET_BINARY(D_RET, bin); |
| 645 | + BIN_LEN(bin) = 64; |
| 646 | + return R_RET; |
| 647 | + } |
| 648 | + else { |
| 649 | + return R_NONE; |
| 650 | + } |
| 651 | + } |
| 652 | + |
| 653 | + if(ref_release) { |
| 654 | + CLEARS(ecc); |
| 655 | + HANDLE_SET_FLAG(val_handle, HANDLE_RELEASABLE); |
| 656 | + return R_ARG1; |
| 657 | + } |
| 658 | + |
| 659 | + if (ref_type) { |
| 660 | + if (IS_HANDLE(val_handle)) { |
| 661 | + Init_Word(val_curve, curve_type); |
| 662 | + return R_ARG3; |
| 663 | + } |
| 664 | + else { |
| 665 | + return R_NONE; |
| 666 | + } |
| 667 | + } |
| 668 | + return R_ARG1; |
| 669 | +} |
0 commit comments