Sebastian Kuschel reports that pfd_closing can be called for a socket
[u/mdw/putty] / sshdh.c
CommitLineData
eaf1e20a 1/*
2 * Diffie-Hellman implementation for PuTTY.
3 */
4
e5574168 5#include "ssh.h"
6
e5574168 7/*
d1aaf71d 8 * The primes used in the group1 and group14 key exchange.
e5574168 9 */
d1aaf71d 10static const unsigned char P1[] = {
3709bfe9 11 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
12 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
13 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
14 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
15 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
16 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
17 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
18 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
19 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
20 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
21 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
e5574168 22};
d1aaf71d 23static const unsigned char P14[] = {
24 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
25 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
26 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
27 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
28 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
29 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
30 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
31 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
32 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
33 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
34 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
35 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
36 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
37 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
38 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
39 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
40 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
41 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
42 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
43 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
44 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
45 0xFF, 0xFF, 0xFF, 0xFF
46};
e5574168 47
48/*
d1aaf71d 49 * The generator g = 2 (used for both group1 and group14).
e5574168 50 */
27cd7fc2 51static const unsigned char G[] = { 2 };
e5574168 52
34557659 53static const struct ssh_kex ssh_diffiehellman_group1_sha1 = {
d1aaf71d 54 "diffie-hellman-group1-sha1", "group1",
fae1a71b 55 KEXTYPE_DH, P1, G, lenof(P1), lenof(G), &ssh_sha1
d1aaf71d 56};
57
34557659 58static const struct ssh_kex *const group1_list[] = {
59 &ssh_diffiehellman_group1_sha1
60};
61
62const struct ssh_kexes ssh_diffiehellman_group1 = {
63 sizeof(group1_list) / sizeof(*group1_list),
64 group1_list
65};
66
67static const struct ssh_kex ssh_diffiehellman_group14_sha1 = {
d1aaf71d 68 "diffie-hellman-group14-sha1", "group14",
fae1a71b 69 KEXTYPE_DH, P14, G, lenof(P14), lenof(G), &ssh_sha1
d1aaf71d 70};
71
34557659 72static const struct ssh_kex *const group14_list[] = {
73 &ssh_diffiehellman_group14_sha1
74};
75
76const struct ssh_kexes ssh_diffiehellman_group14 = {
77 sizeof(group14_list) / sizeof(*group14_list),
78 group14_list
79};
80
2ccb2fc8 81static const struct ssh_kex ssh_diffiehellman_gex_sha256 = {
82 "diffie-hellman-group-exchange-sha256", NULL,
fae1a71b 83 KEXTYPE_DH, NULL, NULL, 0, 0, &ssh_sha256
2ccb2fc8 84};
85
34557659 86static const struct ssh_kex ssh_diffiehellman_gex_sha1 = {
d1aaf71d 87 "diffie-hellman-group-exchange-sha1", NULL,
fae1a71b 88 KEXTYPE_DH, NULL, NULL, 0, 0, &ssh_sha1
d1aaf71d 89};
90
34557659 91static const struct ssh_kex *const gex_list[] = {
2ccb2fc8 92 &ssh_diffiehellman_gex_sha256,
34557659 93 &ssh_diffiehellman_gex_sha1
94};
95
96const struct ssh_kexes ssh_diffiehellman_gex = {
97 sizeof(gex_list) / sizeof(*gex_list),
98 gex_list
99};
100
e5574168 101/*
3709bfe9 102 * Variables.
e5574168 103 */
27cd7fc2 104struct dh_ctx {
105 Bignum x, e, p, q, qmask, g;
106};
e5574168 107
108/*
3709bfe9 109 * Common DH initialisation.
e5574168 110 */
27cd7fc2 111static void dh_init(struct dh_ctx *ctx)
32874aea 112{
27cd7fc2 113 ctx->q = bignum_rshift(ctx->p, 1);
114 ctx->qmask = bignum_bitmask(ctx->q);
115 ctx->x = ctx->e = NULL;
3709bfe9 116}
e5574168 117
118/*
d1aaf71d 119 * Initialise DH for a standard group.
e5574168 120 */
d1aaf71d 121void *dh_setup_group(const struct ssh_kex *kex)
32874aea 122{
3d88e64d 123 struct dh_ctx *ctx = snew(struct dh_ctx);
d1aaf71d 124 ctx->p = bignum_from_bytes(kex->pdata, kex->plen);
125 ctx->g = bignum_from_bytes(kex->gdata, kex->glen);
27cd7fc2 126 dh_init(ctx);
127 return ctx;
3709bfe9 128}
129
130/*
d1aaf71d 131 * Initialise DH for a server-supplied group.
a92dd380 132 */
d1aaf71d 133void *dh_setup_gex(Bignum pval, Bignum gval)
32874aea 134{
3d88e64d 135 struct dh_ctx *ctx = snew(struct dh_ctx);
27cd7fc2 136 ctx->p = copybn(pval);
137 ctx->g = copybn(gval);
138 dh_init(ctx);
139 return ctx;
a92dd380 140}
141
142/*
27cd7fc2 143 * Clean up and free a context.
3709bfe9 144 */
27cd7fc2 145void dh_cleanup(void *handle)
32874aea 146{
27cd7fc2 147 struct dh_ctx *ctx = (struct dh_ctx *)handle;
148 freebn(ctx->x);
149 freebn(ctx->e);
150 freebn(ctx->p);
151 freebn(ctx->g);
152 freebn(ctx->q);
153 freebn(ctx->qmask);
154 sfree(ctx);
3709bfe9 155}
e5574168 156
157/*
158 * DH stage 1: invent a number x between 1 and q, and compute e =
159 * g^x mod p. Return e.
7bd5a860 160 *
161 * If `nbits' is greater than zero, it is used as an upper limit
162 * for the number of bits in x. This is safe provided that (a) you
163 * use twice as many bits in x as the number of bits you expect to
164 * use in your session key, and (b) the DH group is a safe prime
165 * (which SSH demands that it must be).
166 *
167 * P. C. van Oorschot, M. J. Wiener
168 * "On Diffie-Hellman Key Agreement with Short Exponents".
169 * Advances in Cryptology: Proceedings of Eurocrypt '96
170 * Springer-Verlag, May 1996.
e5574168 171 */
27cd7fc2 172Bignum dh_create_e(void *handle, int nbits)
32874aea 173{
27cd7fc2 174 struct dh_ctx *ctx = (struct dh_ctx *)handle;
e5574168 175 int i;
176
3709bfe9 177 int nbytes;
178 unsigned char *buf;
179
27cd7fc2 180 nbytes = ssh1_bignum_length(ctx->qmask);
3d88e64d 181 buf = snewn(nbytes, unsigned char);
e5574168 182
a71540b9 183 do {
184 /*
185 * Create a potential x, by ANDing a string of random bytes
3709bfe9 186 * with qmask.
a71540b9 187 */
27cd7fc2 188 if (ctx->x)
189 freebn(ctx->x);
190 if (nbits == 0 || nbits > bignum_bitcount(ctx->qmask)) {
191 ssh1_write_bignum(buf, ctx->qmask);
7bd5a860 192 for (i = 2; i < nbytes; i++)
193 buf[i] &= random_byte();
0016d70b 194 ssh1_read_bignum(buf, nbytes, &ctx->x); /* can't fail */
7bd5a860 195 } else {
196 int b, nb;
27cd7fc2 197 ctx->x = bn_power_2(nbits);
2d466ffd 198 b = nb = 0;
7bd5a860 199 for (i = 0; i < nbits; i++) {
200 if (nb == 0) {
201 nb = 8;
202 b = random_byte();
203 }
27cd7fc2 204 bignum_set_bit(ctx->x, i, b & 1);
7bd5a860 205 b >>= 1;
206 nb--;
207 }
208 }
27cd7fc2 209 } while (bignum_cmp(ctx->x, One) <= 0 || bignum_cmp(ctx->x, ctx->q) >= 0);
e5574168 210
170c1e6e 211 sfree(buf);
212
e5574168 213 /*
214 * Done. Now compute e = g^x mod p.
215 */
27cd7fc2 216 ctx->e = modpow(ctx->g, ctx->x, ctx->p);
e5574168 217
27cd7fc2 218 return ctx->e;
e5574168 219}
220
221/*
222 * DH stage 2: given a number f, compute K = f^x mod p.
223 */
27cd7fc2 224Bignum dh_find_K(void *handle, Bignum f)
32874aea 225{
27cd7fc2 226 struct dh_ctx *ctx = (struct dh_ctx *)handle;
7bd5a860 227 Bignum ret;
27cd7fc2 228 ret = modpow(f, ctx->x, ctx->p);
7bd5a860 229 return ret;
e5574168 230}