-
Notifications
You must be signed in to change notification settings - Fork 65
/
ecdh_example.c
172 lines (128 loc) · 3.95 KB
/
ecdh_example.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
Diffie-Hellman key exchange (without HMAC) aka ECDH_anon in RFC4492
1. Alice picks a (secret) random natural number 'a', calculates P = a * G and sends P to Bob.
'a' is Alice's private key.
'P' is Alice's public key.
2. Bob picks a (secret) random natural number 'b', calculates Q = b * G and sends Q to Alice.
'b' is Bob's private key.
'Q' is Bob's public key.
3. Alice calculates S = a * Q = a * (b * G).
4. Bob calculates T = b * P = b * (a * G).
.. which are the same two values since multiplication in the field is commutative and associative.
T = S = the new shared secret.
Pseudo-random number generator inspired / stolen from: http://burtleburtle.net/bob/rand/smallprng.html
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "ecdh.h"
/* pseudo random number generator with 128 bit internal state... probably not suited for cryptographical usage */
typedef struct
{
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} prng_t;
static prng_t prng_ctx;
static uint32_t prng_rotate(uint32_t x, uint32_t k)
{
return (x << k) | (x >> (32 - k));
}
static uint32_t prng_next(void)
{
uint32_t e = prng_ctx.a - prng_rotate(prng_ctx.b, 27);
prng_ctx.a = prng_ctx.b ^ prng_rotate(prng_ctx.c, 17);
prng_ctx.b = prng_ctx.c + prng_ctx.d;
prng_ctx.c = prng_ctx.d + e;
prng_ctx.d = e + prng_ctx.a;
return prng_ctx.d;
}
static void prng_init(uint32_t seed)
{
uint32_t i;
prng_ctx.a = 0xf1ea5eed;
prng_ctx.b = prng_ctx.c = prng_ctx.d = seed;
for (i = 0; i < 31; ++i)
{
(void) prng_next();
}
}
static void ecdh_demo(void)
{
static uint8_t puba[ECC_PUB_KEY_SIZE];
static uint8_t prva[ECC_PRV_KEY_SIZE];
static uint8_t seca[ECC_PUB_KEY_SIZE];
static uint8_t pubb[ECC_PUB_KEY_SIZE];
static uint8_t prvb[ECC_PRV_KEY_SIZE];
static uint8_t secb[ECC_PUB_KEY_SIZE];
uint32_t i;
/* 0. Initialize and seed random number generator */
static int initialized = 0;
if (!initialized)
{
prng_init((0xbad ^ 0xc0ffee ^ 42) | 0xcafebabe | 666);
initialized = 1;
}
/* 1. Alice picks a (secret) random natural number 'a', calculates P = a * g and sends P to Bob. */
for (i = 0; i < ECC_PRV_KEY_SIZE; ++i)
{
prva[i] = prng_next();
}
assert(ecdh_generate_keys(puba, prva));
/* 2. Bob picks a (secret) random natural number 'b', calculates Q = b * g and sends Q to Alice. */
for (i = 0; i < ECC_PRV_KEY_SIZE; ++i)
{
prvb[i] = prng_next();
}
assert(ecdh_generate_keys(pubb, prvb));
/* 3. Alice calculates S = a * Q = a * (b * g). */
assert(ecdh_shared_secret(prva, pubb, seca));
/* 4. Bob calculates T = b * P = b * (a * g). */
assert(ecdh_shared_secret(prvb, puba, secb));
/* 5. Assert equality, i.e. check that both parties calculated the same value. */
for (i = 0; i < ECC_PUB_KEY_SIZE; ++i)
{
assert(seca[i] == secb[i]);
}
}
/* WARNING: This is not working correctly. ECDSA is not working... */
void ecdsa_broken()
{
static uint8_t prv[ECC_PRV_KEY_SIZE];
static uint8_t pub[ECC_PUB_KEY_SIZE];
static uint8_t msg[ECC_PRV_KEY_SIZE];
static uint8_t signature[ECC_PUB_KEY_SIZE];
static uint8_t k[ECC_PRV_KEY_SIZE];
uint32_t i;
srand(time(0));
srand(42);
for (i = 0; i < ECC_PRV_KEY_SIZE; ++i)
{
prv[i] = rand();
msg[i] = prv[i] ^ rand();
k[i] = rand();
}
/* int ecdsa_sign(const uint8_t* private, const uint8_t* hash, uint8_t* random_k, uint8_t* signature);
int ecdsa_verify(const uint8_t* public, const uint8_t* hash, uint8_t* signature); */
ecdh_generate_keys(pub, prv);
/* No asserts - ECDSA functionality is broken... */
ecdsa_sign((const uint8_t*)prv, msg, k, signature);
ecdsa_verify((const uint8_t*)pub, msg, (const uint8_t*)signature); /* fails... */
}
int main(int argc, char* argv[])
{
int i;
int ncycles = 1;
if (argc > 1)
{
ncycles = atoi(argv[1]);
}
for (i = 0; i < ncycles; ++i)
{
ecdh_demo();
ecdsa_broken();
}
return 0;
}