chiark / gitweb /
ec-field-test.c: Make the field-element type use internal format.
[secnet] / xdh.c
1 /*
2  * xdh.c: x-coordinate-only Montgomery-ladder elliptic-curve Diffie--Hellman
3  */
4 /*
5  * This file is Free Software.  It was originally written for secnet.
6  *
7  * Copyright 2017 Mark Wooding
8  *
9  * You may redistribute secnet as a whole and/or modify it under the
10  * terms of the GNU General Public License as published by the Free
11  * Software Foundation; either version 3, or (at your option) any
12  * later version.
13  *
14  * You may redistribute this file and/or modify it under the terms of
15  * the GNU General Public License as published by the Free Software
16  * Foundation; either version 2, or (at your option) any later
17  * version.
18  *
19  * This software is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this software; if not, see
26  * https://www.gnu.org/licenses/gpl.html.
27  */
28
29 #include <stdio.h>
30 #include <limits.h>
31
32 #include "secnet.h"
33 #include "magic.h"
34 #include "util.h"
35
36 #include "x25519.h"
37 #include "x448.h"
38
39 #define XDH_MAXSZ 64
40
41 typedef void xdh_fn(uint8_t *z, const uint8_t *k, const uint8_t *x);
42
43 struct xdh {
44     closure_t cl;
45     struct dh_if ops;
46     xdh_fn *fn;
47     const uint8_t *base;
48 };
49
50 static int32_t xdh_makepublic(void *sst, void *pub, int32_t publen,
51                               uint8_t *k, int32_t klen)
52 {
53     struct xdh *st = sst;
54
55     assert(klen == st->ops.secret_len);
56     assert(publen >= st->ops.public_len);
57     st->fn(pub, k, st->base);
58     return st->ops.public_len;
59 }
60
61 static bool_t xdh_makeshared(void *sst,
62                              uint8_t *k, int32_t klen,
63                              const void *pub, int32_t publen,
64                              uint8_t *z, int32_t zlen)
65 {
66     struct xdh *st = sst;
67
68     assert(klen == st->ops.secret_len);
69     assert(zlen >= st->ops.shared_len);
70     if (publen != st->ops.public_len) {
71         Message(M_ERR,
72                 "xdh_makeshared: incoming public point has wrong length");
73         return False;
74     }
75     st->fn(z, k, pub);
76     return (True);
77 }
78
79 static void make_xdh_closure(dict_t *dict, const char *name, xdh_fn *fn,
80                              const uint8_t *base, size_t sz, int cap)
81 {
82     struct xdh *st;
83
84     NEW(st);
85     st->cl.description = name;
86     st->cl.type = CL_DH;
87     st->cl.apply = 0;
88     st->cl.interface = &st->ops;
89     st->ops.st = st;
90     st->ops.makepublic = xdh_makepublic;
91     st->ops.makeshared = xdh_makeshared;
92     st->ops.secret_len = st->ops.public_len = st->ops.shared_len = sz;
93     st->ops.capab_bit = cap;
94     st->fn = fn;
95     st->base = base;
96     dict_add(dict, name, new_closure(&st->cl));
97 }
98
99 void xdh_module(dict_t *dict)
100 {
101     make_xdh_closure(dict, "x25519", x25519, x25519_base,
102                      X25519_PUBSZ, CAPAB_BIT_X25519);
103     make_xdh_closure(dict, "x448", x448, x448_base,
104                      X448_PUBSZ, CAPAB_BIT_X448);
105 }