1 From 3d12521735e7ef7e48be217af0f27d68e23050a7 Mon Sep 17 00:00:00 2001
2 From: Vladislav Grishenko <themiron@users.noreply.github.com>
3 Date: Wed, 11 Mar 2020 21:09:45 +0500
4 Subject: [PATCH] Add Ed25519 support (#91)
6 * Add support for Ed25519 as a public key type
8 Ed25519 is a elliptic curve signature scheme that offers
9 better security than ECDSA and DSA and good performance. It may be
10 used for both user and host keys.
12 OpenSSH key import and fuzzer are not supported yet.
14 Initially inspired by Peter Szabo.
16 * Add curve25519 and ed25519 fuzzers
18 * Add import and export of Ed25519 keys
28 curve25519-donna.c | 860 -----------------------------------------
29 curve25519.c | 502 ++++++++++++++++++++++++
31 default_options.h | 7 +-
34 ed25519.c | 184 +++++++++
38 fuzz-hostkeys.c | 10 +
39 fuzzer-kexcurve25519.c | 72 ++++
43 keyimport.c | 158 +++++++-
50 30 files changed, 1289 insertions(+), 946 deletions(-)
51 delete mode 100644 curve25519-donna.c
52 create mode 100644 curve25519.c
53 create mode 100644 curve25519.h
54 create mode 100644 ed25519.c
55 create mode 100644 ed25519.h
56 create mode 100644 fuzzer-kexcurve25519.c
57 create mode 100644 gened25519.c
58 create mode 100644 gened25519.h
60 diff --git a/.travis.yml b/.travis.yml
61 index 9bcbce4..99499c8 100644
64 @@ -57,6 +57,7 @@ script:
65 - ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
66 - ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
67 - ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
68 + - ~/inst/bin/dropbearkey -t ed25519 -f tested25519
69 - test -z $DO_FUZZ || ./fuzzers_test.sh
72 diff --git a/FUZZER-NOTES.md b/FUZZER-NOTES.md
73 index 7b88238..4967eba 100644
76 @@ -72,3 +72,6 @@ Current fuzzers are
78 - [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh.
79 This is testing libtommath ECC routines.
81 +- [fuzzer-kexcurve25519](fuzzer-kexcurve25519.c) - test Curve25519 Elliptic Curve Diffie-Hellman key exchange
82 + like fuzzer-kexecdh. This is testing `dropbear_curve25519_scalarmult()` and other libtommath routines.
83 diff --git a/LICENSE b/LICENSE
84 index c400d94..a4849ff 100644
87 @@ -90,52 +90,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
93 -/* Copyright 2008, Google Inc.
94 - * All rights reserved.
96 - * Redistribution and use in source and binary forms, with or without
97 - * modification, are permitted provided that the following conditions are
100 - * * Redistributions of source code must retain the above copyright
101 - * notice, this list of conditions and the following disclaimer.
102 - * * Redistributions in binary form must reproduce the above
103 - * copyright notice, this list of conditions and the following disclaimer
104 - * in the documentation and/or other materials provided with the
106 - * * Neither the name of Google Inc. nor the names of its
107 - * contributors may be used to endorse or promote products derived from
108 - * this software without specific prior written permission.
110 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
111 - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
112 - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
113 - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
114 - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
115 - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
116 - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
117 - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
118 - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
119 - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
120 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
122 - * curve25519-donna: Curve25519 elliptic curve, public key function
124 - * http://code.google.com/p/curve25519-donna/
126 - * Adam Langley <agl@imperialviolet.org>
128 - * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
130 - * More information about curve25519 can be found here
131 - * http://cr.yp.to/ecdh.html
133 - * djb's sample implementation of curve25519 is written in a special assembly
134 - * language called qhasm and uses the floating point registers.
136 - * This is, almost, a clean room reimplementation from the curve25519 paper. It
137 - * uses many of the tricks described therein. Only the crecip function is taken
138 - * from the sample implementation.
143 +Modified TweetNaCl version 20140427, a self-contained public-domain C library.
144 +https://tweetnacl.cr.yp.to/
146 +Contributors (alphabetical order)
147 +Daniel J. Bernstein, University of Illinois at Chicago and Technische
148 +Universiteit Eindhoven
149 +Bernard van Gastel, Radboud Universiteit Nijmegen
150 +Wesley Janssen, Radboud Universiteit Nijmegen
151 +Tanja Lange, Technische Universiteit Eindhoven
152 +Peter Schwabe, Radboud Universiteit Nijmegen
153 +Sjaak Smetsers, Radboud Universiteit Nijmegen
156 +This work was supported by the U.S. National Science Foundation under grant
157 +1018836. "Any opinions, findings, and conclusions or recommendations expressed
158 +in this material are those of the author(s) and do not necessarily reflect the
159 +views of the National Science Foundation."
160 +This work was supported by the Netherlands Organisation for Scientific
161 +Research (NWO) under grant 639.073.005 and Veni 2013 project 13114.
162 diff --git a/Makefile.in b/Makefile.in
163 index bc55b7d..aaf7b3b 100644
166 @@ -36,8 +36,9 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
168 atomicio.o compat.o fake-rfc2553.o \
169 ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
170 + curve25519.o ed25519.o \
172 - gensignkey.o gendss.o genrsa.o
173 + gensignkey.o gendss.o genrsa.o gened25519.o
175 SVROBJS=svr-kex.o svr-auth.o sshpty.o \
176 svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
177 @@ -52,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
178 CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
179 common-channel.o common-chansession.o termcodes.o loginrec.o \
180 tcp-accept.o listener.o process-packet.o dh_groups.o \
181 - common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
182 + common-runopts.o circbuffer.o list.o netio.o
184 KEYOBJS=dropbearkey.o
186 @@ -264,7 +265,7 @@ tidy:
189 # list of fuzz targets
190 -FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh
191 +FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519
193 FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
195 @@ -303,6 +304,9 @@ fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
196 fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
197 $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
199 +fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
200 + $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
202 fuzzer-%.options: Makefile
203 echo "[libfuzzer]" > $@
204 echo "max_len = 50000" >> $@
205 @@ -313,7 +317,9 @@ fuzz-hostkeys:
206 dropbearkey -t rsa -f keyr
207 dropbearkey -t dss -f keyd
208 dropbearkey -t ecdsa -size 256 -f keye
209 + dropbearkey -t ed25519 -f keyed25519
211 /usr/bin/xxd -i -a keyr >> hostkeys.c
212 /usr/bin/xxd -i -a keye >> hostkeys.c
213 /usr/bin/xxd -i -a keyd >> hostkeys.c
214 + /usr/bin/xxd -i -a keyed25519 >> hostkeys.c
215 diff --git a/README b/README
216 index b8a6fd2..d197ec7 100644
219 @@ -55,6 +55,7 @@ To run the server, you need to generate server keys, this is one-off:
220 ./dropbearkey -t rsa -f dropbear_rsa_host_key
221 ./dropbearkey -t dss -f dropbear_dss_host_key
222 ./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
223 +./dropbearkey -t ed25519 -f dropbear_ed25519_host_key
225 or alternatively convert OpenSSH keys to Dropbear:
226 ./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
227 diff --git a/cli-kex.c b/cli-kex.c
228 index b02cfc7..7cefb5f 100644
231 @@ -81,7 +81,7 @@ void send_msg_kexdh_init() {
233 cli_ses.curve25519_param = gen_kexcurve25519_param();
235 - buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
236 + buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
240 diff --git a/common-algo.c b/common-algo.c
241 index 2f896ab..558aad2 100644
244 @@ -222,6 +222,9 @@ algo_type ssh_nocompress[] = {
247 algo_type sshhostkey[] = {
248 +#if DROPBEAR_ED25519
249 + {"ssh-ed25519", DROPBEAR_SIGNKEY_ED25519, NULL, 1, NULL},
253 {"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
254 diff --git a/common-kex.c b/common-kex.c
255 index d4933dd..16b7e27 100644
259 #include "dbrandom.h"
262 +#include "curve25519.h"
263 #include "crypto_desc.h"
265 static void kexinitialise(void);
266 @@ -703,23 +704,18 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
267 #endif /* DROPBEAR_ECDH */
269 #if DROPBEAR_CURVE25519
270 -struct kex_curve25519_param *gen_kexcurve25519_param () {
271 +struct kex_curve25519_param *gen_kexcurve25519_param() {
272 /* Per http://cr.yp.to/ecdh.html */
273 struct kex_curve25519_param *param = m_malloc(sizeof(*param));
274 const unsigned char basepoint[32] = {9};
276 genrandom(param->priv, CURVE25519_LEN);
277 - param->priv[0] &= 248;
278 - param->priv[31] &= 127;
279 - param->priv[31] |= 64;
281 - curve25519_donna(param->pub, param->priv, basepoint);
282 + dropbear_curve25519_scalarmult(param->pub, param->priv, basepoint);
287 -void free_kexcurve25519_param(struct kex_curve25519_param *param)
289 +void free_kexcurve25519_param(struct kex_curve25519_param *param) {
290 m_burn(param->priv, CURVE25519_LEN);
293 @@ -736,7 +732,7 @@ void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buff
294 dropbear_exit("Bad curve25519");
297 - curve25519_donna(out, param->priv, buf_pub_them->data);
298 + dropbear_curve25519_scalarmult(out, param->priv, buf_pub_them->data);
300 if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) {
301 dropbear_exit("Bad curve25519");
302 diff --git a/curve25519-donna.c b/curve25519-donna.c
303 deleted file mode 100644
304 index ef0b6d1..0000000
305 --- a/curve25519-donna.c
308 -/* Copyright 2008, Google Inc.
309 - * All rights reserved.
311 - * Redistribution and use in source and binary forms, with or without
312 - * modification, are permitted provided that the following conditions are
315 - * * Redistributions of source code must retain the above copyright
316 - * notice, this list of conditions and the following disclaimer.
317 - * * Redistributions in binary form must reproduce the above
318 - * copyright notice, this list of conditions and the following disclaimer
319 - * in the documentation and/or other materials provided with the
321 - * * Neither the name of Google Inc. nor the names of its
322 - * contributors may be used to endorse or promote products derived from
323 - * this software without specific prior written permission.
325 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
326 - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
327 - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
328 - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
329 - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
330 - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
331 - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
332 - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
333 - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
334 - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
335 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
337 - * curve25519-donna: Curve25519 elliptic curve, public key function
339 - * http://code.google.com/p/curve25519-donna/
341 - * Adam Langley <agl@imperialviolet.org>
343 - * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
345 - * More information about curve25519 can be found here
346 - * http://cr.yp.to/ecdh.html
348 - * djb's sample implementation of curve25519 is written in a special assembly
349 - * language called qhasm and uses the floating point registers.
351 - * This is, almost, a clean room reimplementation from the curve25519 paper. It
352 - * uses many of the tricks described therein. Only the crecip function is taken
353 - * from the sample implementation. */
359 -#define inline __inline
363 -typedef int32_t s32;
364 -typedef int64_t limb;
366 -/* Field element representation:
368 - * Field elements are written as an array of signed, 64-bit limbs, least
369 - * significant first. The value of the field element is:
370 - * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
372 - * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */
374 -/* Sum two numbers: output += in */
375 -static void fsum(limb *output, const limb *in) {
377 - for (i = 0; i < 10; i += 2) {
378 - output[0+i] = output[0+i] + in[0+i];
379 - output[1+i] = output[1+i] + in[1+i];
383 -/* Find the difference of two numbers: output = in - output
384 - * (note the order of the arguments!). */
385 -static void fdifference(limb *output, const limb *in) {
387 - for (i = 0; i < 10; ++i) {
388 - output[i] = in[i] - output[i];
392 -/* Multiply a number by a scalar: output = in * scalar */
393 -static void fscalar_product(limb *output, const limb *in, const limb scalar) {
395 - for (i = 0; i < 10; ++i) {
396 - output[i] = in[i] * scalar;
400 -/* Multiply two numbers: output = in2 * in
402 - * output must be distinct to both inputs. The inputs are reduced coefficient
403 - * form, the output is not.
405 - * output[x] <= 14 * the largest product of the input limbs. */
406 -static void fproduct(limb *output, const limb *in2, const limb *in) {
407 - output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
408 - output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
409 - ((limb) ((s32) in2[1])) * ((s32) in[0]);
410 - output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
411 - ((limb) ((s32) in2[0])) * ((s32) in[2]) +
412 - ((limb) ((s32) in2[2])) * ((s32) in[0]);
413 - output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
414 - ((limb) ((s32) in2[2])) * ((s32) in[1]) +
415 - ((limb) ((s32) in2[0])) * ((s32) in[3]) +
416 - ((limb) ((s32) in2[3])) * ((s32) in[0]);
417 - output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
418 - 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
419 - ((limb) ((s32) in2[3])) * ((s32) in[1])) +
420 - ((limb) ((s32) in2[0])) * ((s32) in[4]) +
421 - ((limb) ((s32) in2[4])) * ((s32) in[0]);
422 - output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
423 - ((limb) ((s32) in2[3])) * ((s32) in[2]) +
424 - ((limb) ((s32) in2[1])) * ((s32) in[4]) +
425 - ((limb) ((s32) in2[4])) * ((s32) in[1]) +
426 - ((limb) ((s32) in2[0])) * ((s32) in[5]) +
427 - ((limb) ((s32) in2[5])) * ((s32) in[0]);
428 - output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
429 - ((limb) ((s32) in2[1])) * ((s32) in[5]) +
430 - ((limb) ((s32) in2[5])) * ((s32) in[1])) +
431 - ((limb) ((s32) in2[2])) * ((s32) in[4]) +
432 - ((limb) ((s32) in2[4])) * ((s32) in[2]) +
433 - ((limb) ((s32) in2[0])) * ((s32) in[6]) +
434 - ((limb) ((s32) in2[6])) * ((s32) in[0]);
435 - output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
436 - ((limb) ((s32) in2[4])) * ((s32) in[3]) +
437 - ((limb) ((s32) in2[2])) * ((s32) in[5]) +
438 - ((limb) ((s32) in2[5])) * ((s32) in[2]) +
439 - ((limb) ((s32) in2[1])) * ((s32) in[6]) +
440 - ((limb) ((s32) in2[6])) * ((s32) in[1]) +
441 - ((limb) ((s32) in2[0])) * ((s32) in[7]) +
442 - ((limb) ((s32) in2[7])) * ((s32) in[0]);
443 - output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
444 - 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
445 - ((limb) ((s32) in2[5])) * ((s32) in[3]) +
446 - ((limb) ((s32) in2[1])) * ((s32) in[7]) +
447 - ((limb) ((s32) in2[7])) * ((s32) in[1])) +
448 - ((limb) ((s32) in2[2])) * ((s32) in[6]) +
449 - ((limb) ((s32) in2[6])) * ((s32) in[2]) +
450 - ((limb) ((s32) in2[0])) * ((s32) in[8]) +
451 - ((limb) ((s32) in2[8])) * ((s32) in[0]);
452 - output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
453 - ((limb) ((s32) in2[5])) * ((s32) in[4]) +
454 - ((limb) ((s32) in2[3])) * ((s32) in[6]) +
455 - ((limb) ((s32) in2[6])) * ((s32) in[3]) +
456 - ((limb) ((s32) in2[2])) * ((s32) in[7]) +
457 - ((limb) ((s32) in2[7])) * ((s32) in[2]) +
458 - ((limb) ((s32) in2[1])) * ((s32) in[8]) +
459 - ((limb) ((s32) in2[8])) * ((s32) in[1]) +
460 - ((limb) ((s32) in2[0])) * ((s32) in[9]) +
461 - ((limb) ((s32) in2[9])) * ((s32) in[0]);
462 - output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
463 - ((limb) ((s32) in2[3])) * ((s32) in[7]) +
464 - ((limb) ((s32) in2[7])) * ((s32) in[3]) +
465 - ((limb) ((s32) in2[1])) * ((s32) in[9]) +
466 - ((limb) ((s32) in2[9])) * ((s32) in[1])) +
467 - ((limb) ((s32) in2[4])) * ((s32) in[6]) +
468 - ((limb) ((s32) in2[6])) * ((s32) in[4]) +
469 - ((limb) ((s32) in2[2])) * ((s32) in[8]) +
470 - ((limb) ((s32) in2[8])) * ((s32) in[2]);
471 - output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
472 - ((limb) ((s32) in2[6])) * ((s32) in[5]) +
473 - ((limb) ((s32) in2[4])) * ((s32) in[7]) +
474 - ((limb) ((s32) in2[7])) * ((s32) in[4]) +
475 - ((limb) ((s32) in2[3])) * ((s32) in[8]) +
476 - ((limb) ((s32) in2[8])) * ((s32) in[3]) +
477 - ((limb) ((s32) in2[2])) * ((s32) in[9]) +
478 - ((limb) ((s32) in2[9])) * ((s32) in[2]);
479 - output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
480 - 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
481 - ((limb) ((s32) in2[7])) * ((s32) in[5]) +
482 - ((limb) ((s32) in2[3])) * ((s32) in[9]) +
483 - ((limb) ((s32) in2[9])) * ((s32) in[3])) +
484 - ((limb) ((s32) in2[4])) * ((s32) in[8]) +
485 - ((limb) ((s32) in2[8])) * ((s32) in[4]);
486 - output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
487 - ((limb) ((s32) in2[7])) * ((s32) in[6]) +
488 - ((limb) ((s32) in2[5])) * ((s32) in[8]) +
489 - ((limb) ((s32) in2[8])) * ((s32) in[5]) +
490 - ((limb) ((s32) in2[4])) * ((s32) in[9]) +
491 - ((limb) ((s32) in2[9])) * ((s32) in[4]);
492 - output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
493 - ((limb) ((s32) in2[5])) * ((s32) in[9]) +
494 - ((limb) ((s32) in2[9])) * ((s32) in[5])) +
495 - ((limb) ((s32) in2[6])) * ((s32) in[8]) +
496 - ((limb) ((s32) in2[8])) * ((s32) in[6]);
497 - output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
498 - ((limb) ((s32) in2[8])) * ((s32) in[7]) +
499 - ((limb) ((s32) in2[6])) * ((s32) in[9]) +
500 - ((limb) ((s32) in2[9])) * ((s32) in[6]);
501 - output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
502 - 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
503 - ((limb) ((s32) in2[9])) * ((s32) in[7]));
504 - output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
505 - ((limb) ((s32) in2[9])) * ((s32) in[8]);
506 - output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
509 -/* Reduce a long form to a short form by taking the input mod 2^255 - 19.
511 - * On entry: |output[i]| < 14*2^54
512 - * On exit: |output[0..8]| < 280*2^54 */
513 -static void freduce_degree(limb *output) {
514 - /* Each of these shifts and adds ends up multiplying the value by 19.
516 - * For output[0..8], the absolute entry value is < 14*2^54 and we add, at
517 - * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */
518 - output[8] += output[18] << 4;
519 - output[8] += output[18] << 1;
520 - output[8] += output[18];
521 - output[7] += output[17] << 4;
522 - output[7] += output[17] << 1;
523 - output[7] += output[17];
524 - output[6] += output[16] << 4;
525 - output[6] += output[16] << 1;
526 - output[6] += output[16];
527 - output[5] += output[15] << 4;
528 - output[5] += output[15] << 1;
529 - output[5] += output[15];
530 - output[4] += output[14] << 4;
531 - output[4] += output[14] << 1;
532 - output[4] += output[14];
533 - output[3] += output[13] << 4;
534 - output[3] += output[13] << 1;
535 - output[3] += output[13];
536 - output[2] += output[12] << 4;
537 - output[2] += output[12] << 1;
538 - output[2] += output[12];
539 - output[1] += output[11] << 4;
540 - output[1] += output[11] << 1;
541 - output[1] += output[11];
542 - output[0] += output[10] << 4;
543 - output[0] += output[10] << 1;
544 - output[0] += output[10];
548 -#error "This code only works on a two's complement system"
551 -/* return v / 2^26, using only shifts and adds.
553 - * On entry: v can take any value. */
555 -div_by_2_26(const limb v)
557 - /* High word of v; no shift needed. */
558 - const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
559 - /* Set to all 1s if v was negative; else set to 0s. */
560 - const int32_t sign = ((int32_t) highword) >> 31;
561 - /* Set to 0x3ffffff if v was negative; else set to 0. */
562 - const int32_t roundoff = ((uint32_t) sign) >> 6;
563 - /* Should return v / (1<<26) */
564 - return (v + roundoff) >> 26;
567 -/* return v / (2^25), using only shifts and adds.
569 - * On entry: v can take any value. */
571 -div_by_2_25(const limb v)
573 - /* High word of v; no shift needed*/
574 - const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
575 - /* Set to all 1s if v was negative; else set to 0s. */
576 - const int32_t sign = ((int32_t) highword) >> 31;
577 - /* Set to 0x1ffffff if v was negative; else set to 0. */
578 - const int32_t roundoff = ((uint32_t) sign) >> 7;
579 - /* Should return v / (1<<25) */
580 - return (v + roundoff) >> 25;
583 -/* Reduce all coefficients of the short form input so that |x| < 2^26.
585 - * On entry: |output[i]| < 280*2^54 */
586 -static void freduce_coefficients(limb *output) {
591 - for (i = 0; i < 10; i += 2) {
592 - limb over = div_by_2_26(output[i]);
593 - /* The entry condition (that |output[i]| < 280*2^54) means that over is, at
594 - * most, 280*2^28 in the first iteration of this loop. This is added to the
595 - * next limb and we can approximate the resulting bound of that limb by
597 - output[i] -= over << 26;
598 - output[i+1] += over;
600 - /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| <
601 - * 281*2^29. When this is added to the next limb, the resulting bound can
602 - * be approximated as 281*2^54.
604 - * For subsequent iterations of the loop, 281*2^54 remains a conservative
605 - * bound and no overflow occurs. */
606 - over = div_by_2_25(output[i+1]);
607 - output[i+1] -= over << 25;
608 - output[i+2] += over;
610 - /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */
611 - output[0] += output[10] << 4;
612 - output[0] += output[10] << 1;
613 - output[0] += output[10];
617 - /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29
618 - * So |over| will be no more than 2^16. */
620 - limb over = div_by_2_26(output[0]);
621 - output[0] -= over << 26;
625 - /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The
626 - * bound on |output[1]| is sufficient to meet our needs. */
629 -/* A helpful wrapper around fproduct: output = in * in2.
631 - * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27.
633 - * output must be distinct to both inputs. The output is reduced degree
634 - * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */
636 -fmul(limb *output, const limb *in, const limb *in2) {
638 - fproduct(t, in, in2);
639 - /* |t[i]| < 14*2^54 */
641 - freduce_coefficients(t);
642 - /* |t[i]| < 2^26 */
643 - memcpy(output, t, sizeof(limb) * 10);
646 -/* Square a number: output = in**2
648 - * output must be distinct from the input. The inputs are reduced coefficient
649 - * form, the output is not.
651 - * output[x] <= 14 * the largest product of the input limbs. */
652 -static void fsquare_inner(limb *output, const limb *in) {
653 - output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
654 - output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
655 - output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
656 - ((limb) ((s32) in[0])) * ((s32) in[2]));
657 - output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
658 - ((limb) ((s32) in[0])) * ((s32) in[3]));
659 - output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
660 - 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
661 - 2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
662 - output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
663 - ((limb) ((s32) in[1])) * ((s32) in[4]) +
664 - ((limb) ((s32) in[0])) * ((s32) in[5]));
665 - output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
666 - ((limb) ((s32) in[2])) * ((s32) in[4]) +
667 - ((limb) ((s32) in[0])) * ((s32) in[6]) +
668 - 2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
669 - output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
670 - ((limb) ((s32) in[2])) * ((s32) in[5]) +
671 - ((limb) ((s32) in[1])) * ((s32) in[6]) +
672 - ((limb) ((s32) in[0])) * ((s32) in[7]));
673 - output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
674 - 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
675 - ((limb) ((s32) in[0])) * ((s32) in[8]) +
676 - 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
677 - ((limb) ((s32) in[3])) * ((s32) in[5])));
678 - output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
679 - ((limb) ((s32) in[3])) * ((s32) in[6]) +
680 - ((limb) ((s32) in[2])) * ((s32) in[7]) +
681 - ((limb) ((s32) in[1])) * ((s32) in[8]) +
682 - ((limb) ((s32) in[0])) * ((s32) in[9]));
683 - output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
684 - ((limb) ((s32) in[4])) * ((s32) in[6]) +
685 - ((limb) ((s32) in[2])) * ((s32) in[8]) +
686 - 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
687 - ((limb) ((s32) in[1])) * ((s32) in[9])));
688 - output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
689 - ((limb) ((s32) in[4])) * ((s32) in[7]) +
690 - ((limb) ((s32) in[3])) * ((s32) in[8]) +
691 - ((limb) ((s32) in[2])) * ((s32) in[9]));
692 - output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
693 - 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
694 - 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
695 - ((limb) ((s32) in[3])) * ((s32) in[9])));
696 - output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
697 - ((limb) ((s32) in[5])) * ((s32) in[8]) +
698 - ((limb) ((s32) in[4])) * ((s32) in[9]));
699 - output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
700 - ((limb) ((s32) in[6])) * ((s32) in[8]) +
701 - 2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
702 - output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
703 - ((limb) ((s32) in[6])) * ((s32) in[9]));
704 - output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
705 - 4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
706 - output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
707 - output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
710 -/* fsquare sets output = in^2.
712 - * On entry: The |in| argument is in reduced coefficients form and |in[i]| <
715 - * On exit: The |output| argument is in reduced coefficients form (indeed, one
716 - * need only provide storage for 10 limbs) and |out[i]| < 2^26. */
718 -fsquare(limb *output, const limb *in) {
720 - fsquare_inner(t, in);
721 - /* |t[i]| < 14*2^54 because the largest product of two limbs will be <
722 - * 2^(27+27) and fsquare_inner adds together, at most, 14 of those
725 - freduce_coefficients(t);
726 - /* |t[i]| < 2^26 */
727 - memcpy(output, t, sizeof(limb) * 10);
730 -/* Take a little-endian, 32-byte number and expand it into polynomial form */
732 -fexpand(limb *output, const u8 *input) {
733 -#define F(n,start,shift,mask) \
734 - output[n] = ((((limb) input[start + 0]) | \
735 - ((limb) input[start + 1]) << 8 | \
736 - ((limb) input[start + 2]) << 16 | \
737 - ((limb) input[start + 3]) << 24) >> shift) & mask;
738 - F(0, 0, 0, 0x3ffffff);
739 - F(1, 3, 2, 0x1ffffff);
740 - F(2, 6, 3, 0x3ffffff);
741 - F(3, 9, 5, 0x1ffffff);
742 - F(4, 12, 6, 0x3ffffff);
743 - F(5, 16, 0, 0x1ffffff);
744 - F(6, 19, 1, 0x3ffffff);
745 - F(7, 22, 3, 0x1ffffff);
746 - F(8, 25, 4, 0x3ffffff);
747 - F(9, 28, 6, 0x1ffffff);
751 -#if (-32 >> 1) != -16
752 -#error "This code only works when >> does sign-extension on negative numbers"
755 -/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */
756 -static s32 s32_eq(s32 a, s32 b) {
766 -/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are
767 - * both non-negative. */
768 -static s32 s32_gte(s32 a, s32 b) {
770 - /* a >= 0 iff a >= b. */
774 -/* Take a fully reduced polynomial form number and contract it into a
775 - * little-endian, 32-byte array.
777 - * On entry: |input_limbs[i]| < 2^26 */
779 -fcontract(u8 *output, limb *input_limbs) {
785 - /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */
786 - for (i = 0; i < 10; i++) {
787 - input[i] = input_limbs[i];
790 - for (j = 0; j < 2; ++j) {
791 - for (i = 0; i < 9; ++i) {
792 - if ((i & 1) == 1) {
793 - /* This calculation is a time-invariant way to make input[i]
794 - * non-negative by borrowing from the next-larger limb. */
795 - const s32 mask = input[i] >> 31;
796 - const s32 carry = -((input[i] & mask) >> 25);
797 - input[i] = input[i] + (carry << 25);
798 - input[i+1] = input[i+1] - carry;
800 - const s32 mask = input[i] >> 31;
801 - const s32 carry = -((input[i] & mask) >> 26);
802 - input[i] = input[i] + (carry << 26);
803 - input[i+1] = input[i+1] - carry;
807 - /* There's no greater limb for input[9] to borrow from, but we can multiply
808 - * by 19 and borrow from input[0], which is valid mod 2^255-19. */
810 - const s32 mask = input[9] >> 31;
811 - const s32 carry = -((input[9] & mask) >> 25);
812 - input[9] = input[9] + (carry << 25);
813 - input[0] = input[0] - (carry * 19);
816 - /* After the first iteration, input[1..9] are non-negative and fit within
817 - * 25 or 26 bits, depending on position. However, input[0] may be
821 - /* The first borrow-propagation pass above ended with every limb
822 - except (possibly) input[0] non-negative.
824 - If input[0] was negative after the first pass, then it was because of a
825 - carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most,
826 - one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19.
828 - In the second pass, each limb is decreased by at most one. Thus the second
829 - borrow-propagation pass could only have wrapped around to decrease
830 - input[0] again if the first pass left input[0] negative *and* input[1]
831 - through input[9] were all zero. In that case, input[1] is now 2^25 - 1,
832 - and this last borrow-propagation step will leave input[1] non-negative. */
834 - const s32 mask = input[0] >> 31;
835 - const s32 carry = -((input[0] & mask) >> 26);
836 - input[0] = input[0] + (carry << 26);
837 - input[1] = input[1] - carry;
840 - /* All input[i] are now non-negative. However, there might be values between
841 - * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */
842 - for (j = 0; j < 2; j++) {
843 - for (i = 0; i < 9; i++) {
844 - if ((i & 1) == 1) {
845 - const s32 carry = input[i] >> 25;
846 - input[i] &= 0x1ffffff;
847 - input[i+1] += carry;
849 - const s32 carry = input[i] >> 26;
850 - input[i] &= 0x3ffffff;
851 - input[i+1] += carry;
856 - const s32 carry = input[9] >> 25;
857 - input[9] &= 0x1ffffff;
858 - input[0] += 19*carry;
862 - /* If the first carry-chain pass, just above, ended up with a carry from
863 - * input[9], and that caused input[0] to be out-of-bounds, then input[0] was
864 - * < 2^26 + 2*19, because the carry was, at most, two.
866 - * If the second pass carried from input[9] again then input[0] is < 2*19 and
867 - * the input[9] -> input[0] carry didn't push input[0] out of bounds. */
869 - /* It still remains the case that input might be between 2^255-19 and 2^255.
870 - * In this case, input[1..9] must take their maximum value and input[0] must
871 - * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */
872 - mask = s32_gte(input[0], 0x3ffffed);
873 - for (i = 1; i < 10; i++) {
874 - if ((i & 1) == 1) {
875 - mask &= s32_eq(input[i], 0x1ffffff);
877 - mask &= s32_eq(input[i], 0x3ffffff);
881 - /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus
882 - * this conditionally subtracts 2^255-19. */
883 - input[0] -= mask & 0x3ffffed;
885 - for (i = 1; i < 10; i++) {
886 - if ((i & 1) == 1) {
887 - input[i] -= mask & 0x1ffffff;
889 - input[i] -= mask & 0x3ffffff;
902 - output[s+0] |= input[i] & 0xff; \
903 - output[s+1] = (input[i] >> 8) & 0xff; \
904 - output[s+2] = (input[i] >> 16) & 0xff; \
905 - output[s+3] = (input[i] >> 24) & 0xff;
921 -/* Input: Q, Q', Q-Q'
926 - * x z: short form, destroyed
927 - * xprime zprime: short form, destroyed
928 - * qmqp: short form, preserved
930 - * On entry and exit, the absolute value of the limbs of all inputs and outputs
932 -static void fmonty(limb *x2, limb *z2, /* output 2Q */
933 - limb *x3, limb *z3, /* output Q + Q' */
934 - limb *x, limb *z, /* input Q */
935 - limb *xprime, limb *zprime, /* input Q' */
936 - const limb *qmqp /* input Q - Q' */) {
937 - limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
938 - zzprime[19], zzzprime[19], xxxprime[19];
940 - memcpy(origx, x, 10 * sizeof(limb));
942 - /* |x[i]| < 2^27 */
943 - fdifference(z, origx); /* does x - z */
944 - /* |z[i]| < 2^27 */
946 - memcpy(origxprime, xprime, sizeof(limb) * 10);
947 - fsum(xprime, zprime);
948 - /* |xprime[i]| < 2^27 */
949 - fdifference(zprime, origxprime);
950 - /* |zprime[i]| < 2^27 */
951 - fproduct(xxprime, xprime, z);
952 - /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be <
953 - * 2^(27+27) and fproduct adds together, at most, 14 of those products.
954 - * (Approximating that to 2^58 doesn't work out.) */
955 - fproduct(zzprime, x, zprime);
956 - /* |zzprime[i]| < 14*2^54 */
957 - freduce_degree(xxprime);
958 - freduce_coefficients(xxprime);
959 - /* |xxprime[i]| < 2^26 */
960 - freduce_degree(zzprime);
961 - freduce_coefficients(zzprime);
962 - /* |zzprime[i]| < 2^26 */
963 - memcpy(origxprime, xxprime, sizeof(limb) * 10);
964 - fsum(xxprime, zzprime);
965 - /* |xxprime[i]| < 2^27 */
966 - fdifference(zzprime, origxprime);
967 - /* |zzprime[i]| < 2^27 */
968 - fsquare(xxxprime, xxprime);
969 - /* |xxxprime[i]| < 2^26 */
970 - fsquare(zzzprime, zzprime);
971 - /* |zzzprime[i]| < 2^26 */
972 - fproduct(zzprime, zzzprime, qmqp);
973 - /* |zzprime[i]| < 14*2^52 */
974 - freduce_degree(zzprime);
975 - freduce_coefficients(zzprime);
976 - /* |zzprime[i]| < 2^26 */
977 - memcpy(x3, xxxprime, sizeof(limb) * 10);
978 - memcpy(z3, zzprime, sizeof(limb) * 10);
981 - /* |xx[i]| < 2^26 */
983 - /* |zz[i]| < 2^26 */
984 - fproduct(x2, xx, zz);
985 - /* |x2[i]| < 14*2^52 */
986 - freduce_degree(x2);
987 - freduce_coefficients(x2);
988 - /* |x2[i]| < 2^26 */
989 - fdifference(zz, xx); /* does zz = xx - zz */
990 - /* |zz[i]| < 2^27 */
991 - memset(zzz + 10, 0, sizeof(limb) * 9);
992 - fscalar_product(zzz, zz, 121665);
993 - /* |zzz[i]| < 2^(27+17) */
994 - /* No need to call freduce_degree here:
995 - fscalar_product doesn't increase the degree of its input. */
996 - freduce_coefficients(zzz);
997 - /* |zzz[i]| < 2^26 */
999 - /* |zzz[i]| < 2^27 */
1000 - fproduct(z2, zz, zzz);
1001 - /* |z2[i]| < 14*2^(26+27) */
1002 - freduce_degree(z2);
1003 - freduce_coefficients(z2);
1004 - /* |z2|i| < 2^26 */
1007 -/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
1008 - * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
1009 - * side-channel attacks.
1011 - * NOTE that this function requires that 'iswap' be 1 or 0; other values give
1012 - * wrong results. Also, the two limb arrays must be in reduced-coefficient,
1013 - * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
1014 - * and all all values in a[0..9],b[0..9] must have magnitude less than
1017 -swap_conditional(limb a[19], limb b[19], limb iswap) {
1019 - const s32 swap = (s32) -iswap;
1021 - for (i = 0; i < 10; ++i) {
1022 - const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
1023 - a[i] = ((s32)a[i]) ^ x;
1024 - b[i] = ((s32)b[i]) ^ x;
1028 -/* Calculates nQ where Q is the x-coordinate of a point on the curve
1030 - * resultx/resultz: the x coordinate of the resulting curve point (short form)
1031 - * n: a little endian, 32-byte number
1032 - * q: a point of the curve (short form) */
1034 -cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
1035 - limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
1036 - limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
1037 - limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
1038 - limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
1042 - memcpy(nqpqx, q, sizeof(limb) * 10);
1044 - for (i = 0; i < 32; ++i) {
1045 - u8 byte = n[31 - i];
1046 - for (j = 0; j < 8; ++j) {
1047 - const limb bit = byte >> 7;
1049 - swap_conditional(nqx, nqpqx, bit);
1050 - swap_conditional(nqz, nqpqz, bit);
1051 - fmonty(nqx2, nqz2,
1056 - swap_conditional(nqx2, nqpqx2, bit);
1057 - swap_conditional(nqz2, nqpqz2, bit);
1076 - memcpy(resultx, nqx, sizeof(limb) * 10);
1077 - memcpy(resultz, nqz, sizeof(limb) * 10);
1080 -/* -----------------------------------------------------------------------------
1081 - * Shamelessly copied from djb's code
1082 - * ----------------------------------------------------------------------------- */
1084 -crecip(limb *out, const limb *z) {
1092 - limb z2_100_0[10];
1097 - /* 2 */ fsquare(z2,z);
1098 - /* 4 */ fsquare(t1,z2);
1099 - /* 8 */ fsquare(t0,t1);
1100 - /* 9 */ fmul(z9,t0,z);
1101 - /* 11 */ fmul(z11,z9,z2);
1102 - /* 22 */ fsquare(t0,z11);
1103 - /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
1105 - /* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
1106 - /* 2^7 - 2^2 */ fsquare(t1,t0);
1107 - /* 2^8 - 2^3 */ fsquare(t0,t1);
1108 - /* 2^9 - 2^4 */ fsquare(t1,t0);
1109 - /* 2^10 - 2^5 */ fsquare(t0,t1);
1110 - /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
1112 - /* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
1113 - /* 2^12 - 2^2 */ fsquare(t1,t0);
1114 - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
1115 - /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
1117 - /* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
1118 - /* 2^22 - 2^2 */ fsquare(t1,t0);
1119 - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
1120 - /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
1122 - /* 2^41 - 2^1 */ fsquare(t1,t0);
1123 - /* 2^42 - 2^2 */ fsquare(t0,t1);
1124 - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
1125 - /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
1127 - /* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
1128 - /* 2^52 - 2^2 */ fsquare(t1,t0);
1129 - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
1130 - /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
1132 - /* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
1133 - /* 2^102 - 2^2 */ fsquare(t0,t1);
1134 - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
1135 - /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
1137 - /* 2^201 - 2^1 */ fsquare(t0,t1);
1138 - /* 2^202 - 2^2 */ fsquare(t1,t0);
1139 - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
1140 - /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
1142 - /* 2^251 - 2^1 */ fsquare(t1,t0);
1143 - /* 2^252 - 2^2 */ fsquare(t0,t1);
1144 - /* 2^253 - 2^3 */ fsquare(t1,t0);
1145 - /* 2^254 - 2^4 */ fsquare(t0,t1);
1146 - /* 2^255 - 2^5 */ fsquare(t1,t0);
1147 - /* 2^255 - 21 */ fmul(out,t1,z11);
1151 -curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
1152 - limb bp[10], x[10], z[11], zmone[10];
1156 - for (i = 0; i < 32; ++i) e[i] = secret[i];
1161 - fexpand(bp, basepoint);
1162 - cmult(x, z, e, bp);
1164 - fmul(z, x, zmone);
1165 - fcontract(mypublic, z);
1168 diff --git a/curve25519.c b/curve25519.c
1169 new file mode 100644
1170 index 0000000..4b83776
1175 + * Dropbear - a SSH2 server
1177 + * Copyright (c) 2002,2003 Matt Johnston
1178 + * All rights reserved.
1180 + * Permission is hereby granted, free of charge, to any person obtaining a copy
1181 + * of this software and associated documentation files (the "Software"), to deal
1182 + * in the Software without restriction, including without limitation the rights
1183 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1184 + * copies of the Software, and to permit persons to whom the Software is
1185 + * furnished to do so, subject to the following conditions:
1187 + * The above copyright notice and this permission notice shall be included in
1188 + * all copies or substantial portions of the Software.
1190 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1191 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1192 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1193 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1194 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1195 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1198 +#include "includes.h"
1199 +#include "dbrandom.h"
1200 +#include "curve25519.h"
1202 +#if DROPBEAR_CURVE25519 || DROPBEAR_ED25519
1204 +/* Modified TweetNaCl version 20140427, a self-contained public-domain C library.
1205 + * https://tweetnacl.cr.yp.to/ */
1207 +#define FOR(i,n) for (i = 0;i < n;++i)
1208 +#define sv static void
1210 +typedef unsigned char u8;
1211 +typedef unsigned long u32;
1212 +typedef unsigned long long u64;
1213 +typedef long long i64;
1214 +typedef i64 gf[16];
1216 +#if DROPBEAR_CURVE25519
1218 + _121665 = {0xDB41,1};
1219 +#endif /* DROPBEAR_CURVE25519 */
1220 +#if DROPBEAR_ED25519
1224 + D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
1225 + X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
1226 + Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666};
1227 +#if DROPBEAR_SIGNKEY_VERIFY
1229 + D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
1230 + I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
1231 +#endif /* DROPBEAR_SIGNKEY_VERIFY */
1232 +#endif /* DROPBEAR_ED25519 */
1234 +#if DROPBEAR_ED25519
1235 +#if DROPBEAR_SIGNKEY_VERIFY
1236 +static int vn(const u8 *x,const u8 *y,u32 n)
1239 + FOR(i,n) d |= x[i]^y[i];
1240 + return (1 & ((d - 1) >> 8)) - 1;
1243 +static int crypto_verify_32(const u8 *x,const u8 *y)
1245 + return vn(x,y,32);
1247 +#endif /* DROPBEAR_SIGNKEY_VERIFY */
1249 +sv set25519(gf r, const gf a)
1252 + FOR(i,16) r[i]=a[i];
1254 +#endif /* DROPBEAR_ED25519 */
1263 + o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15);
1268 +sv sel25519(gf p,gf q,int b)
1278 +sv pack25519(u8 *o,const gf n)
1282 + FOR(i,16) t[i]=n[i];
1288 + for(i=1;i<15;i++) {
1289 + m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
1292 + m[15]=t[15]-0x7fff-((m[14]>>16)&1);
1295 + sel25519(t,m,1-b);
1303 +#if DROPBEAR_ED25519
1304 +#if DROPBEAR_SIGNKEY_VERIFY
1305 +static int neq25519(const gf a, const gf b)
1310 + return crypto_verify_32(c,d);
1312 +#endif /* DROPBEAR_SIGNKEY_VERIFY */
1314 +static u8 par25519(const gf a)
1320 +#endif /* DROPBEAR_ED25519 */
1322 +sv unpack25519(gf o, const u8 *n)
1325 + FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8);
1329 +sv A(gf o,const gf a,const gf b)
1332 + FOR(i,16) o[i]=a[i]+b[i];
1335 +sv Z(gf o,const gf a,const gf b)
1338 + FOR(i,16) o[i]=a[i]-b[i];
1341 +sv M(gf o,const gf a,const gf b)
1345 + FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j];
1346 + FOR(i,15) t[i]+=38*t[i+16];
1347 + FOR(i,16) o[i]=t[i];
1352 +sv S(gf o,const gf a)
1357 +sv inv25519(gf o,const gf i)
1361 + FOR(a,16) c[a]=i[a];
1362 + for(a=253;a>=0;a--) {
1364 + if(a!=2&&a!=4) M(c,c,i);
1366 + FOR(a,16) o[a]=c[a];
1369 +#if DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY
1370 +sv pow2523(gf o,const gf i)
1374 + FOR(a,16) c[a]=i[a];
1375 + for(a=250;a>=0;a--) {
1377 + if(a!=1) M(c,c,i);
1379 + FOR(a,16) o[a]=c[a];
1381 +#endif /* DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY */
1383 +#if DROPBEAR_CURVE25519
1384 +int dropbear_curve25519_scalarmult(u8 *q,const u8 *n,const u8 *p)
1389 + FOR(i,31) z[i]=n[i];
1390 + z[31]=(n[31]&127)|64;
1398 + for(i=254;i>=0;--i) {
1399 + r=(z[i>>3]>>(i&7))&1;
1429 + inv25519(x+32,x+32);
1430 + M(x+16,x+16,x+32);
1431 + pack25519(q,x+16);
1434 +#endif /* DROPBEAR_CURVE25519 */
1436 +#if DROPBEAR_ED25519
1437 +static int crypto_hash(u8 *out,const u8 *m,u64 n)
1442 + sha512_process(&hs, m, n);
1443 + return sha512_done(&hs, out);
1446 +sv add(gf p[4],gf q[4])
1448 + gf a,b,c,d,t,e,f,g,h;
1471 +sv cswap(gf p[4],gf q[4],u8 b)
1475 + sel25519(p[i],q[i],b);
1478 +sv pack(u8 *r,gf p[4])
1481 + inv25519(zi, p[2]);
1485 + r[31] ^= par25519(tx) << 7;
1488 +sv scalarmult(gf p[4],gf q[4],const u8 *s)
1491 + set25519(p[0],gf0);
1492 + set25519(p[1],gf1);
1493 + set25519(p[2],gf1);
1494 + set25519(p[3],gf0);
1495 + for (i = 255;i >= 0;--i) {
1496 + u8 b = (s[i/8]>>(i&7))&1;
1504 +sv scalarbase(gf p[4],const u8 *s)
1509 + set25519(q[2],gf1);
1511 + scalarmult(p,q,s);
1514 +int dropbear_ed25519_make_key(u8 *pk,u8 *sk)
1519 + genrandom(sk, 32);
1521 + crypto_hash(d, sk, 32);
1532 +static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10};
1534 +sv modL(u8 *r,i64 x[64])
1537 + for (i = 63;i >= 32;--i) {
1539 + for (j = i - 32;j < i - 12;++j) {
1540 + x[j] += carry - 16 * x[i] * L[j - (i - 32)];
1541 + carry = (x[j] + 128) >> 8;
1542 + x[j] -= carry << 8;
1549 + x[j] += carry - (x[31] >> 4) * L[j];
1550 + carry = x[j] >> 8;
1553 + FOR(j,32) x[j] -= carry * L[j];
1555 + x[i+1] += x[i] >> 8;
1556 + r[i] = x[i] & 255;
1563 + FOR(i,64) x[i] = (u64) r[i];
1564 + FOR(i,64) r[i] = 0;
1568 +int dropbear_ed25519_sign(const u8 *m,u32 mlen,u8 *s,u32 *slen,const u8 *sk, const u8 *pk)
1571 + u8 d[64],h[64],r[64];
1576 + crypto_hash(d, sk, 32);
1584 + sha512_process(&hs,d + 32,32);
1585 + sha512_process(&hs,m,mlen);
1586 + sha512_done(&hs,r);
1592 + sha512_process(&hs,s,32);
1593 + sha512_process(&hs,pk,32);
1594 + sha512_process(&hs,m,mlen);
1595 + sha512_done(&hs,h);
1598 + FOR(i,64) x[i] = 0;
1599 + FOR(i,32) x[i] = (u64) r[i];
1600 + FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j];
1606 +#if DROPBEAR_SIGNKEY_VERIFY
1607 +static int unpackneg(gf r[4],const u8 p[32])
1609 + gf t, chk, num, den, den2, den4, den6;
1610 + set25519(r[2],gf1);
1611 + unpack25519(r[1],p);
1619 + M(den6,den4,den2);
1631 + if (neq25519(chk, num)) M(r[0],r[0],I);
1635 + if (neq25519(chk, num)) return -1;
1637 + if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]);
1639 + M(r[3],r[0],r[1]);
1643 +int dropbear_ed25519_verify(const u8 *m,u32 mlen,const u8 *s,u32 slen,const u8 *pk)
1649 + if (slen < 64) return -1;
1651 + if (unpackneg(q,pk)) return -1;
1654 + sha512_process(&hs,s,32);
1655 + sha512_process(&hs,pk,32);
1656 + sha512_process(&hs,m,mlen);
1657 + sha512_done(&hs,h);
1660 + scalarmult(p,q,h);
1662 + scalarbase(q,s + 32);
1666 + if (crypto_verify_32(s, t))
1671 +#endif /* DROPBEAR_SIGNKEY_VERIFY */
1673 +#endif /* DROPBEAR_ED25519 */
1675 +#endif /* DROPBEAR_CURVE25519 || DROPBEAR_ED25519 */
1676 diff --git a/curve25519.h b/curve25519.h
1677 new file mode 100644
1678 index 0000000..7f75aed
1683 + * Dropbear - a SSH2 server
1685 + * Copyright (c) 2002,2003 Matt Johnston
1686 + * All rights reserved.
1688 + * Permission is hereby granted, free of charge, to any person obtaining a copy
1689 + * of this software and associated documentation files (the "Software"), to deal
1690 + * in the Software without restriction, including without limitation the rights
1691 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1692 + * copies of the Software, and to permit persons to whom the Software is
1693 + * furnished to do so, subject to the following conditions:
1695 + * The above copyright notice and this permission notice shall be included in
1696 + * all copies or substantial portions of the Software.
1698 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1699 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1700 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1701 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1702 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1703 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1706 +#ifndef DROPBEAR_CURVE25519_H
1707 +#define DROPBEAR_CURVE25519_H
1709 +int dropbear_curve25519_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
1710 +int dropbear_ed25519_make_key(unsigned char *pk, unsigned char *sk);
1711 +int dropbear_ed25519_sign(const unsigned char *m, unsigned long mlen,
1712 + unsigned char *s, unsigned long *slen,
1713 + const unsigned char *sk, const unsigned char *pk);
1714 +int dropbear_ed25519_verify(const unsigned char *m, unsigned long mlen,
1715 + const unsigned char *s, unsigned long slen,
1716 + const unsigned char *pk);
1718 +#endif /* DROPBEAR_CURVE25519_H */
1719 diff --git a/default_options.h b/default_options.h
1720 index 9000fcc..5b232dd 100644
1721 --- a/default_options.h
1722 +++ b/default_options.h
1723 @@ -22,6 +22,7 @@ IMPORTANT: Some options will require "make clean" after changes */
1724 #define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
1725 #define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
1726 #define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
1727 +#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_host_key"
1729 /* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
1730 * on chosen ports and keeps accepting connections. This is the default.
1731 @@ -116,11 +117,15 @@ IMPORTANT: Some options will require "make clean" after changes */
1732 * code (either ECDSA or ECDH) increases binary size - around 30kB
1734 #define DROPBEAR_ECDSA 1
1735 +/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
1736 + binary size - around 7,5kB on x86-64 */
1737 +#define DROPBEAR_ED25519 1
1739 /* RSA must be >=1024 */
1740 #define DROPBEAR_DEFAULT_RSA_SIZE 2048
1741 /* DSS is always 1024 */
1742 /* ECDSA defaults to largest size configured, usually 521 */
1743 +/* Ed25519 is always 256 */
1745 /* Add runtime flag "-R" to generate hostkeys as-needed when the first
1746 connection using that key type occurs.
1747 @@ -143,7 +148,7 @@ IMPORTANT: Some options will require "make clean" after changes */
1748 * group14 is supported by most implementations.
1749 * group16 provides a greater strength level but is slower and increases binary size
1750 * curve25519 and ecdh algorithms are faster than non-elliptic curve methods
1751 - * curve25519 increases binary size by ~8kB on x86-64
1752 + * curve25519 increases binary size by ~2,5kB on x86-64
1753 * including either ECDH or ECDSA increases binary size by ~30kB on x86-64
1755 * Small systems should generally include either curve25519 or ecdh for performance.
1756 diff --git a/dropbear.8 b/dropbear.8
1757 index 71c955a..345954f 100644
1760 @@ -107,7 +107,7 @@ Print the version
1763 ~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
1765 +ECDSA, Ed25519 or DSS
1766 key. Each line is of the form
1768 [restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
1769 @@ -146,8 +146,8 @@ key authentication.
1772 Host key files are read at startup from a standard location, by default
1773 -/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
1774 -/etc/dropbear/dropbear_ecdsa_host_key
1775 +/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key,
1776 +/etc/dropbear/dropbear_ecdsa_host_key and /etc/dropbear/dropbear_ed25519_host_key
1778 If the -r command line option is specified the default files are not loaded.
1779 Host key files are of the form generated by dropbearkey.
1780 diff --git a/dropbearkey.c b/dropbearkey.c
1781 index dd0e697..f881855 100644
1789 + * string "ssh-ed25519"
1790 + * string k (32 bytes) + A (32 bytes)
1793 #include "includes.h"
1794 #include "signkey.h"
1799 +#include "gened25519.h"
1801 #include "crypto_desc.h"
1802 #include "dbrandom.h"
1803 @@ -75,6 +80,9 @@ static void printhelp(char * progname) {
1808 +#if DROPBEAR_ED25519
1811 "-f filename Use filename for the secret key.\n"
1812 " ~/.ssh/id_dropbear is recommended for client keys.\n"
1813 @@ -94,6 +102,9 @@ static void printhelp(char * progname) {
1818 +#if DROPBEAR_ED25519
1819 + " Ed25519 has a fixed size of 256 bits\n"
1821 "-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
1823 @@ -106,6 +117,14 @@ static void printhelp(char * progname) {
1824 static void check_signkey_bits(enum signkey_type type, int bits)
1827 +#if DROPBEAR_ED25519
1828 + case DROPBEAR_SIGNKEY_ED25519:
1829 + if (bits != 256) {
1830 + dropbear_exit("Ed25519 keys have a fixed size of 256 bits\n");
1831 + exit(EXIT_FAILURE);
1836 case DROPBEAR_SIGNKEY_RSA:
1837 if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
1838 @@ -224,6 +243,12 @@ int main(int argc, char ** argv) {
1839 keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
1842 +#if DROPBEAR_ED25519
1843 + if (strcmp(typetext, "ed25519") == 0)
1845 + keytype = DROPBEAR_SIGNKEY_ED25519;
1849 if (keytype == DROPBEAR_SIGNKEY_NONE) {
1850 fprintf(stderr, "Unknown key type '%s'\n", typetext);
1851 diff --git a/ed25519.c b/ed25519.c
1852 new file mode 100644
1853 index 0000000..3fb544c
1858 + * Dropbear - a SSH2 server
1860 + * Copyright (c) 2002,2003 Matt Johnston
1861 + * All rights reserved.
1863 + * Permission is hereby granted, free of charge, to any person obtaining a copy
1864 + * of this software and associated documentation files (the "Software"), to deal
1865 + * in the Software without restriction, including without limitation the rights
1866 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1867 + * copies of the Software, and to permit persons to whom the Software is
1868 + * furnished to do so, subject to the following conditions:
1870 + * The above copyright notice and this permission notice shall be included in
1871 + * all copies or substantial portions of the Software.
1873 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1874 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1875 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1876 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1877 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1878 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1881 +/* Perform Ed25519 operations on data, including reading keys, signing and
1882 + * verification. */
1884 +#include "includes.h"
1885 +#include "dbutil.h"
1886 +#include "buffer.h"
1888 +#include "curve25519.h"
1889 +#include "ed25519.h"
1891 +#if DROPBEAR_ED25519
1893 +/* Load a public ed25519 key from a buffer, initialising the values.
1894 + * The key will have the same format as buf_put_ed25519_key.
1895 + * These should be freed with ed25519_key_free.
1896 + * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
1897 +int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key) {
1901 + TRACE(("enter buf_get_ed25519_pub_key"))
1902 + dropbear_assert(key != NULL);
1904 + buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
1906 + len = buf_getint(buf);
1907 + if (len != CURVE25519_LEN || buf->len - buf->pos < len) {
1908 + TRACE(("leave buf_get_ed25519_pub_key: failure"))
1909 + return DROPBEAR_FAILURE;
1912 + m_burn(key->priv, CURVE25519_LEN);
1913 + memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
1914 + buf_incrpos(buf, CURVE25519_LEN);
1916 + TRACE(("leave buf_get_ed25519_pub_key: success"))
1917 + return DROPBEAR_SUCCESS;
1920 +/* Same as buf_get_ed25519_pub_key, but reads private key at the end.
1921 + * Loads a public and private ed25519 key from a buffer
1922 + * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
1923 +int buf_get_ed25519_priv_key(buffer *buf, dropbear_ed25519_key *key) {
1927 + TRACE(("enter buf_get_ed25519_priv_key"))
1928 + dropbear_assert(key != NULL);
1930 + buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
1932 + len = buf_getint(buf);
1933 + if (len != CURVE25519_LEN*2 || buf->len - buf->pos < len) {
1934 + TRACE(("leave buf_get_ed25519_priv_key: failure"))
1935 + return DROPBEAR_FAILURE;
1938 + memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
1939 + buf_incrpos(buf, CURVE25519_LEN);
1940 + memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
1941 + buf_incrpos(buf, CURVE25519_LEN);
1943 + TRACE(("leave buf_get_ed25519_pub_key: success"))
1944 + return DROPBEAR_SUCCESS;
1947 +/* Clear and free the memory used by a public or private key */
1948 +void ed25519_key_free(dropbear_ed25519_key *key) {
1950 + TRACE2(("enter ed25519_key_free"))
1952 + if (key == NULL) {
1953 + TRACE2(("leave ed25519_key_free: key == NULL"))
1956 + m_burn(key->priv, CURVE25519_LEN);
1959 + TRACE2(("leave rsa_key_free"))
1962 +/* Put the public ed25519 key into the buffer in the required format */
1963 +void buf_put_ed25519_pub_key(buffer *buf, const dropbear_ed25519_key *key) {
1965 + TRACE(("enter buf_put_ed25519_pub_key"))
1966 + dropbear_assert(key != NULL);
1968 + buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
1969 + buf_putstring(buf, key->pub, CURVE25519_LEN);
1971 + TRACE(("leave buf_put_ed25519_pub_key"))
1974 +/* Put the public and private ed25519 key into the buffer in the required format */
1975 +void buf_put_ed25519_priv_key(buffer *buf, const dropbear_ed25519_key *key) {
1977 + TRACE(("enter buf_put_ed25519_priv_key"))
1978 + dropbear_assert(key != NULL);
1980 + buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
1981 + buf_putint(buf, CURVE25519_LEN*2);
1982 + buf_putbytes(buf, key->priv, CURVE25519_LEN);
1983 + buf_putbytes(buf, key->pub, CURVE25519_LEN);
1985 + TRACE(("leave buf_put_ed25519_priv_key"))
1988 +/* Sign the data presented with key, writing the signature contents
1989 + * to the buffer */
1990 +void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
1992 + unsigned char s[64];
1993 + unsigned long slen = sizeof(s);
1995 + TRACE(("enter buf_put_ed25519_sign"))
1996 + dropbear_assert(key != NULL);
1998 + if (dropbear_ed25519_sign(data_buf->data, data_buf->len,
1999 + s, &slen, key->priv, key->pub) == 0) {
2000 + buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
2001 + buf_putstring(buf, s, slen);
2004 + TRACE(("leave buf_put_ed25519_sign"))
2007 +#if DROPBEAR_SIGNKEY_VERIFY
2008 +/* Verify a signature in buf, made on data by the key given.
2009 + * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
2010 +int buf_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
2012 + int ret = DROPBEAR_FAILURE;
2014 + unsigned long slen;
2016 + TRACE(("enter buf_ed25519_verify"))
2017 + dropbear_assert(key != NULL);
2019 + slen = buf_getint(buf);
2020 + if (slen != 64 || buf->len - buf->pos < slen) {
2021 + TRACE(("bad size"))
2024 + s = buf_getptr(buf, slen);
2026 + if (dropbear_ed25519_verify(data_buf->data, data_buf->len,
2027 + s, slen, key->pub) == 0) {
2028 + /* signature is valid */
2029 + TRACE(("success!"))
2030 + ret = DROPBEAR_SUCCESS;
2034 + TRACE(("leave buf_ed25519_verify: ret %d", ret))
2038 +#endif /* DROPBEAR_SIGNKEY_VERIFY */
2040 +#endif /* DROPBEAR_ED25519 */
2041 diff --git a/ed25519.h b/ed25519.h
2042 new file mode 100644
2043 index 0000000..16c0d7b
2048 + * Dropbear - a SSH2 server
2050 + * Copyright (c) 2002,2003 Matt Johnston
2051 + * All rights reserved.
2053 + * Permission is hereby granted, free of charge, to any person obtaining a copy
2054 + * of this software and associated documentation files (the "Software"), to deal
2055 + * in the Software without restriction, including without limitation the rights
2056 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2057 + * copies of the Software, and to permit persons to whom the Software is
2058 + * furnished to do so, subject to the following conditions:
2060 + * The above copyright notice and this permission notice shall be included in
2061 + * all copies or substantial portions of the Software.
2063 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2064 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2065 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2066 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2067 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2068 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2071 +#ifndef DROPBEAR_ED25519_H_
2072 +#define DROPBEAR_ED25519_H_
2074 +#include "includes.h"
2075 +#include "buffer.h"
2077 +#if DROPBEAR_ED25519
2079 +#define CURVE25519_LEN 32
2083 + unsigned char priv[CURVE25519_LEN];
2084 + unsigned char pub[CURVE25519_LEN];
2086 +} dropbear_ed25519_key;
2088 +void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf);
2089 +#if DROPBEAR_SIGNKEY_VERIFY
2090 +int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf);
2092 +int buf_get_ed25519_pub_key(buffer* buf, dropbear_ed25519_key *key);
2093 +int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key);
2094 +void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key);
2095 +void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key);
2096 +void ed25519_key_free(dropbear_ed25519_key *key);
2098 +#endif /* DROPBEAR_ED25519 */
2100 +#endif /* DROPBEAR_ED25519_H_ */
2101 diff --git a/filelist.txt b/filelist.txt
2102 index 8281c14..3b9bb67 100644
2105 @@ -99,6 +99,10 @@ rsa.c RSA asymmetric crypto routines
2107 dss.c DSS asymmetric crypto routines
2109 +ed25519.c Ed25519 asymmetric crypto routines
2111 +gened25519.c Ed25519 key generation
2113 gendss.c DSS key generation
2115 genrsa.c RSA key generation
2116 diff --git a/fuzz-common.c b/fuzz-common.c
2117 index 5c90c45..b1b00f6 100644
2120 @@ -112,6 +112,14 @@ static void load_fixed_hostkeys(void) {
2121 dropbear_exit("failed fixed ecdsa hostkey");
2125 + buf_putbytes(b, keyed25519, keyed25519_len);
2127 + type = DROPBEAR_SIGNKEY_ED25519;
2128 + if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
2129 + dropbear_exit("failed fixed ed25519 hostkey");
2135 diff --git a/fuzz-hostkeys.c b/fuzz-hostkeys.c
2136 index dc1615d..3fff5cb 100644
2137 --- a/fuzz-hostkeys.c
2138 +++ b/fuzz-hostkeys.c
2139 @@ -127,3 +127,13 @@ unsigned char keyd[] = {
2142 unsigned int keyd_len = 458;
2143 +unsigned char keyed25519[] = {
2144 + 0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
2145 + 0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
2146 + 0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
2147 + 0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2,
2148 + 0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19,
2149 + 0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69,
2150 + 0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9
2152 +unsigned int keyed25519_len = 83;
2153 diff --git a/fuzzer-kexcurve25519.c b/fuzzer-kexcurve25519.c
2154 new file mode 100644
2155 index 0000000..f2eab14
2157 +++ b/fuzzer-kexcurve25519.c
2160 +#include "session.h"
2161 +#include "fuzz-wrapfd.h"
2163 +#include "runopts.h"
2165 +#include "bignum.h"
2167 +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
2168 + static int once = 0;
2169 + static struct key_context* keep_newkeys = NULL;
2170 + /* number of generated parameters is limited by the timeout for the first run.
2171 + TODO move this to the libfuzzer initialiser function instead if the timeout
2172 + doesn't apply there */
2173 + #define NUM_PARAMS 20
2174 + static struct kex_curve25519_param *curve25519_params[NUM_PARAMS];
2177 + fuzz_common_setup();
2180 + keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
2181 + keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256");
2182 + keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
2183 + ses.newkeys = keep_newkeys;
2185 + /* Pre-generate parameters */
2187 + for (i = 0; i < NUM_PARAMS; i++) {
2188 + curve25519_params[i] = gen_kexcurve25519_param();
2194 + if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
2198 + m_malloc_set_epoch(1);
2200 + if (setjmp(fuzz.jmp) == 0) {
2201 + /* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
2202 + with DROPBEAR_KEX_CURVE25519 */
2203 + ses.newkeys = keep_newkeys;
2205 + /* Choose from the collection of curve25519 params */
2206 + unsigned int e = buf_getint(fuzz.input);
2207 + struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS];
2209 + buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
2211 + ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
2212 + kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey);
2214 + mp_clear(ses.dh_K);
2216 + buf_free(ecdh_qs);
2218 + buf_free(ses.hash);
2219 + buf_free(ses.session_id);
2220 + /* kexhashbuf is freed in kexdh_comb_key */
2222 + m_malloc_free_epoch(1, 0);
2224 + m_malloc_free_epoch(1, 1);
2225 + TRACE(("dropbear_exit longjmped"))
2226 + /* dropbear_exit jumped here */
2231 diff --git a/gened25519.c b/gened25519.c
2232 new file mode 100644
2233 index 0000000..a027914
2238 + * Dropbear - a SSH2 server
2240 + * Copyright (c) 2002,2003 Matt Johnston
2241 + * All rights reserved.
2243 + * Permission is hereby granted, free of charge, to any person obtaining a copy
2244 + * of this software and associated documentation files (the "Software"), to deal
2245 + * in the Software without restriction, including without limitation the rights
2246 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2247 + * copies of the Software, and to permit persons to whom the Software is
2248 + * furnished to do so, subject to the following conditions:
2250 + * The above copyright notice and this permission notice shall be included in
2251 + * all copies or substantial portions of the Software.
2253 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2254 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2255 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2256 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2257 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2258 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2261 +#include "includes.h"
2262 +#include "dbutil.h"
2263 +#include "dbrandom.h"
2264 +#include "curve25519.h"
2265 +#include "gened25519.h"
2267 +#if DROPBEAR_ED25519
2269 +dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size) {
2271 + dropbear_ed25519_key *key;
2273 + if (size != 256) {
2274 + dropbear_exit("Ed25519 keys have a fixed size of 256 bits");
2277 + key = m_malloc(sizeof(*key));
2278 + dropbear_ed25519_make_key(key->pub, key->priv);
2283 +#endif /* DROPBEAR_ED25519 */
2284 diff --git a/gened25519.h b/gened25519.h
2285 new file mode 100644
2286 index 0000000..8058310
2291 + * Dropbear - a SSH2 server
2293 + * Copyright (c) 2002,2003 Matt Johnston
2294 + * All rights reserved.
2296 + * Permission is hereby granted, free of charge, to any person obtaining a copy
2297 + * of this software and associated documentation files (the "Software"), to deal
2298 + * in the Software without restriction, including without limitation the rights
2299 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2300 + * copies of the Software, and to permit persons to whom the Software is
2301 + * furnished to do so, subject to the following conditions:
2303 + * The above copyright notice and this permission notice shall be included in
2304 + * all copies or substantial portions of the Software.
2306 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2307 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2308 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2309 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2310 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2311 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2314 +#ifndef DROPBEAR_GENED25519_H_
2315 +#define DROPBEAR_GENED25519_H_
2317 +#include "ed25519.h"
2319 +#if DROPBEAR_ED25519
2321 +dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size);
2323 +#endif /* DROPBEAR_ED25519 */
2325 +#endif /* DROPBEAR_GENED25519_H_ */
2326 diff --git a/gensignkey.c b/gensignkey.c
2327 index 34b6f5a..674d81f 100644
2334 +#include "gened25519.h"
2335 #include "signkey.h"
2336 #include "dbrandom.h"
2338 @@ -68,6 +69,10 @@ static int get_default_bits(enum signkey_type keytype)
2340 case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
2343 +#if DROPBEAR_ED25519
2344 + case DROPBEAR_SIGNKEY_ED25519:
2349 @@ -118,6 +123,11 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
2350 *signkey_key_ptr(key, keytype) = ecckey;
2354 +#if DROPBEAR_ED25519
2355 + case DROPBEAR_SIGNKEY_ED25519:
2356 + key->ed25519key = gen_ed25519_priv_key(bits);
2360 dropbear_exit("Internal error");
2361 diff --git a/keyimport.c b/keyimport.c
2362 index 7304e58..ad0c530 100644
2371 +static const unsigned char OSSH_PKEY_BLOB[] =
2372 + "openssh-key-v1\0" /* AUTH_MAGIC */
2373 + "\0\0\0\4none" /* cipher name*/
2374 + "\0\0\0\4none" /* kdf name */
2375 + "\0\0\0\0" /* kdf */
2376 + "\0\0\0\1"; /* key num */
2377 +#define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1)
2380 static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
2381 @@ -352,7 +361,7 @@ struct mpint_pos { void *start; int bytes; };
2382 * Code to read and write OpenSSH private keys.
2385 -enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
2386 +enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY };
2387 struct openssh_key {
2390 @@ -364,11 +373,12 @@ struct openssh_key {
2391 static struct openssh_key *load_openssh_key(const char *filename)
2393 struct openssh_key *ret;
2394 + buffer *buf = NULL;
2397 char *errmsg = NULL, *p = NULL;
2399 - unsigned long len, outlen;
2400 + unsigned long len;
2402 ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key));
2403 ret->keyblob = NULL;
2404 @@ -397,12 +407,15 @@ static struct openssh_key *load_openssh_key(const char *filename)
2405 ret->type = OSSH_DSA;
2406 else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n"))
2407 ret->type = OSSH_EC;
2408 + else if (!strcmp(buffer, "-----BEGIN OPENSSH PRIVATE KEY-----\n"))
2409 + ret->type = OSSH_PKEY;
2411 errmsg = "Unrecognised key type";
2418 if (!fgets(buffer, sizeof(buffer), fp)) {
2419 errmsg = "Unexpected end of file";
2420 @@ -448,20 +461,31 @@ static struct openssh_key *load_openssh_key(const char *filename)
2423 len = strlen(buffer);
2425 - if (ret->keyblob_len + outlen > ret->keyblob_size) {
2426 - ret->keyblob_size = ret->keyblob_len + outlen + 256;
2427 - ret->keyblob = (unsigned char*)m_realloc(ret->keyblob,
2428 - ret->keyblob_size);
2430 - outlen = ret->keyblob_size - ret->keyblob_len;
2431 - if (base64_decode((const unsigned char *)buffer, len,
2432 - ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
2433 - errmsg = "Error decoding base64";
2436 - ret->keyblob_len += outlen;
2437 + buf = buf_resize(buf, buf->size + len);
2438 + buf_putbytes(buf, buffer, len);
2442 + if (buf && buf->len) {
2443 + ret->keyblob_size = ret->keyblob_len + buf->len*4/3 + 256;
2444 + ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, ret->keyblob_size);
2445 + len = ret->keyblob_size;
2446 + if (base64_decode((const unsigned char *)buf->data, buf->len,
2447 + ret->keyblob, &len) != CRYPT_OK){
2448 + errmsg = "Error decoding base64";
2451 + ret->keyblob_len = len;
2454 + if (ret->type == OSSH_PKEY) {
2455 + if (ret->keyblob_len < OSSH_PKEY_BLOBLEN ||
2456 + memcmp(ret->keyblob, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN)) {
2457 + errmsg = "Error decoding OpenSSH key";
2460 + ret->keyblob_len -= OSSH_PKEY_BLOBLEN;
2461 + memmove(ret->keyblob, ret->keyblob + OSSH_PKEY_BLOBLEN, ret->keyblob_len);
2464 if (ret->keyblob_len == 0 || !ret->keyblob) {
2465 @@ -474,10 +498,18 @@ static struct openssh_key *load_openssh_key(const char *filename)
2473 m_burn(buffer, sizeof(buffer));
2481 m_burn(buffer, sizeof(buffer));
2484 @@ -569,6 +601,57 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
2489 + * Now we have a decrypted key blob, which contains OpenSSH
2490 + * encoded private key. We must now untangle the OpenSSH format.
2492 + if (key->type == OSSH_PKEY) {
2493 + blobbuf = buf_new(key->keyblob_len);
2494 + buf_putbytes(blobbuf, key->keyblob, key->keyblob_len);
2495 + buf_setpos(blobbuf, 0);
2497 + /* limit length of private key blob */
2498 + len = buf_getint(blobbuf);
2499 + buf_setlen(blobbuf, blobbuf->pos + len);
2501 + type = DROPBEAR_SIGNKEY_ANY;
2502 + if (buf_get_pub_key(blobbuf, retkey, &type)
2503 + != DROPBEAR_SUCCESS) {
2504 + errmsg = "Error parsing OpenSSH key";
2508 + /* restore full length */
2509 + buf_setlen(blobbuf, key->keyblob_len);
2511 + if (type != DROPBEAR_SIGNKEY_NONE) {
2512 + retkey->type = type;
2513 + /* limit length of private key blob */
2514 + len = buf_getint(blobbuf);
2515 + buf_setlen(blobbuf, blobbuf->pos + len);
2516 +#if DROPBEAR_ED25519
2517 + if (type == DROPBEAR_SIGNKEY_ED25519) {
2518 + buf_incrpos(blobbuf, 8);
2519 + buf_eatstring(blobbuf);
2520 + buf_eatstring(blobbuf);
2521 + buf_incrpos(blobbuf, -SSH_SIGNKEY_ED25519_LEN-4);
2522 + if (buf_get_ed25519_priv_key(blobbuf, retkey->ed25519key)
2523 + == DROPBEAR_SUCCESS) {
2532 + errmsg = "Unsupported OpenSSH key type";
2534 + sign_key_free(retkey);
2540 * Now we have a decrypted key blob, which contains an ASN.1
2541 * encoded private key. We must now untangle the ASN.1.
2542 @@ -1129,6 +1212,51 @@ static int openssh_write(const char *filename, sign_key *key,
2546 +#if DROPBEAR_ED25519
2547 + if (key->type == DROPBEAR_SIGNKEY_ED25519) {
2548 + buffer *buf = buf_new(300);
2549 + keyblob = buf_new(100);
2550 + extrablob = buf_new(200);
2552 + /* private key blob w/o header */
2553 + buf_put_priv_key(keyblob, key, key->type);
2554 + buf_setpos(keyblob, 0);
2555 + buf_incrpos(keyblob, buf_getint(keyblob));
2556 + len = buf_getint(keyblob);
2559 + buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);
2562 + buf_put_pub_key(buf, key, key->type);
2565 + buf_incrwritepos(extrablob, 4);
2566 + buf_put_pub_key(extrablob, key, key->type);
2567 + buf_putstring(extrablob, buf_getptr(keyblob, len), len);
2569 + buf_putstring(extrablob, "", 0);
2570 + /* padding to cipher block length */
2571 + len = (extrablob->len+8) & ~7;
2572 + for (i = 1; len - extrablob->len > 0; i++)
2573 + buf_putbyte(extrablob, i);
2574 + buf_setpos(extrablob, 0);
2575 + buf_putbytes(extrablob, "\0\0\0\0\0\0\0\0", 8);
2576 + buf_putbufstring(buf, extrablob);
2578 + outlen = len = pos = buf->len;
2579 + outblob = (unsigned char*)m_malloc(outlen);
2580 + memcpy(outblob, buf->data, buf->len);
2586 + header = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
2587 + footer = "-----END OPENSSH PRIVATE KEY-----\n";
2592 * Padding on OpenSSH keys is deterministic. The number of
2593 * padding bytes is always more than zero, and always at most
2594 diff --git a/signkey.c b/signkey.c
2595 index 88f06c7..a0af44a 100644
2598 @@ -39,8 +39,11 @@ static const char * const signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
2600 "ecdsa-sha2-nistp256",
2601 "ecdsa-sha2-nistp384",
2602 - "ecdsa-sha2-nistp521"
2603 + "ecdsa-sha2-nistp521",
2604 #endif /* DROPBEAR_ECDSA */
2605 +#if DROPBEAR_ED25519
2607 +#endif /* DROPBEAR_ED25519 */
2610 /* malloc a new sign_key and set the dss and rsa keys to NULL */
2611 @@ -107,6 +110,10 @@ Be sure to check both (ret != NULL) and (*ret != NULL) */
2613 signkey_key_ptr(sign_key *key, enum signkey_type type) {
2615 +#if DROPBEAR_ED25519
2616 + case DROPBEAR_SIGNKEY_ED25519:
2617 + return (void**)&key->ed25519key;
2620 #if DROPBEAR_ECC_256
2621 case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
2622 @@ -200,6 +207,17 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
2626 +#if DROPBEAR_ED25519
2627 + if (keytype == DROPBEAR_SIGNKEY_ED25519) {
2628 + ed25519_key_free(key->ed25519key);
2629 + key->ed25519key = m_malloc(sizeof(*key->ed25519key));
2630 + ret = buf_get_ed25519_pub_key(buf, key->ed25519key);
2631 + if (ret == DROPBEAR_FAILURE) {
2632 + m_free(key->ed25519key);
2633 + key->ed25519key = NULL;
2638 TRACE2(("leave buf_get_pub_key"))
2640 @@ -270,6 +288,17 @@ int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
2644 +#if DROPBEAR_ED25519
2645 + if (keytype == DROPBEAR_SIGNKEY_ED25519) {
2646 + ed25519_key_free(key->ed25519key);
2647 + key->ed25519key = m_malloc(sizeof(*key->ed25519key));
2648 + ret = buf_get_ed25519_priv_key(buf, key->ed25519key);
2649 + if (ret == DROPBEAR_FAILURE) {
2650 + m_free(key->ed25519key);
2651 + key->ed25519key = NULL;
2656 TRACE2(("leave buf_get_priv_key"))
2658 @@ -302,6 +331,11 @@ void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
2659 buf_put_ecdsa_pub_key(pubkeys, *eck);
2663 +#if DROPBEAR_ED25519
2664 + if (type == DROPBEAR_SIGNKEY_ED25519) {
2665 + buf_put_ed25519_pub_key(pubkeys, key->ed25519key);
2668 if (pubkeys->len == 0) {
2669 dropbear_exit("Bad key types in buf_put_pub_key");
2670 @@ -341,6 +375,13 @@ void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) {
2675 +#if DROPBEAR_ED25519
2676 + if (type == DROPBEAR_SIGNKEY_ED25519) {
2677 + buf_put_ed25519_priv_key(buf, key->ed25519key);
2678 + TRACE(("leave buf_put_priv_key: ed25519 done"))
2682 dropbear_exit("Bad key types in put pub key");
2684 @@ -379,6 +420,10 @@ void sign_key_free(sign_key *key) {
2685 key->ecckey521 = NULL;
2689 +#if DROPBEAR_ED25519
2690 + ed25519_key_free(key->ed25519key);
2691 + key->ed25519key = NULL;
2694 m_free(key->filename);
2695 @@ -503,6 +548,11 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
2696 buf_put_ecdsa_sign(sigblob, *eck, data_buf);
2700 +#if DROPBEAR_ED25519
2701 + if (type == DROPBEAR_SIGNKEY_ED25519) {
2702 + buf_put_ed25519_sign(sigblob, key->ed25519key, data_buf);
2705 if (sigblob->len == 0) {
2706 dropbear_exit("Non-matching signing type");
2707 @@ -555,6 +605,14 @@ int buf_verify(buffer * buf, sign_key *key, const buffer *data_buf) {
2711 +#if DROPBEAR_ED25519
2712 + if (type == DROPBEAR_SIGNKEY_ED25519) {
2713 + if (key->ed25519key == NULL) {
2714 + dropbear_exit("No Ed25519 key to verify signature");
2716 + return buf_ed25519_verify(buf, key->ed25519key, data_buf);
2720 dropbear_exit("Non-matching signing type");
2721 return DROPBEAR_FAILURE;
2722 diff --git a/signkey.h b/signkey.h
2723 index 59df3ee..fa39a02 100644
2730 +#include "ed25519.h"
2734 @@ -41,6 +42,9 @@ enum signkey_type {
2735 DROPBEAR_SIGNKEY_ECDSA_NISTP384,
2736 DROPBEAR_SIGNKEY_ECDSA_NISTP521,
2737 #endif /* DROPBEAR_ECDSA */
2738 +#if DROPBEAR_ED25519
2739 + DROPBEAR_SIGNKEY_ED25519,
2741 DROPBEAR_SIGNKEY_NUM_NAMED,
2742 DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */
2743 DROPBEAR_SIGNKEY_ANY = 80,
2744 @@ -78,6 +82,9 @@ struct SIGN_key {
2745 ecc_key * ecckey521;
2748 +#if DROPBEAR_ED25519
2749 + dropbear_ed25519_key * ed25519key;
2753 typedef struct SIGN_key sign_key;
2754 diff --git a/ssh.h b/ssh.h
2755 index f40b65a..db723b8 100644
2759 #define SSH_SIGNKEY_DSS_LEN 7
2760 #define SSH_SIGNKEY_RSA "ssh-rsa"
2761 #define SSH_SIGNKEY_RSA_LEN 7
2762 +#define SSH_SIGNKEY_ED25519 "ssh-ed25519"
2763 +#define SSH_SIGNKEY_ED25519_LEN 11
2765 /* Agent commands. These aren't part of the spec, and are defined
2766 * only on the openssh implementation. */
2767 diff --git a/svr-kex.c b/svr-kex.c
2768 index 406ad97..af16d2f 100644
2771 @@ -122,6 +122,11 @@ static void svr_ensure_hostkey() {
2772 case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
2773 fn = ECDSA_PRIV_FILENAME;
2776 +#if DROPBEAR_ED25519
2777 + case DROPBEAR_SIGNKEY_ED25519:
2778 + fn = ED25519_PRIV_FILENAME;
2783 @@ -219,7 +224,8 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
2785 struct kex_curve25519_param *param = gen_kexcurve25519_param();
2786 kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey);
2787 - buf_putstring(ses.writepayload, (const char*)param->pub, CURVE25519_LEN);
2789 + buf_putstring(ses.writepayload, param->pub, CURVE25519_LEN);
2790 free_kexcurve25519_param(param);
2793 diff --git a/svr-runopts.c b/svr-runopts.c
2794 index d7a0d5a..d430825 100644
2797 @@ -57,6 +57,9 @@ static void printhelp(const char * progname) {
2801 +#if DROPBEAR_ED25519
2804 #if DROPBEAR_DELAY_HOSTKEY
2805 "-R Create hostkeys as required\n"
2807 @@ -116,6 +119,9 @@ static void printhelp(const char * progname) {
2810 ECDSA_PRIV_FILENAME,
2812 +#if DROPBEAR_ED25519
2813 + ED25519_PRIV_FILENAME,
2816 DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
2817 @@ -538,6 +544,13 @@ static void loadhostkey(const char *keyfile, int fatal_duplicate) {
2820 #endif /* DROPBEAR_ECDSA */
2822 +#if DROPBEAR_ED25519
2823 + if (type == DROPBEAR_SIGNKEY_ED25519) {
2824 + loadhostkey_helper("ed25519", (void**)&read_key->ed25519key, (void**)&svr_opts.hostkey->ed25519key, fatal_duplicate);
2828 sign_key_free(read_key);
2829 TRACE(("leave loadhostkey"))
2831 @@ -578,6 +591,9 @@ void load_all_hostkeys() {
2834 loadhostkey(ECDSA_PRIV_FILENAME, 0);
2836 +#if DROPBEAR_ED25519
2837 + loadhostkey(ED25519_PRIV_FILENAME, 0);
2841 @@ -642,6 +658,14 @@ void load_all_hostkeys() {
2843 #endif /* DROPBEAR_ECDSA */
2845 +#if DROPBEAR_ED25519
2846 + if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
2847 + disablekey(DROPBEAR_SIGNKEY_ED25519);
2854 dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
2856 diff --git a/sysoptions.h b/sysoptions.h
2857 index cfd5469..2c27caf 100644
2860 @@ -145,7 +145,8 @@ If you test it please contact the Dropbear author */
2861 #define DROPBEAR_SHA384 (DROPBEAR_ECC_384)
2862 /* LTC SHA384 depends on SHA512 */
2863 #define DROPBEAR_SHA512 ((DROPBEAR_SHA2_512_HMAC) || (DROPBEAR_ECC_521) \
2864 - || (DROPBEAR_SHA384) || (DROPBEAR_DH_GROUP16))
2865 + || (DROPBEAR_SHA384) || (DROPBEAR_DH_GROUP16) \
2866 + || (DROPBEAR_ED25519))
2867 #define DROPBEAR_MD5 (DROPBEAR_MD5_HMAC)
2869 #define DROPBEAR_DH_GROUP14 ((DROPBEAR_DH_GROUP14_SHA256) || (DROPBEAR_DH_GROUP14_SHA1))
2870 @@ -186,7 +187,7 @@ If you test it please contact the Dropbear author */
2871 /* For a 4096 bit DSS key, empirically determined */
2872 #define MAX_PRIVKEY_SIZE 1700
2874 -#define MAX_HOSTKEYS 3
2875 +#define MAX_HOSTKEYS 4
2877 /* The maximum size of the bignum portion of the kexhash buffer */
2878 /* Sect. 8 of the transport rfc 4253, K_S + e + f + K */
2879 @@ -252,7 +253,7 @@ If you test it please contact the Dropbear author */
2880 #error "At least one encryption algorithm must be enabled. AES128 is recommended."
2883 -#if !(DROPBEAR_RSA || DROPBEAR_DSS || DROPBEAR_ECDSA)
2884 +#if !(DROPBEAR_RSA || DROPBEAR_DSS || DROPBEAR_ECDSA || DROPBEAR_ED25519)
2885 #error "At least one hostkey or public-key algorithm must be enabled; RSA is recommended."