curve25519: Add a plugin providing Curve25519 DH using backend drivers
[strongswan.git] / src / libstrongswan / plugins / curve25519 / curve25519_dh.c
1 /*
2 * Copyright (C) 2015 Martin Willi
3 * Copyright (C) 2015 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <string.h>
17 #include <stdint.h>
18
19 #include "curve25519_dh.h"
20 #include "curve25519_drv.h"
21
22 typedef struct private_curve25519_dh_t private_curve25519_dh_t;
23
24 /**
25 * Private data of an curve25519_dh_t object.
26 */
27 struct private_curve25519_dh_t {
28
29 /**
30 * Public curve25519_dh_t interface.
31 */
32 curve25519_dh_t public;
33
34 /**
35 * Shared key, if computed
36 */
37 u_char shared[CURVE25519_KEY_SIZE];
38
39 /**
40 * TRUE if shared secret is computed
41 */
42 bool computed;
43
44 /**
45 * Curve25519 backend
46 */
47 curve25519_drv_t *drv;
48 };
49
50 /**
51 * Generate a valid Curve25519 key
52 */
53 static bool generate_key(private_curve25519_dh_t *this)
54 {
55 u_char key[CURVE25519_KEY_SIZE];
56 rng_t *rng;
57
58 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
59 if (!rng)
60 {
61 DBG1(DBG_LIB, "no RNG found for quality %N",
62 rng_quality_names, RNG_STRONG);
63 return FALSE;
64 }
65 if (!rng->get_bytes(rng, CURVE25519_KEY_SIZE, key))
66 {
67 rng->destroy(rng);
68 return FALSE;
69 }
70 rng->destroy(rng);
71
72 return this->drv->set_key(this->drv, key);
73 }
74
75 METHOD(diffie_hellman_t, set_other_public_value, bool,
76 private_curve25519_dh_t *this, chunk_t value)
77 {
78 if (value.len == CURVE25519_KEY_SIZE)
79 {
80 if (this->drv->curve25519(this->drv, value.ptr, this->shared))
81 {
82 this->computed = TRUE;
83 return TRUE;
84 }
85 }
86 return FALSE;
87 }
88
89 METHOD(diffie_hellman_t, get_my_public_value, bool,
90 private_curve25519_dh_t *this, chunk_t *value)
91 {
92 u_char basepoint[CURVE25519_KEY_SIZE] = { 9 };
93
94 *value = chunk_alloc(CURVE25519_KEY_SIZE);
95 if (this->drv->curve25519(this->drv, basepoint, value->ptr))
96 {
97 return TRUE;
98 }
99 free(value->ptr);
100 return FALSE;
101 }
102
103 METHOD(diffie_hellman_t, set_private_value, bool,
104 private_curve25519_dh_t *this, chunk_t value)
105 {
106 if (value.len != CURVE25519_KEY_SIZE)
107 {
108 return FALSE;
109 }
110 return this->drv->set_key(this->drv, value.ptr);
111 }
112
113 METHOD(diffie_hellman_t, get_shared_secret, bool,
114 private_curve25519_dh_t *this, chunk_t *secret)
115 {
116 if (!this->computed)
117 {
118 return FALSE;
119 }
120 *secret = chunk_clone(chunk_from_thing(this->shared));
121 return TRUE;
122 }
123
124 METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
125 private_curve25519_dh_t *this)
126 {
127 return CURVE_25519;
128 }
129
130 METHOD(diffie_hellman_t, destroy, void,
131 private_curve25519_dh_t *this)
132 {
133 this->drv->destroy(this->drv);
134 free(this);
135 }
136
137 /*
138 * Described in header.
139 */
140 curve25519_dh_t *curve25519_dh_create(diffie_hellman_group_t group)
141 {
142 private_curve25519_dh_t *this;
143
144 if (group != CURVE_25519)
145 {
146 return FALSE;
147 }
148
149 INIT(this,
150 .public = {
151 .dh = {
152 .get_shared_secret = _get_shared_secret,
153 .set_other_public_value = _set_other_public_value,
154 .get_my_public_value = _get_my_public_value,
155 .set_private_value = _set_private_value,
156 .get_dh_group = _get_dh_group,
157 .destroy = _destroy,
158 },
159 },
160 .drv = curve25519_drv_probe(),
161 );
162
163 if (!this->drv)
164 {
165 free(this);
166 return NULL;
167 }
168 if (!generate_key(this))
169 {
170 destroy(this);
171 return NULL;
172 }
173 return &this->public;
174 }