|
32 | 32 | #include "sys-rc4.h"
|
33 | 33 | #include "sys-aes.h"
|
34 | 34 | #include "sys-rsa.h"
|
| 35 | +#include "sys-dh.h" |
35 | 36 |
|
36 | 37 | const REBYTE rc4_name[] = "RC4-context"; //Used as a context handle name
|
37 | 38 | const REBYTE aes_name[] = "AES-context";
|
38 | 39 | const REBYTE rsa_name[] = "RSA-context";
|
| 40 | +const REBYTE dh_name[] = "DH-Key"; |
39 | 41 |
|
40 | 42 | /***********************************************************************
|
41 | 43 | **
|
@@ -101,7 +103,7 @@ const REBYTE rsa_name[] = "RSA-context";
|
101 | 103 | // /decrypt "Use the crypt-key for decryption (default is to encrypt)"
|
102 | 104 | // /stream
|
103 | 105 | // ctx [handle!] "Stream cipher context."
|
104 |
| -// data [binary!] "Data to encrypt/decrypt. Or NONE to close the cipher stream." |
| 106 | +// data [binary! none!] "Data to encrypt/decrypt. Or NONE to close the cipher stream." |
105 | 107 | // ]
|
106 | 108 | ***********************************************************************/
|
107 | 109 | {
|
@@ -160,6 +162,14 @@ const REBYTE rsa_name[] = "RSA-context";
|
160 | 162 | }
|
161 | 163 |
|
162 | 164 | ctx = (REBSER*)VAL_HANDLE(val_ctx);
|
| 165 | + if(ctx == NULL) Trap0(RE_INVALID_HANDLE); |
| 166 | + |
| 167 | + if(IS_NONE(val_data)) { |
| 168 | + puts("releasing AES ctx"); |
| 169 | + Free_Series(ctx); |
| 170 | + SET_HANDLE(val_ctx, NULL); |
| 171 | + return R_TRUE; |
| 172 | + } |
163 | 173 |
|
164 | 174 | len = VAL_LEN(val_data);
|
165 | 175 | if (len == 0) return R_NONE;
|
@@ -358,3 +368,162 @@ const REBYTE rsa_name[] = "RSA-context";
|
358 | 368 | return R_RET;
|
359 | 369 |
|
360 | 370 | }
|
| 371 | + |
| 372 | + |
| 373 | +/*********************************************************************** |
| 374 | +** |
| 375 | +*/ REBNATIVE(dh_init) |
| 376 | +/* |
| 377 | +// dh-init: native [ |
| 378 | +// "Generates a new Diffie-Hellman private/public key pair" |
| 379 | +// g [binary!] "Generator" |
| 380 | +// p [binary!] "Field prime" |
| 381 | +// /into |
| 382 | +// dh-key [handle!] "Existing DH key handle" |
| 383 | +// ] |
| 384 | +***********************************************************************/ |
| 385 | +{ |
| 386 | + REBSER *g = VAL_SERIES(D_ARG(1)); |
| 387 | + REBSER *p = VAL_SERIES(D_ARG(2)); |
| 388 | + REBOOL ref_into = D_REF(3); |
| 389 | + REBVAL *val_dh = D_ARG(4); |
| 390 | + |
| 391 | + DH_CTX *dh; |
| 392 | + REBYTE *bin; |
| 393 | + REBCNT len; |
| 394 | + REBVAL *ret; |
| 395 | + |
| 396 | + REBCNT len_g = BIN_LEN(g); |
| 397 | + REBCNT len_p = BIN_LEN(p); |
| 398 | + REBYTE *buffer = NULL; |
| 399 | + |
| 400 | + // allocating buffers for all keys as a one blob |
| 401 | + REBCNT buffer_len = BIN_LEN(g) + (5 * BIN_LEN(p)); |
| 402 | + |
| 403 | + if(ref_into) { |
| 404 | + if(!IS_HANDLE(val_dh) || VAL_HANDLE_NAME(val_dh) != dh_name) { |
| 405 | + //error! |
| 406 | + return R_NONE; |
| 407 | + } |
| 408 | + ret = val_dh; |
| 409 | + *D_RET = *D_ARG(4); |
| 410 | + dh = (DH_CTX*)VAL_HANDLE(val_dh); |
| 411 | + if(dh == NULL) goto new_dh_handle; |
| 412 | + if(dh->len_data < buffer_len) { |
| 413 | + //needs new allocation for keys |
| 414 | + if(dh->data != NULL) FREE_MEM(dh->data); |
| 415 | + } else { |
| 416 | + //skip the buffer allocation |
| 417 | + buffer = dh->data; |
| 418 | + } |
| 419 | + } else { |
| 420 | + ret = D_RET; |
| 421 | +new_dh_handle: |
| 422 | + dh = (DH_CTX*)MAKE_NEW(DH_CTX); |
| 423 | + SET_HANDLE(ret, dh); |
| 424 | + VAL_HANDLE_NAME(ret) = dh_name; |
| 425 | + } |
| 426 | + |
| 427 | + if(buffer == NULL) { |
| 428 | + buffer = MAKE_MEM(buffer_len); |
| 429 | + dh->len_data = buffer_len; |
| 430 | + } |
| 431 | + |
| 432 | + CLEAR(buffer, dh->len_data); |
| 433 | + |
| 434 | + bin = BIN_DATA(g); //@@ use VAL_BIN_AT instead? |
| 435 | + dh->len_g = len_g; |
| 436 | + dh->g = buffer; |
| 437 | + COPY_MEM(dh->g, bin, len_g); |
| 438 | + |
| 439 | + buffer += len_g; |
| 440 | + |
| 441 | + bin = BIN_DATA(p); |
| 442 | + dh->len = len_p; |
| 443 | + dh->p = buffer; |
| 444 | + COPY_MEM(dh->p, bin, len_p); |
| 445 | + |
| 446 | + buffer += len_p; |
| 447 | + |
| 448 | + dh->x = buffer; //private key |
| 449 | + buffer += len_p; |
| 450 | + dh->gx = buffer; //public key (self) |
| 451 | + buffer += len_p; |
| 452 | + dh->gy = buffer; //public key (peer) |
| 453 | + buffer += len_p; |
| 454 | + dh->k = buffer; //negotiated key |
| 455 | + |
| 456 | + DH_generate_key(dh); |
| 457 | + |
| 458 | + return R_RET; |
| 459 | +} |
| 460 | + |
| 461 | +/*********************************************************************** |
| 462 | +** |
| 463 | +*/ REBNATIVE(dh) |
| 464 | +/* |
| 465 | +// dh: native [ |
| 466 | +// "Diffie-Hellman key exchange" |
| 467 | +// dh-key [handle!] "DH key created using `dh-init` function" |
| 468 | +// /release "Releases internal DH key resources" |
| 469 | +// /public "Returns public key as a binary" |
| 470 | +// /secret "Computes secret result using peer's public key" |
| 471 | +// public-key [binary!] "Peer's public key" |
| 472 | +// ] |
| 473 | +***********************************************************************/ |
| 474 | +{ |
| 475 | + REBVAL *val_dh = D_ARG(1); |
| 476 | + REBOOL ref_release = D_REF(2); |
| 477 | + REBOOL ref_public = D_REF(3); |
| 478 | + REBOOL ref_secret = D_REF(4); |
| 479 | + REBVAL *pub_key = D_ARG(5); |
| 480 | + |
| 481 | + REBVAL *ret = D_RET; |
| 482 | + REBSER *bin; |
| 483 | + REBCNT len; |
| 484 | + |
| 485 | + if (ref_public && ref_secret) { |
| 486 | + // only one can be used |
| 487 | + Trap0(RE_BAD_REFINES); |
| 488 | + } |
| 489 | + |
| 490 | + if (VAL_HANDLE_NAME(val_dh) != dh_name || VAL_HANDLE(val_dh) == NULL) { |
| 491 | + Trap0(RE_INVALID_HANDLE); |
| 492 | + } |
| 493 | + |
| 494 | + DH_CTX *dh = (DH_CTX*)VAL_HANDLE(val_dh); |
| 495 | + |
| 496 | + if (dh->g == NULL) return R_NONE; //or error? |
| 497 | + |
| 498 | + if(ref_public) { |
| 499 | + bin = Make_Binary(dh->len); |
| 500 | + COPY_MEM(BIN_DATA(bin), dh->gx, dh->len); |
| 501 | + SET_BINARY(ret, bin); |
| 502 | + BIN_LEN(bin) = dh->len; |
| 503 | + } |
| 504 | + |
| 505 | + if(ref_secret) { |
| 506 | + bin = BIN_DATA(VAL_SERIES(pub_key)); //@@ use VAL_BIN_AT instead? |
| 507 | + len = BIN_LEN(VAL_SERIES(pub_key)); |
| 508 | + if(len != dh->len) { |
| 509 | + return R_NONE; // throw an error? |
| 510 | + } |
| 511 | + COPY_MEM(dh->gy, bin, len); |
| 512 | + |
| 513 | + DH_compute_key(dh); |
| 514 | + |
| 515 | + bin = Make_Binary(len); |
| 516 | + COPY_MEM(BIN_DATA(bin), dh->k, len); |
| 517 | + SET_BINARY(ret, bin); |
| 518 | + BIN_LEN(bin) = len; |
| 519 | + } |
| 520 | + |
| 521 | + if(ref_release) { |
| 522 | + if(dh->g != NULL) FREE_MEM(dh->data); |
| 523 | + CLEARS(dh); |
| 524 | + if(!ref_public && !ref_secret) return R_ARG1; |
| 525 | + } |
| 526 | + |
| 527 | + return R_RET; |
| 528 | + |
| 529 | +} |
0 commit comments