Skip to content

Commit b5378c5

Browse files
committed
FIX: Diffie-Hellman algorithm (missing files)
1 parent 740aaed commit b5378c5

File tree

7 files changed

+359
-2
lines changed

7 files changed

+359
-2
lines changed

src/core/n-crypt.c

+170-1
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@
3232
#include "sys-rc4.h"
3333
#include "sys-aes.h"
3434
#include "sys-rsa.h"
35+
#include "sys-dh.h"
3536

3637
const REBYTE rc4_name[] = "RC4-context"; //Used as a context handle name
3738
const REBYTE aes_name[] = "AES-context";
3839
const REBYTE rsa_name[] = "RSA-context";
40+
const REBYTE dh_name[] = "DH-Key";
3941

4042
/***********************************************************************
4143
**
@@ -101,7 +103,7 @@ const REBYTE rsa_name[] = "RSA-context";
101103
// /decrypt "Use the crypt-key for decryption (default is to encrypt)"
102104
// /stream
103105
// 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."
105107
// ]
106108
***********************************************************************/
107109
{
@@ -160,6 +162,14 @@ const REBYTE rsa_name[] = "RSA-context";
160162
}
161163

162164
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+
}
163173

164174
len = VAL_LEN(val_data);
165175
if (len == 0) return R_NONE;
@@ -358,3 +368,162 @@ const REBYTE rsa_name[] = "RSA-context";
358368
return R_RET;
359369

360370
}
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+
}

src/core/u-dh.c

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
Simple implementation of Diffie-Hellman algorithm (c) 2013 Richard Smolak
3+
The code uses Bigint implementation Copyright (c) 2007, Cameron Rich
4+
*/
5+
6+
#include "sys-dh.h"
7+
8+
void DH_generate_key(DH_CTX *dh_ctx)
9+
{
10+
BI_CTX *bi_ctx = bi_initialize();
11+
int len = dh_ctx->len;
12+
bigint *p = bi_import(bi_ctx, dh_ctx->p, len); //p modulus
13+
bigint *g = bi_import(bi_ctx, dh_ctx->g, dh_ctx->len_g); //generator
14+
bigint *x, *gx;
15+
16+
bi_permanent(g);
17+
18+
//generate private key X
19+
get_random_NZ(len, dh_ctx->x);
20+
x = bi_import(bi_ctx, dh_ctx->x, len);
21+
bi_permanent(x);
22+
23+
//calculate public key gx = g^x mod p
24+
bi_set_mod(bi_ctx, p, BIGINT_M_OFFSET);
25+
bi_ctx->mod_offset = BIGINT_M_OFFSET;
26+
gx = bi_mod_power(bi_ctx, g, x);
27+
bi_permanent(gx);
28+
29+
bi_export(bi_ctx, x, dh_ctx->x, len);
30+
bi_export(bi_ctx, gx, dh_ctx->gx, len);
31+
32+
bi_depermanent(g);
33+
bi_depermanent(x);
34+
bi_depermanent(gx);
35+
bi_free(bi_ctx, g);
36+
bi_free(bi_ctx, x);
37+
bi_free(bi_ctx, gx);
38+
39+
bi_free_mod(bi_ctx, BIGINT_M_OFFSET);
40+
bi_terminate(bi_ctx);
41+
}
42+
43+
void DH_compute_key(DH_CTX *dh_ctx)
44+
{
45+
BI_CTX *bi_ctx = bi_initialize();
46+
int len = dh_ctx->len;
47+
bigint *p = bi_import(bi_ctx, dh_ctx->p, len); //p modulus
48+
bigint *x = bi_import(bi_ctx, dh_ctx->x, len); //private key
49+
bigint *gy = bi_import(bi_ctx, dh_ctx->gy, len); //public key(peer)
50+
bigint *k; //negotiated(session) key
51+
52+
bi_permanent(x);
53+
bi_permanent(gy);
54+
55+
//calculate session key k = gy^x mod p
56+
bi_set_mod(bi_ctx, p, BIGINT_M_OFFSET);
57+
bi_ctx->mod_offset = BIGINT_M_OFFSET;
58+
k = bi_mod_power(bi_ctx, gy, x);
59+
bi_permanent(k);
60+
61+
bi_export(bi_ctx, k, dh_ctx->k, len);
62+
63+
bi_depermanent(x);
64+
bi_depermanent(gy);
65+
bi_depermanent(k);
66+
bi_free(bi_ctx, x);
67+
bi_free(bi_ctx, gy);
68+
bi_free(bi_ctx, k);
69+
70+
bi_free_mod(bi_ctx, BIGINT_M_OFFSET);
71+
bi_terminate(bi_ctx);
72+
}

src/include/sys-dh.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Simple implementation of Diffie-Hellman algorithm (c) 2013 Richard Smolak
3+
The code uses Bigint implementation Copyright (c) 2007, Cameron Rich
4+
*/
5+
6+
#include <stdint.h>
7+
#include "bigint.h"
8+
9+
typedef struct
10+
{
11+
int len; //length of modulus and keys in bytes
12+
int len_g; //length of generator in bytes
13+
int len_data; //length of allocated following data blob
14+
union {
15+
uint8_t *data; // head of following keys
16+
uint8_t *g; // generator
17+
};
18+
uint8_t *p; // prime modulus
19+
uint8_t *x; // private key
20+
uint8_t *gx; // public key(self)
21+
uint8_t *gy; // public key(peer)
22+
uint8_t *k; // negotiated key
23+
}
24+
DH_CTX;
25+
26+
27+
void DH_generate_key(
28+
DH_CTX *dh_ctx
29+
);
30+
31+
void DH_compute_key(
32+
DH_CTX *dh_ctx
33+
);
34+

src/mezz/boot-files.r

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,5 @@ REBOL [
5353
;-- protocols:
5454
[
5555
%prot-http.r
56-
%prot-tls.r
56+
;%prot-tls.r
5757
]

src/tests/run-tests.r3

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ wrap load %units/map-test.r3
1414
wrap load %units/power-test.r3
1515
wrap load %units/mezz-crypt-test.r3
1616
wrap load %units/rsa-test.r3
17+
wrap load %units/dh-test.r3
1718
wrap load %units/port-test.r3
1819

1920
***end-run***

0 commit comments

Comments
 (0)