mirror of
https://github.com/clearml/dropbear
synced 2025-03-03 10:41:39 +00:00
merge ecc again
This commit is contained in:
commit
8c8ecec3e9
@ -27,7 +27,8 @@ COMMONOBJS=dbutil.o buffer.o \
|
||||
signkey.o rsa.o random.o \
|
||||
queue.o \
|
||||
atomicio.o compat.o fake-rfc2553.o \
|
||||
ltc_prng.o ecc.o ecdsa.o crypto_desc.o
|
||||
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
|
||||
gensignkey.o gendss.o genrsa.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
@ -42,9 +43,9 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
tcp-accept.o listener.o process-packet.o \
|
||||
common-runopts.o circbuffer.o
|
||||
common-runopts.o circbuffer.o curve25519-donna.o
|
||||
|
||||
KEYOBJS=dropbearkey.o gendss.o genrsa.o
|
||||
KEYOBJS=dropbearkey.o
|
||||
|
||||
CONVERTOBJS=dropbearconvert.o keyimport.o
|
||||
|
||||
|
22
algo.h
22
algo.h
@ -81,17 +81,27 @@ struct dropbear_hash {
|
||||
const unsigned char hashsize;
|
||||
};
|
||||
|
||||
enum dropbear_kex_mode {
|
||||
DROPBEAR_KEX_NORMAL_DH,
|
||||
DROPBEAR_KEX_ECDH,
|
||||
DROPBEAR_KEX_CURVE25519,
|
||||
};
|
||||
|
||||
struct dropbear_kex {
|
||||
// "normal" DH KEX
|
||||
enum dropbear_kex_mode mode;
|
||||
|
||||
/* "normal" DH KEX */
|
||||
const unsigned char *dh_p_bytes;
|
||||
const int dh_p_len;
|
||||
|
||||
// elliptic curve DH KEX
|
||||
/* elliptic curve DH KEX */
|
||||
#ifdef DROPBEAR_ECDH
|
||||
const struct dropbear_ecc_curve *ecc_curve;
|
||||
#else
|
||||
const void* dummy;
|
||||
#endif
|
||||
|
||||
// both
|
||||
/* both */
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
};
|
||||
|
||||
@ -117,12 +127,6 @@ int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
char * algolist_string(algo_type algos[]);
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#define IS_NORMAL_DH(algo) ((algo)->dh_p_bytes != NULL)
|
||||
#else
|
||||
#define IS_NORMAL_DH(algo) 1
|
||||
#endif
|
||||
|
||||
enum {
|
||||
DROPBEAR_COMP_NONE,
|
||||
DROPBEAR_COMP_ZLIB,
|
||||
|
2
bignum.c
2
bignum.c
@ -78,8 +78,6 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
|
||||
/* hash the ssh representation of the mp_int mp */
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp) {
|
||||
|
||||
int i;
|
||||
buffer * buf;
|
||||
|
||||
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
|
||||
|
116
cli-kex.c
116
cli-kex.c
@ -47,27 +47,43 @@ void send_msg_kexdh_init() {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
|
||||
if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.dh_param) {
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.dh_param) {
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
}
|
||||
cli_ses.dh_param = gen_kexdh_param();
|
||||
}
|
||||
cli_ses.dh_param = gen_kexdh_param();
|
||||
}
|
||||
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
|
||||
} else {
|
||||
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
|
||||
break;
|
||||
case DROPBEAR_KEX_ECDH:
|
||||
#ifdef DROPBEAR_ECDH
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.ecdh_param) {
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.ecdh_param) {
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
}
|
||||
cli_ses.ecdh_param = gen_kexecdh_param();
|
||||
}
|
||||
cli_ses.ecdh_param = gen_kexecdh_param();
|
||||
}
|
||||
buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
|
||||
buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
|
||||
#endif
|
||||
break;
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.curve25519_param) {
|
||||
if (cli_ses.curve25519_param) {
|
||||
free_kexcurve25519_param(cli_ses.curve25519_param);
|
||||
}
|
||||
cli_ses.curve25519_param = gen_kexcurve25519_param();
|
||||
}
|
||||
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
cli_ses.param_kex_algo = ses.newkeys->algo_kex;
|
||||
encrypt_packet();
|
||||
ses.requirenext[0] = SSH_MSG_KEXDH_REPLY;
|
||||
@ -103,23 +119,38 @@ void recv_msg_kexdh_reply() {
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
|
||||
// Normal diffie-hellman
|
||||
DEF_MP_INT(dh_f);
|
||||
m_mp_init(&dh_f);
|
||||
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting mpint"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
{
|
||||
DEF_MP_INT(dh_f);
|
||||
m_mp_init(&dh_f);
|
||||
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting mpint"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
|
||||
mp_clear(&dh_f);
|
||||
} else {
|
||||
kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
|
||||
mp_clear(&dh_f);
|
||||
}
|
||||
break;
|
||||
case DROPBEAR_KEX_ECDH:
|
||||
#ifdef DROPBEAR_ECDH
|
||||
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
|
||||
buf_free(ecdh_qs);
|
||||
{
|
||||
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
|
||||
buf_free(ecdh_qs);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
{
|
||||
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey);
|
||||
buf_free(ecdh_qs);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (cli_ses.dh_param) {
|
||||
@ -132,6 +163,12 @@ void recv_msg_kexdh_reply() {
|
||||
cli_ses.ecdh_param = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
if (cli_ses.curve25519_param) {
|
||||
free_kexcurve25519_param(cli_ses.curve25519_param);
|
||||
cli_ses.curve25519_param = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
cli_ses.param_kex_algo = NULL;
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
|
||||
@ -147,7 +184,8 @@ void recv_msg_kexdh_reply() {
|
||||
TRACE(("leave recv_msg_kexdh_init"))
|
||||
}
|
||||
|
||||
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen,
|
||||
const char* algoname) {
|
||||
|
||||
char* fp = NULL;
|
||||
FILE *tty = NULL;
|
||||
@ -155,14 +193,16 @@ static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
fp = sign_key_fingerprint(keyblob, keybloblen);
|
||||
if (cli_opts.always_accept_key) {
|
||||
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(fingerprint %s)\n",
|
||||
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
|
||||
cli_opts.remotehost,
|
||||
algoname,
|
||||
fp);
|
||||
m_free(fp);
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n) ",
|
||||
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\nDo you want to continue connecting? (y/n) ",
|
||||
cli_opts.remotehost,
|
||||
algoname,
|
||||
fp);
|
||||
m_free(fp);
|
||||
|
||||
@ -257,16 +297,17 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
return;
|
||||
}
|
||||
|
||||
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
|
||||
|
||||
hostsfile = open_known_hosts_file(&readonly);
|
||||
if (!hostsfile) {
|
||||
ask_to_confirm(keyblob, keybloblen);
|
||||
ask_to_confirm(keyblob, keybloblen, algoname);
|
||||
/* ask_to_confirm will exit upon failure */
|
||||
return;
|
||||
}
|
||||
|
||||
line = buf_new(MAX_KNOWNHOSTS_LINE);
|
||||
hostlen = strlen(cli_opts.remotehost);
|
||||
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
|
||||
|
||||
do {
|
||||
if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
|
||||
@ -319,17 +360,18 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
/* The keys didn't match. eep. Note that we're "leaking"
|
||||
the fingerprint strings here, but we're exiting anyway */
|
||||
dropbear_exit("\n\nHost key mismatch for %s !\n"
|
||||
dropbear_exit("\n\n%s host key mismatch for %s !\n"
|
||||
"Fingerprint is %s\n"
|
||||
"Expected %s\n"
|
||||
"If you know that the host key is correct you can\nremove the bad entry from ~/.ssh/known_hosts",
|
||||
algoname,
|
||||
cli_opts.remotehost,
|
||||
sign_key_fingerprint(keyblob, keybloblen),
|
||||
fingerprint ? fingerprint : "UNKNOWN");
|
||||
} while (1); /* keep going 'til something happens */
|
||||
|
||||
/* Key doesn't exist yet */
|
||||
ask_to_confirm(keyblob, keybloblen);
|
||||
ask_to_confirm(keyblob, keybloblen, algoname);
|
||||
|
||||
/* If we get here, they said yes */
|
||||
|
||||
|
@ -450,7 +450,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
static void loadidentityfile(const char* filename) {
|
||||
sign_key *key;
|
||||
int keytype;
|
||||
enum signkey_type keytype;
|
||||
|
||||
key = new_sign_key();
|
||||
keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
|
@ -228,23 +228,32 @@ algo_type sshhostkey[] = {
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static struct dropbear_kex kex_dh_group1 = {dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
|
||||
static struct dropbear_kex kex_dh_group14 = {dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
|
||||
static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
|
||||
static const struct dropbear_kex kex_dh_group14 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
|
||||
|
||||
/* These can't be const since dropbear_ecc_fill_dp() fills out
|
||||
ecc_curve at runtime */
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
static struct dropbear_kex kex_ecdh_nistp256 = {NULL, 0, &ecc_curve_nistp256, &sha256_desc };
|
||||
static struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
static struct dropbear_kex kex_ecdh_nistp384 = {NULL, 0, &ecc_curve_nistp384, &sha384_desc };
|
||||
static struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
static struct dropbear_kex kex_ecdh_nistp521 = {NULL, 0, &ecc_curve_nistp521, &sha512_desc };
|
||||
static struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
|
||||
#endif
|
||||
#endif // DROPBEAR_ECDH
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
/* Referred to directly */
|
||||
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
|
||||
#endif
|
||||
|
||||
algo_type sshkex[] = {
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
{"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
|
||||
@ -289,7 +298,7 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
unsigned int donefirst = 0;
|
||||
buffer *algolist = NULL;
|
||||
|
||||
algolist = buf_new(160);
|
||||
algolist = buf_new(200);
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
if (donefirst)
|
||||
|
73
common-kex.c
73
common-kex.c
@ -577,7 +577,7 @@ struct kex_dh_param *gen_kexdh_param() {
|
||||
TRACE(("enter gen_kexdh_vals"))
|
||||
|
||||
struct kex_dh_param *param = m_malloc(sizeof(*param));
|
||||
m_mp_init_multi(¶m->pub, ¶m->priv, NULL);
|
||||
m_mp_init_multi(¶m->pub, ¶m->priv, &dh_g, &dh_p, &dh_q, NULL);
|
||||
|
||||
/* read the prime and generator*/
|
||||
load_dh_p(&dh_p);
|
||||
@ -690,8 +690,8 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
|
||||
ses.dh_K = dropbear_ecc_shared_secret(Q_them, ¶m->key);
|
||||
|
||||
/* From here on, the code needs to work with the _same_ vars on each side,
|
||||
* not vice-versaing for client/server */
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash
|
||||
See RFC5656 section 4 page 7 */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
Q_C = ¶m->key;
|
||||
Q_S = Q_them;
|
||||
@ -700,7 +700,6 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
Q_S = ¶m->key;
|
||||
}
|
||||
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash */
|
||||
/* K_S, the host key */
|
||||
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
|
||||
/* Q_C, client's ephemeral public key octet string */
|
||||
@ -713,7 +712,71 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param () {
|
||||
/* Per http://cr.yp.to/ecdh.html */
|
||||
struct kex_curve25519_param *param = m_malloc(sizeof(*param));
|
||||
const unsigned char basepoint[32] = {9};
|
||||
|
||||
genrandom(param->priv, CURVE25519_LEN);
|
||||
param->priv[0] &= 248;
|
||||
param->priv[31] &= 127;
|
||||
param->priv[31] |= 64;
|
||||
|
||||
curve25519_donna(param->pub, param->priv, basepoint);
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param)
|
||||
{
|
||||
m_burn(param->priv, CURVE25519_LEN);
|
||||
m_free(param);
|
||||
}
|
||||
|
||||
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_them,
|
||||
sign_key *hostkey) {
|
||||
unsigned char out[CURVE25519_LEN];
|
||||
const unsigned char* Q_C = NULL;
|
||||
const unsigned char* Q_S = NULL;
|
||||
|
||||
if (buf_pub_them->len != CURVE25519_LEN)
|
||||
{
|
||||
dropbear_exit("Bad curve25519");
|
||||
}
|
||||
|
||||
curve25519_donna(out, param->priv, buf_pub_them->data);
|
||||
m_mp_alloc_init_multi(&ses.dh_K, NULL);
|
||||
bytes_to_mp(ses.dh_K, out, CURVE25519_LEN);
|
||||
m_burn(out, sizeof(out));
|
||||
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash.
|
||||
See RFC5656 section 4 page 7 */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
Q_C = param->pub;
|
||||
Q_S = buf_pub_them->data;
|
||||
} else {
|
||||
Q_S = param->pub;
|
||||
Q_C = buf_pub_them->data;
|
||||
}
|
||||
|
||||
/* K_S, the host key */
|
||||
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
|
||||
/* Q_C, client's ephemeral public key octet string */
|
||||
buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
|
||||
/* Q_S, server's ephemeral public key octet string */
|
||||
buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
|
||||
|
||||
|
||||
static void finish_kexhashbuf(void) {
|
||||
hash_state hs;
|
||||
|
734
curve25519-donna.c
Normal file
734
curve25519-donna.c
Normal file
@ -0,0 +1,734 @@
|
||||
/* Copyright 2008, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* curve25519-donna: Curve25519 elliptic curve, public key function
|
||||
*
|
||||
* http://code.google.com/p/curve25519-donna/
|
||||
*
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* More information about curve25519 can be found here
|
||||
* http://cr.yp.to/ecdh.html
|
||||
*
|
||||
* djb's sample implementation of curve25519 is written in a special assembly
|
||||
* language called qhasm and uses the floating point registers.
|
||||
*
|
||||
* This is, almost, a clean room reimplementation from the curve25519 paper. It
|
||||
* uses many of the tricks described therein. Only the crecip function is taken
|
||||
* from the sample implementation.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t limb;
|
||||
|
||||
/* Field element representation:
|
||||
*
|
||||
* Field elements are written as an array of signed, 64-bit limbs, least
|
||||
* significant first. The value of the field element is:
|
||||
* x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
|
||||
*
|
||||
* i.e. the limbs are 26, 25, 26, 25, ... bits wide.
|
||||
*/
|
||||
|
||||
/* Sum two numbers: output += in */
|
||||
static void fsum(limb *output, const limb *in) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; i += 2) {
|
||||
output[0+i] = (output[0+i] + in[0+i]);
|
||||
output[1+i] = (output[1+i] + in[1+i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the difference of two numbers: output = in - output
|
||||
* (note the order of the arguments!)
|
||||
*/
|
||||
static void fdifference(limb *output, const limb *in) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
output[i] = (in[i] - output[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply a number by a scalar: output = in * scalar */
|
||||
static void fscalar_product(limb *output, const limb *in, const limb scalar) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
output[i] = in[i] * scalar;
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply two numbers: output = in2 * in
|
||||
*
|
||||
* output must be distinct to both inputs. The inputs are reduced coefficient
|
||||
* form, the output is not.
|
||||
*/
|
||||
static void fproduct(limb *output, const limb *in2, const limb *in) {
|
||||
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
|
||||
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[0]);
|
||||
output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[0]);
|
||||
output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[0]);
|
||||
output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
|
||||
2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[0]);
|
||||
output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[0]);
|
||||
output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[0]);
|
||||
output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[0]);
|
||||
output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
|
||||
2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[0]);
|
||||
output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[0]);
|
||||
output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[2]);
|
||||
output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[2]);
|
||||
output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
|
||||
2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[3])) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[4]);
|
||||
output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[4]);
|
||||
output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[5])) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[6]);
|
||||
output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[6]);
|
||||
output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[7]));
|
||||
output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[8]);
|
||||
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
|
||||
}
|
||||
|
||||
/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */
|
||||
static void freduce_degree(limb *output) {
|
||||
/* Each of these shifts and adds ends up multiplying the value by 19. */
|
||||
output[8] += output[18] << 4;
|
||||
output[8] += output[18] << 1;
|
||||
output[8] += output[18];
|
||||
output[7] += output[17] << 4;
|
||||
output[7] += output[17] << 1;
|
||||
output[7] += output[17];
|
||||
output[6] += output[16] << 4;
|
||||
output[6] += output[16] << 1;
|
||||
output[6] += output[16];
|
||||
output[5] += output[15] << 4;
|
||||
output[5] += output[15] << 1;
|
||||
output[5] += output[15];
|
||||
output[4] += output[14] << 4;
|
||||
output[4] += output[14] << 1;
|
||||
output[4] += output[14];
|
||||
output[3] += output[13] << 4;
|
||||
output[3] += output[13] << 1;
|
||||
output[3] += output[13];
|
||||
output[2] += output[12] << 4;
|
||||
output[2] += output[12] << 1;
|
||||
output[2] += output[12];
|
||||
output[1] += output[11] << 4;
|
||||
output[1] += output[11] << 1;
|
||||
output[1] += output[11];
|
||||
output[0] += output[10] << 4;
|
||||
output[0] += output[10] << 1;
|
||||
output[0] += output[10];
|
||||
}
|
||||
|
||||
#if (-1 & 3) != 3
|
||||
#error "This code only works on a two's complement system"
|
||||
#endif
|
||||
|
||||
/* return v / 2^26, using only shifts and adds. */
|
||||
static inline limb
|
||||
div_by_2_26(const limb v)
|
||||
{
|
||||
/* High word of v; no shift needed*/
|
||||
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
|
||||
/* Set to all 1s if v was negative; else set to 0s. */
|
||||
const int32_t sign = ((int32_t) highword) >> 31;
|
||||
/* Set to 0x3ffffff if v was negative; else set to 0. */
|
||||
const int32_t roundoff = ((uint32_t) sign) >> 6;
|
||||
/* Should return v / (1<<26) */
|
||||
return (v + roundoff) >> 26;
|
||||
}
|
||||
|
||||
/* return v / (2^25), using only shifts and adds. */
|
||||
static inline limb
|
||||
div_by_2_25(const limb v)
|
||||
{
|
||||
/* High word of v; no shift needed*/
|
||||
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
|
||||
/* Set to all 1s if v was negative; else set to 0s. */
|
||||
const int32_t sign = ((int32_t) highword) >> 31;
|
||||
/* Set to 0x1ffffff if v was negative; else set to 0. */
|
||||
const int32_t roundoff = ((uint32_t) sign) >> 7;
|
||||
/* Should return v / (1<<25) */
|
||||
return (v + roundoff) >> 25;
|
||||
}
|
||||
|
||||
static inline s32
|
||||
div_s32_by_2_25(const s32 v)
|
||||
{
|
||||
const s32 roundoff = ((uint32_t)(v >> 31)) >> 7;
|
||||
return (v + roundoff) >> 25;
|
||||
}
|
||||
|
||||
/* Reduce all coefficients of the short form input so that |x| < 2^26.
|
||||
*
|
||||
* On entry: |output[i]| < 2^62
|
||||
*/
|
||||
static void freduce_coefficients(limb *output) {
|
||||
unsigned i;
|
||||
|
||||
output[10] = 0;
|
||||
|
||||
for (i = 0; i < 10; i += 2) {
|
||||
limb over = div_by_2_26(output[i]);
|
||||
output[i] -= over << 26;
|
||||
output[i+1] += over;
|
||||
|
||||
over = div_by_2_25(output[i+1]);
|
||||
output[i+1] -= over << 25;
|
||||
output[i+2] += over;
|
||||
}
|
||||
/* Now |output[10]| < 2 ^ 38 and all other coefficients are reduced. */
|
||||
output[0] += output[10] << 4;
|
||||
output[0] += output[10] << 1;
|
||||
output[0] += output[10];
|
||||
|
||||
output[10] = 0;
|
||||
|
||||
/* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19 * 2^38
|
||||
* So |over| will be no more than 77825 */
|
||||
{
|
||||
limb over = div_by_2_26(output[0]);
|
||||
output[0] -= over << 26;
|
||||
output[1] += over;
|
||||
}
|
||||
|
||||
/* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 77825
|
||||
* So |over| will be no more than 1. */
|
||||
{
|
||||
/* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */
|
||||
s32 over32 = div_s32_by_2_25((s32) output[1]);
|
||||
output[1] -= over32 << 25;
|
||||
output[2] += over32;
|
||||
}
|
||||
|
||||
/* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced":
|
||||
* we have |output[2]| <= 2^26. This is good enough for all of our math,
|
||||
* but it will require an extra freduce_coefficients before fcontract. */
|
||||
}
|
||||
|
||||
/* A helpful wrapper around fproduct: output = in * in2.
|
||||
*
|
||||
* output must be distinct to both inputs. The output is reduced degree and
|
||||
* reduced coefficient.
|
||||
*/
|
||||
static void
|
||||
fmul(limb *output, const limb *in, const limb *in2) {
|
||||
limb t[19];
|
||||
fproduct(t, in, in2);
|
||||
freduce_degree(t);
|
||||
freduce_coefficients(t);
|
||||
memcpy(output, t, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
static void fsquare_inner(limb *output, const limb *in) {
|
||||
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
|
||||
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
|
||||
output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[2]));
|
||||
output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[3]));
|
||||
output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
|
||||
4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
|
||||
2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
|
||||
output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[5]));
|
||||
output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[6]) +
|
||||
2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
|
||||
output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[7]));
|
||||
output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
|
||||
2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[5])));
|
||||
output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[9]));
|
||||
output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[9])));
|
||||
output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[9]));
|
||||
output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
|
||||
2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[9])));
|
||||
output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[5])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[9]));
|
||||
output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[6])) * ((s32) in[8]) +
|
||||
2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
|
||||
output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[6])) * ((s32) in[9]));
|
||||
output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
|
||||
4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
|
||||
output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
|
||||
output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
|
||||
}
|
||||
|
||||
static void
|
||||
fsquare(limb *output, const limb *in) {
|
||||
limb t[19];
|
||||
fsquare_inner(t, in);
|
||||
freduce_degree(t);
|
||||
freduce_coefficients(t);
|
||||
memcpy(output, t, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* Take a little-endian, 32-byte number and expand it into polynomial form */
|
||||
static void
|
||||
fexpand(limb *output, const u8 *input) {
|
||||
#define F(n,start,shift,mask) \
|
||||
output[n] = ((((limb) input[start + 0]) | \
|
||||
((limb) input[start + 1]) << 8 | \
|
||||
((limb) input[start + 2]) << 16 | \
|
||||
((limb) input[start + 3]) << 24) >> shift) & mask;
|
||||
F(0, 0, 0, 0x3ffffff);
|
||||
F(1, 3, 2, 0x1ffffff);
|
||||
F(2, 6, 3, 0x3ffffff);
|
||||
F(3, 9, 5, 0x1ffffff);
|
||||
F(4, 12, 6, 0x3ffffff);
|
||||
F(5, 16, 0, 0x1ffffff);
|
||||
F(6, 19, 1, 0x3ffffff);
|
||||
F(7, 22, 3, 0x1ffffff);
|
||||
F(8, 25, 4, 0x3ffffff);
|
||||
F(9, 28, 6, 0x3ffffff);
|
||||
#undef F
|
||||
}
|
||||
|
||||
#if (-32 >> 1) != -16
|
||||
#error "This code only works when >> does sign-extension on negative numbers"
|
||||
#endif
|
||||
|
||||
/* Take a fully reduced polynomial form number and contract it into a
|
||||
* little-endian, 32-byte array
|
||||
*/
|
||||
static void
|
||||
fcontract(u8 *output, limb *input) {
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 2; ++j) {
|
||||
for (i = 0; i < 9; ++i) {
|
||||
if ((i & 1) == 1) {
|
||||
/* This calculation is a time-invariant way to make input[i] positive
|
||||
by borrowing from the next-larger limb.
|
||||
*/
|
||||
const s32 mask = (s32)(input[i]) >> 31;
|
||||
const s32 carry = -(((s32)(input[i]) & mask) >> 25);
|
||||
input[i] = (s32)(input[i]) + (carry << 25);
|
||||
input[i+1] = (s32)(input[i+1]) - carry;
|
||||
} else {
|
||||
const s32 mask = (s32)(input[i]) >> 31;
|
||||
const s32 carry = -(((s32)(input[i]) & mask) >> 26);
|
||||
input[i] = (s32)(input[i]) + (carry << 26);
|
||||
input[i+1] = (s32)(input[i+1]) - carry;
|
||||
}
|
||||
}
|
||||
{
|
||||
const s32 mask = (s32)(input[9]) >> 31;
|
||||
const s32 carry = -(((s32)(input[9]) & mask) >> 25);
|
||||
input[9] = (s32)(input[9]) + (carry << 25);
|
||||
input[0] = (s32)(input[0]) - (carry * 19);
|
||||
}
|
||||
}
|
||||
|
||||
/* The first borrow-propagation pass above ended with every limb
|
||||
except (possibly) input[0] non-negative.
|
||||
|
||||
Since each input limb except input[0] is decreased by at most 1
|
||||
by a borrow-propagation pass, the second borrow-propagation pass
|
||||
could only have wrapped around to decrease input[0] again if the
|
||||
first pass left input[0] negative *and* input[1] through input[9]
|
||||
were all zero. In that case, input[1] is now 2^25 - 1, and this
|
||||
last borrow-propagation step will leave input[1] non-negative.
|
||||
*/
|
||||
{
|
||||
const s32 mask = (s32)(input[0]) >> 31;
|
||||
const s32 carry = -(((s32)(input[0]) & mask) >> 26);
|
||||
input[0] = (s32)(input[0]) + (carry << 26);
|
||||
input[1] = (s32)(input[1]) - carry;
|
||||
}
|
||||
|
||||
/* Both passes through the above loop, plus the last 0-to-1 step, are
|
||||
necessary: if input[9] is -1 and input[0] through input[8] are 0,
|
||||
negative values will remain in the array until the end.
|
||||
*/
|
||||
|
||||
input[1] <<= 2;
|
||||
input[2] <<= 3;
|
||||
input[3] <<= 5;
|
||||
input[4] <<= 6;
|
||||
input[6] <<= 1;
|
||||
input[7] <<= 3;
|
||||
input[8] <<= 4;
|
||||
input[9] <<= 6;
|
||||
#define F(i, s) \
|
||||
output[s+0] |= input[i] & 0xff; \
|
||||
output[s+1] = (input[i] >> 8) & 0xff; \
|
||||
output[s+2] = (input[i] >> 16) & 0xff; \
|
||||
output[s+3] = (input[i] >> 24) & 0xff;
|
||||
output[0] = 0;
|
||||
output[16] = 0;
|
||||
F(0,0);
|
||||
F(1,3);
|
||||
F(2,6);
|
||||
F(3,9);
|
||||
F(4,12);
|
||||
F(5,16);
|
||||
F(6,19);
|
||||
F(7,22);
|
||||
F(8,25);
|
||||
F(9,28);
|
||||
#undef F
|
||||
}
|
||||
|
||||
/* Input: Q, Q', Q-Q'
|
||||
* Output: 2Q, Q+Q'
|
||||
*
|
||||
* x2 z3: long form
|
||||
* x3 z3: long form
|
||||
* x z: short form, destroyed
|
||||
* xprime zprime: short form, destroyed
|
||||
* qmqp: short form, preserved
|
||||
*/
|
||||
static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
||||
limb *x3, limb *z3, /* output Q + Q' */
|
||||
limb *x, limb *z, /* input Q */
|
||||
limb *xprime, limb *zprime, /* input Q' */
|
||||
const limb *qmqp /* input Q - Q' */) {
|
||||
limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
|
||||
zzprime[19], zzzprime[19], xxxprime[19];
|
||||
|
||||
memcpy(origx, x, 10 * sizeof(limb));
|
||||
fsum(x, z);
|
||||
fdifference(z, origx); // does x - z
|
||||
|
||||
memcpy(origxprime, xprime, sizeof(limb) * 10);
|
||||
fsum(xprime, zprime);
|
||||
fdifference(zprime, origxprime);
|
||||
fproduct(xxprime, xprime, z);
|
||||
fproduct(zzprime, x, zprime);
|
||||
freduce_degree(xxprime);
|
||||
freduce_coefficients(xxprime);
|
||||
freduce_degree(zzprime);
|
||||
freduce_coefficients(zzprime);
|
||||
memcpy(origxprime, xxprime, sizeof(limb) * 10);
|
||||
fsum(xxprime, zzprime);
|
||||
fdifference(zzprime, origxprime);
|
||||
fsquare(xxxprime, xxprime);
|
||||
fsquare(zzzprime, zzprime);
|
||||
fproduct(zzprime, zzzprime, qmqp);
|
||||
freduce_degree(zzprime);
|
||||
freduce_coefficients(zzprime);
|
||||
memcpy(x3, xxxprime, sizeof(limb) * 10);
|
||||
memcpy(z3, zzprime, sizeof(limb) * 10);
|
||||
|
||||
fsquare(xx, x);
|
||||
fsquare(zz, z);
|
||||
fproduct(x2, xx, zz);
|
||||
freduce_degree(x2);
|
||||
freduce_coefficients(x2);
|
||||
fdifference(zz, xx); // does zz = xx - zz
|
||||
memset(zzz + 10, 0, sizeof(limb) * 9);
|
||||
fscalar_product(zzz, zz, 121665);
|
||||
/* No need to call freduce_degree here:
|
||||
fscalar_product doesn't increase the degree of its input. */
|
||||
freduce_coefficients(zzz);
|
||||
fsum(zzz, xx);
|
||||
fproduct(z2, zz, zzz);
|
||||
freduce_degree(z2);
|
||||
freduce_coefficients(z2);
|
||||
}
|
||||
|
||||
/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
|
||||
* them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
|
||||
* side-channel attacks.
|
||||
*
|
||||
* NOTE that this function requires that 'iswap' be 1 or 0; other values give
|
||||
* wrong results. Also, the two limb arrays must be in reduced-coefficient,
|
||||
* reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
|
||||
* and all all values in a[0..9],b[0..9] must have magnitude less than
|
||||
* INT32_MAX.
|
||||
*/
|
||||
static void
|
||||
swap_conditional(limb a[19], limb b[19], limb iswap) {
|
||||
unsigned i;
|
||||
const s32 swap = (s32) -iswap;
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
|
||||
a[i] = ((s32)a[i]) ^ x;
|
||||
b[i] = ((s32)b[i]) ^ x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates nQ where Q is the x-coordinate of a point on the curve
|
||||
*
|
||||
* resultx/resultz: the x coordinate of the resulting curve point (short form)
|
||||
* n: a little endian, 32-byte number
|
||||
* q: a point of the curve (short form)
|
||||
*/
|
||||
static void
|
||||
cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
|
||||
limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
|
||||
limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
|
||||
limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
|
||||
limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
|
||||
|
||||
unsigned i, j;
|
||||
|
||||
memcpy(nqpqx, q, sizeof(limb) * 10);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
u8 byte = n[31 - i];
|
||||
for (j = 0; j < 8; ++j) {
|
||||
const limb bit = byte >> 7;
|
||||
|
||||
swap_conditional(nqx, nqpqx, bit);
|
||||
swap_conditional(nqz, nqpqz, bit);
|
||||
fmonty(nqx2, nqz2,
|
||||
nqpqx2, nqpqz2,
|
||||
nqx, nqz,
|
||||
nqpqx, nqpqz,
|
||||
q);
|
||||
swap_conditional(nqx2, nqpqx2, bit);
|
||||
swap_conditional(nqz2, nqpqz2, bit);
|
||||
|
||||
t = nqx;
|
||||
nqx = nqx2;
|
||||
nqx2 = t;
|
||||
t = nqz;
|
||||
nqz = nqz2;
|
||||
nqz2 = t;
|
||||
t = nqpqx;
|
||||
nqpqx = nqpqx2;
|
||||
nqpqx2 = t;
|
||||
t = nqpqz;
|
||||
nqpqz = nqpqz2;
|
||||
nqpqz2 = t;
|
||||
|
||||
byte <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(resultx, nqx, sizeof(limb) * 10);
|
||||
memcpy(resultz, nqz, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Shamelessly copied from djb's code
|
||||
// -----------------------------------------------------------------------------
|
||||
static void
|
||||
crecip(limb *out, const limb *z) {
|
||||
limb z2[10];
|
||||
limb z9[10];
|
||||
limb z11[10];
|
||||
limb z2_5_0[10];
|
||||
limb z2_10_0[10];
|
||||
limb z2_20_0[10];
|
||||
limb z2_50_0[10];
|
||||
limb z2_100_0[10];
|
||||
limb t0[10];
|
||||
limb t1[10];
|
||||
int i;
|
||||
|
||||
/* 2 */ fsquare(z2,z);
|
||||
/* 4 */ fsquare(t1,z2);
|
||||
/* 8 */ fsquare(t0,t1);
|
||||
/* 9 */ fmul(z9,t0,z);
|
||||
/* 11 */ fmul(z11,z9,z2);
|
||||
/* 22 */ fsquare(t0,z11);
|
||||
/* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
|
||||
|
||||
/* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
|
||||
/* 2^7 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^8 - 2^3 */ fsquare(t0,t1);
|
||||
/* 2^9 - 2^4 */ fsquare(t1,t0);
|
||||
/* 2^10 - 2^5 */ fsquare(t0,t1);
|
||||
/* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
|
||||
|
||||
/* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
|
||||
/* 2^12 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
|
||||
|
||||
/* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
|
||||
/* 2^22 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
|
||||
|
||||
/* 2^41 - 2^1 */ fsquare(t1,t0);
|
||||
/* 2^42 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
||||
/* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
|
||||
|
||||
/* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
|
||||
/* 2^52 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
|
||||
|
||||
/* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
|
||||
/* 2^102 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
||||
/* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
|
||||
|
||||
/* 2^201 - 2^1 */ fsquare(t0,t1);
|
||||
/* 2^202 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
|
||||
|
||||
/* 2^251 - 2^1 */ fsquare(t1,t0);
|
||||
/* 2^252 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^253 - 2^3 */ fsquare(t1,t0);
|
||||
/* 2^254 - 2^4 */ fsquare(t0,t1);
|
||||
/* 2^255 - 2^5 */ fsquare(t1,t0);
|
||||
/* 2^255 - 21 */ fmul(out,t1,z11);
|
||||
}
|
||||
|
||||
int curve25519_donna(u8 *, const u8 *, const u8 *);
|
||||
|
||||
int
|
||||
curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
|
||||
limb bp[10], x[10], z[11], zmone[10];
|
||||
uint8_t e[32];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; ++i) e[i] = secret[i];
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
|
||||
fexpand(bp, basepoint);
|
||||
cmult(x, z, e, bp);
|
||||
crecip(zmone, z);
|
||||
fmul(z, x, zmone);
|
||||
freduce_coefficients(z);
|
||||
fcontract(mypublic, z);
|
||||
return 0;
|
||||
}
|
3
debug.h
3
debug.h
@ -40,7 +40,6 @@
|
||||
* since the printing may not sanitise strings etc. This will add a reasonable
|
||||
* amount to your executable size. */
|
||||
/* #define DEBUG_TRACE */
|
||||
#define DEBUG_TRACE
|
||||
|
||||
/* All functions writing to the cleartext payload buffer call
|
||||
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
|
||||
@ -72,7 +71,7 @@
|
||||
|
||||
/* To debug with GDB it is easier to run with no forking of child processes.
|
||||
You will need to pass "-F" as well. */
|
||||
#define DEBUG_NOFORK
|
||||
/* #define DEBUG_NOFORK */
|
||||
|
||||
|
||||
/* For testing as non-root on shadowed systems, include the crypt of a password
|
||||
|
172
dropbearkey.c
172
dropbearkey.c
@ -54,15 +54,13 @@
|
||||
#include "ecdsa.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "random.h"
|
||||
#include "gensignkey.h"
|
||||
|
||||
static void printhelp(char * progname);
|
||||
|
||||
#define RSA_DEFAULT_SIZE 2048
|
||||
#define DSS_DEFAULT_SIZE 1024
|
||||
|
||||
static void buf_writefile(buffer * buf, const char * filename);
|
||||
static void printpubkey(sign_key * key, int keytype);
|
||||
static void justprintpub(const char* filename);
|
||||
static int printpubfile(const char* filename);
|
||||
|
||||
/* Print a help message */
|
||||
static void printhelp(char * progname) {
|
||||
@ -103,6 +101,30 @@ static void printhelp(char * progname) {
|
||||
,progname);
|
||||
}
|
||||
|
||||
/* fails fatally */
|
||||
static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
{
|
||||
switch (type) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8\n");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
if (bits != 1024) {
|
||||
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
(void)0; /* quiet, compiler. ecdsa handles checks itself */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
|
||||
int dropbearkey_main(int argc, char ** argv) {
|
||||
@ -112,13 +134,11 @@ int main(int argc, char ** argv) {
|
||||
|
||||
int i;
|
||||
char ** next = 0;
|
||||
sign_key *key = NULL;
|
||||
buffer *buf = NULL;
|
||||
char * filename = NULL;
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
|
||||
char * typetext = NULL;
|
||||
char * sizetext = NULL;
|
||||
unsigned int bits;
|
||||
unsigned int bits = 0;
|
||||
int printpub = 0;
|
||||
|
||||
crypto_init();
|
||||
@ -174,8 +194,8 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
if (printpub) {
|
||||
justprintpub(filename);
|
||||
/* Not reached */
|
||||
int ret = printpubfile(filename);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
/* check/parse args */
|
||||
@ -216,106 +236,22 @@ int main(int argc, char ** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// TODO: put RSA and DSS size checks into genrsa.c etc
|
||||
switch (keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
if (bits != 1024) {
|
||||
fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
(void)0; /* quiet, compiler. ecdsa handles checks itself */
|
||||
}
|
||||
check_signkey_bits(keytype, bits);;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* default key size */
|
||||
|
||||
switch (keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
bits = RSA_DEFAULT_SIZE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
bits = DSS_DEFAULT_SIZE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
|
||||
bits = ECDSA_DEFAULT_SIZE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
exit(EXIT_FAILURE); /* not reached */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", bits,
|
||||
typetext, filename);
|
||||
|
||||
/* don't want the file readable by others */
|
||||
umask(077);
|
||||
|
||||
/* now we can generate the key */
|
||||
key = new_sign_key();
|
||||
|
||||
fprintf(stderr, "Generating key, this may take a while...\n");
|
||||
switch(keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
key->rsakey = gen_rsa_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
key->dsskey = gen_dss_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
|
||||
{
|
||||
ecc_key *ecckey = gen_ecdsa_priv_key(bits);
|
||||
keytype = ecdsa_signkey_type(ecckey);
|
||||
*signkey_key_ptr(key, keytype) = ecckey;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr, "Internal error, bad key type\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
|
||||
{
|
||||
dropbear_exit("Failed to generate key.\n");
|
||||
}
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
|
||||
buf_put_priv_key(buf, key, keytype);
|
||||
buf_setpos(buf, 0);
|
||||
buf_writefile(buf, filename);
|
||||
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
|
||||
printpubkey(key, keytype);
|
||||
|
||||
sign_key_free(key);
|
||||
printpubfile(filename);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void justprintpub(const char* filename) {
|
||||
static int printpubfile(const char* filename) {
|
||||
|
||||
buffer *buf = NULL;
|
||||
sign_key *key = NULL;
|
||||
@ -353,7 +289,7 @@ out:
|
||||
sign_key_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
exit(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void printpubkey(sign_key * key, int keytype) {
|
||||
@ -402,35 +338,3 @@ static void printpubkey(sign_key * key, int keytype) {
|
||||
m_free(fp);
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
/* Write a buffer to a file specified, failing if the file exists */
|
||||
static void buf_writefile(buffer * buf, const char * filename) {
|
||||
|
||||
int fd;
|
||||
int len;
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Couldn't create new file %s\n", filename);
|
||||
perror("Reason");
|
||||
buf_burn(buf);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* write the file now */
|
||||
while (buf->pos != buf->len) {
|
||||
len = write(fd, buf_getptr(buf, buf->len - buf->pos),
|
||||
buf->len - buf->pos);
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (len <= 0) {
|
||||
fprintf(stderr, "Failed writing file '%s'\n",filename);
|
||||
perror("Reason");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
buf_incrpos(buf, len);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
4
ecc.c
4
ecc.c
@ -6,7 +6,7 @@
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
|
||||
// .dp members are filled out by dropbear_ecc_fill_dp() at startup
|
||||
/* .dp members are filled out by dropbear_ecc_fill_dp() at startup */
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
struct dropbear_ecc_curve ecc_curve_nistp256 = {
|
||||
.ltc_size = 32,
|
||||
@ -44,7 +44,7 @@ struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
|
||||
|
||||
void dropbear_ecc_fill_dp() {
|
||||
struct dropbear_ecc_curve **curve;
|
||||
// libtomcrypt guarantees they're ordered by size
|
||||
/* libtomcrypt guarantees they're ordered by size */
|
||||
const ltc_ecc_set_type *dp = ltc_ecc_sets;
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
for (;dp->size > 0; dp++) {
|
||||
|
13
ecdsa.c
13
ecdsa.c
@ -8,6 +8,13 @@
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
|
||||
int signkey_is_ecdsa(enum signkey_type type)
|
||||
{
|
||||
return type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|
||||
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|
||||
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
}
|
||||
|
||||
enum signkey_type ecdsa_signkey_type(ecc_key * key) {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (key->dp == ecc_curve_nistp256.dp) {
|
||||
@ -239,8 +246,8 @@ out:
|
||||
|
||||
// returns values in s and r
|
||||
// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
|
||||
static int buf_get_ecdsa_verify_params(buffer *buf, struct dropbear_ecc_curve *curve,
|
||||
void *r, void* s) {
|
||||
static int buf_get_ecdsa_verify_params(buffer *buf,
|
||||
void *r, void* s) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned int sig_len;
|
||||
unsigned int sig_pos;
|
||||
@ -295,7 +302,7 @@ int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
|
||||
if (buf_get_ecdsa_verify_params(buf, curve, r, s) != DROPBEAR_SUCCESS) {
|
||||
if (buf_get_ecdsa_verify_params(buf, r, s) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
3
ecdsa.h
3
ecdsa.h
@ -7,6 +7,7 @@
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
|
||||
/* Prefer the larger size - it's fast anyway */
|
||||
#if defined(DROPBEAR_ECC_521)
|
||||
#define ECDSA_DEFAULT_SIZE 521
|
||||
#elif defined(DROPBEAR_ECC_384)
|
||||
@ -26,6 +27,8 @@ enum signkey_type ecdsa_signkey_type(ecc_key * key);
|
||||
|
||||
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf);
|
||||
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf);
|
||||
/* Returns 1 on success */
|
||||
int signkey_is_ecdsa(enum signkey_type type);
|
||||
|
||||
#endif
|
||||
|
||||
|
131
gensignkey.c
Normal file
131
gensignkey.c
Normal file
@ -0,0 +1,131 @@
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
#include "ecdsa.h"
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "signkey.h"
|
||||
|
||||
#define RSA_DEFAULT_SIZE 2048
|
||||
#define DSS_DEFAULT_SIZE 1024
|
||||
|
||||
// Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
|
||||
static int buf_writefile(buffer * buf, const char * filename) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
int fd = -1;
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
|
||||
filename, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* write the file now */
|
||||
while (buf->pos != buf->len) {
|
||||
int len = write(fd, buf_getptr(buf, buf->len - buf->pos),
|
||||
buf->len - buf->pos);
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (len <= 0) {
|
||||
dropbear_log(LOG_ERR, "Failed writing file %s: %s",
|
||||
filename, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, len);
|
||||
}
|
||||
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
if (fd >= 0) {
|
||||
m_close(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* returns 0 on failure */
|
||||
static int get_default_bits(enum signkey_type keytype)
|
||||
{
|
||||
switch (keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
return RSA_DEFAULT_SIZE;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
return DSS_DEFAULT_SIZE;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
|
||||
return ECDSA_DEFAULT_SIZE;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
return 521;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
return 384;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
return 256;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
|
||||
{
|
||||
sign_key * key = NULL;
|
||||
buffer *buf = NULL;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
if (bits == 0)
|
||||
{
|
||||
bits = get_default_bits(keytype);
|
||||
}
|
||||
|
||||
/* now we can generate the key */
|
||||
key = new_sign_key();
|
||||
|
||||
seedrandom();
|
||||
|
||||
switch(keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
key->rsakey = gen_rsa_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
key->dsskey = gen_dss_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
{
|
||||
ecc_key *ecckey = gen_ecdsa_priv_key(bits);
|
||||
keytype = ecdsa_signkey_type(ecckey);
|
||||
*signkey_key_ptr(key, keytype) = ecckey;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
dropbear_exit("Internal error");
|
||||
}
|
||||
|
||||
seedrandom();
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
|
||||
buf_put_priv_key(buf, key, keytype);
|
||||
sign_key_free(key);
|
||||
key = NULL;
|
||||
buf_setpos(buf, 0);
|
||||
ret = buf_writefile(buf, filename);
|
||||
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
buf = NULL;
|
||||
return ret;
|
||||
}
|
8
gensignkey.h
Normal file
8
gensignkey.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _GENSIGNKEY_H
|
||||
#define _GENSIGNKEY_H
|
||||
|
||||
#include "signkey.h"
|
||||
|
||||
int signkey_generate(enum signkey_type type, int bits, const char* filename);
|
||||
|
||||
#endif
|
19
kex.h
19
kex.h
@ -47,6 +47,13 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
sign_key *hostkey);
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param();
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param);
|
||||
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *pub_them,
|
||||
sign_key *hostkey);
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
int is_compress_trans();
|
||||
int is_compress_recv();
|
||||
@ -92,6 +99,18 @@ struct kex_ecdh_param {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
#define CURVE25519_LEN 32
|
||||
struct kex_curve25519_param {
|
||||
unsigned char priv[CURVE25519_LEN];
|
||||
unsigned char pub[CURVE25519_LEN];
|
||||
};
|
||||
|
||||
/* No header file for curve25519_donna */
|
||||
int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsigned char *other);
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_KEXHASHBUF 2000
|
||||
|
||||
#endif /* _KEX_H_ */
|
||||
|
28
keyimport.c
28
keyimport.c
@ -112,7 +112,7 @@ static sign_key *dropbear_read(const char* filename) {
|
||||
|
||||
buffer * buf = NULL;
|
||||
sign_key *ret = NULL;
|
||||
int type;
|
||||
enum signkey_type type;
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
|
||||
@ -501,7 +501,7 @@ static int openssh_encrypted(const char *filename)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
|
||||
{
|
||||
struct openssh_key *key;
|
||||
unsigned char *p;
|
||||
@ -511,7 +511,7 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
char *errmsg;
|
||||
char *modptr = NULL;
|
||||
int modlen = -9999;
|
||||
int type;
|
||||
enum signkey_type type;
|
||||
|
||||
sign_key *retkey;
|
||||
buffer * blobbuf = NULL;
|
||||
@ -709,19 +709,29 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (len == sizeof(OID_SEC256R1_BLOB)
|
||||
if (0) {}
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
else if (len == sizeof(OID_SEC256R1_BLOB)
|
||||
&& memcmp(p, OID_SEC256R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
curve = &ecc_curve_nistp256;
|
||||
} else if (len == sizeof(OID_SEC384R1_BLOB)
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
else if (len == sizeof(OID_SEC384R1_BLOB)
|
||||
&& memcmp(p, OID_SEC384R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP384;
|
||||
curve = &ecc_curve_nistp384;
|
||||
} else if (len == sizeof(OID_SEC521R1_BLOB)
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
else if (len == sizeof(OID_SEC521R1_BLOB)
|
||||
&& memcmp(p, OID_SEC521R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
curve = &ecc_curve_nistp521;
|
||||
} else {
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
errmsg = "Unknown ECC key type";
|
||||
goto error;
|
||||
}
|
||||
@ -1018,8 +1028,8 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
}
|
||||
*/
|
||||
buffer *seq_buf = buf_new(400);
|
||||
ecc_key **eck = signkey_ecc_key_ptr(key, key->type);
|
||||
const unsigned long curve_size = (*eck)->dp->size;
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
|
||||
const long curve_size = (*eck)->dp->size;
|
||||
int curve_oid_len = 0;
|
||||
const void* curve_oid = NULL;
|
||||
unsigned long pubkey_size = 2*curve_size+1;
|
||||
|
30
options.h
30
options.h
@ -8,7 +8,7 @@
|
||||
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
|
||||
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */
|
||||
|
||||
/* Important: Many options will require "make clean" after changes */
|
||||
/* IMPORTANT: Many options will require "make clean" after changes */
|
||||
|
||||
#ifndef DROPBEAR_DEFPORT
|
||||
#define DROPBEAR_DEFPORT "22"
|
||||
@ -129,7 +129,7 @@ much traffic. */
|
||||
|
||||
/* You can also disable integrity. Don't bother disabling this if you're
|
||||
* still using a cipher, it's relatively cheap. If you disable this it's dead
|
||||
* simple to run arbitrary commands on the remote host. Beware. */
|
||||
* simple for an attacker to run arbitrary commands on the remote host. Beware. */
|
||||
/* #define DROPBEAR_NONE_INTEGRITY */
|
||||
|
||||
/* Hostkey/public key algorithms - at least one required, these are used
|
||||
@ -138,14 +138,26 @@ much traffic. */
|
||||
* SSH2 RFC Draft requires dss, recommends rsa */
|
||||
#define DROPBEAR_RSA
|
||||
#define DROPBEAR_DSS
|
||||
|
||||
#define DROPBEAR_ECDH
|
||||
/* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
|
||||
* code (either ECDSA or ECDH) increases binary size - around 30kB
|
||||
* on x86-64 */
|
||||
#define DROPBEAR_ECDSA
|
||||
|
||||
/* RSA can be vulnerable to timing attacks which use the time required for
|
||||
* signing to guess the private key. Blinding avoids this attack, though makes
|
||||
* signing operations slightly slower. */
|
||||
#define RSA_BLINDING
|
||||
/* Generate hostkeys as-needed when the first connection using that key type occurs.
|
||||
This avoids the need to otherwise run "dropbearkey" and avoids some problems
|
||||
with badly seeded /dev/urandom when systems first boot.
|
||||
This also requires a runtime flag "-R". This adds ~4kB to binary size (or hardly
|
||||
anything if dropbearkey is linked in a "dropbearmulti" binary) */
|
||||
#define DROPBEAR_DELAY_HOSTKEY
|
||||
|
||||
/* Enable Curve25519 for key exchange. This is another elliptic
|
||||
* curve method with good security properties. Increases binary size
|
||||
* by ~8kB on x86-64 */
|
||||
#define DROPBEAR_CURVE25519
|
||||
|
||||
/* Enable elliptic curve Diffie Hellman key exchange, see note about
|
||||
* ECDSA above */
|
||||
#define DROPBEAR_ECDH
|
||||
|
||||
/* Control the memory/performance/compression tradeoff for zlib.
|
||||
* Set windowBits=8 for least memory usage, see your system's
|
||||
@ -182,7 +194,7 @@ much traffic. */
|
||||
|
||||
#define ENABLE_SVR_PASSWORD_AUTH
|
||||
/* PAM requires ./configure --enable-pam */
|
||||
//#define ENABLE_SVR_PAM_AUTH
|
||||
/*#define ENABLE_SVR_PAM_AUTH */
|
||||
#define ENABLE_SVR_PUBKEY_AUTH
|
||||
|
||||
/* Whether to take public key options in
|
||||
|
@ -100,6 +100,8 @@ typedef struct svr_runopts {
|
||||
|
||||
sign_key *hostkey;
|
||||
|
||||
int delay_hostkey;
|
||||
|
||||
char *hostkey_files[MAX_HOSTKEYS];
|
||||
int num_hostkey_files;
|
||||
|
||||
|
@ -244,6 +244,7 @@ struct clientsession {
|
||||
// XXX - move these to kexstate?
|
||||
struct kex_dh_param *dh_param;
|
||||
struct kex_ecdh_param *ecdh_param;
|
||||
struct kex_curve25519_param *curve25519_param;
|
||||
const struct dropbear_kex *param_kex_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
|
||||
|
||||
cli_kex_state kex_state; /* Used for progressing KEX */
|
||||
|
24
signkey.c
24
signkey.c
@ -39,8 +39,7 @@ static const char *signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
"ecdsa-sha2-nistp256",
|
||||
"ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp521",
|
||||
"ecdsa" // for keygen
|
||||
"ecdsa-sha2-nistp521"
|
||||
#endif // DROPBEAR_ECDSA
|
||||
};
|
||||
|
||||
@ -181,7 +180,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
if (signkey_is_ecdsa(keytype)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
@ -249,7 +248,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
if (signkey_is_ecdsa(keytype)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
@ -289,10 +288,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|
||||
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|
||||
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521)
|
||||
{
|
||||
if (signkey_is_ecdsa(type)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_pub_key(pubkeys, *eck);
|
||||
@ -329,7 +325,7 @@ void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) {
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
if (signkey_is_ecdsa(type)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_priv_key(buf, *eck);
|
||||
@ -354,18 +350,24 @@ void sign_key_free(sign_key *key) {
|
||||
key->rsakey = NULL;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (key->ecckey256) {
|
||||
ecc_free(key->ecckey256);
|
||||
key->ecckey256 = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (key->ecckey384) {
|
||||
ecc_free(key->ecckey384);
|
||||
key->ecckey384 = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (key->ecckey521) {
|
||||
ecc_free(key->ecckey521);
|
||||
key->ecckey521 = NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
m_free(key->filename);
|
||||
@ -484,7 +486,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
if (signkey_is_ecdsa(type)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_sign(sigblob, *eck, data_buf);
|
||||
@ -535,7 +537,7 @@ int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
if (signkey_is_ecdsa(type)) {
|
||||
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
|
||||
if (eck) {
|
||||
return buf_ecdsa_verify(buf, *eck, data_buf);
|
||||
|
@ -231,7 +231,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
|
||||
char* listshell = NULL;
|
||||
char* usershell = NULL;
|
||||
int uid;
|
||||
uid_t uid;
|
||||
TRACE(("enter checkusername"))
|
||||
if (userlen > MAX_USERNAME_LEN) {
|
||||
return DROPBEAR_FAILURE;
|
||||
|
@ -89,7 +89,7 @@ void svr_auth_pubkey() {
|
||||
buffer * signbuf = NULL;
|
||||
sign_key * key = NULL;
|
||||
char* fp = NULL;
|
||||
int type = -1;
|
||||
enum signkey_type type = -1;
|
||||
|
||||
TRACE(("enter pubkeyauth"))
|
||||
|
||||
@ -294,8 +294,8 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
options_buf = buf_new(options_len);
|
||||
buf_putbytes(options_buf, options_start, options_len);
|
||||
|
||||
/* compare the algorithm */
|
||||
if (line->pos + algolen > line->len) {
|
||||
/* compare the algorithm. +3 so we have enough bytes to read a space and some base64 characters too. */
|
||||
if (line->pos + algolen+3 > line->len) {
|
||||
continue;
|
||||
}
|
||||
if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) {
|
||||
|
146
svr-kex.c
146
svr-kex.c
@ -35,6 +35,7 @@
|
||||
#include "random.h"
|
||||
#include "runopts.h"
|
||||
#include "ecc.h"
|
||||
#include "gensignkey.h"
|
||||
|
||||
static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs);
|
||||
|
||||
@ -52,15 +53,22 @@ void recv_msg_kexdh_init() {
|
||||
dropbear_exit("Premature kexdh_init message received");
|
||||
}
|
||||
|
||||
if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
|
||||
m_mp_init(&dh_e);
|
||||
if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failed to get kex value");
|
||||
}
|
||||
} else {
|
||||
#ifdef DROPBEAR_ECDH
|
||||
ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
m_mp_init(&dh_e);
|
||||
if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad kex value");
|
||||
}
|
||||
break;
|
||||
case DROPBEAR_KEX_ECDH:
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
#if defined(DROPBEAR_ECDH) || defined(DROPBEAR_CURVE25519)
|
||||
ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (ses.payload->pos != ses.payload->len) {
|
||||
dropbear_exit("Bad kex value");
|
||||
}
|
||||
|
||||
send_msg_kexdh_reply(&dh_e, ecdh_qs);
|
||||
@ -68,6 +76,7 @@ void recv_msg_kexdh_init() {
|
||||
mp_clear(&dh_e);
|
||||
if (ecdh_qs) {
|
||||
buf_free(ecdh_qs);
|
||||
ecdh_qs = NULL;
|
||||
}
|
||||
|
||||
send_msg_newkeys();
|
||||
@ -75,6 +84,79 @@ void recv_msg_kexdh_init() {
|
||||
ses.requirenext[1] = 0;
|
||||
TRACE(("leave recv_msg_kexdh_init"))
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_DELAY_HOSTKEY
|
||||
static void svr_ensure_hostkey() {
|
||||
|
||||
const char* fn = NULL;
|
||||
char *fn_temp = NULL;
|
||||
enum signkey_type type = ses.newkeys->algo_hostkey;
|
||||
void **hostkey = signkey_key_ptr(svr_opts.hostkey, type);
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
if (hostkey && *hostkey) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
fn = RSA_PRIV_FILENAME;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
fn = DSS_PRIV_FILENAME;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
fn = ECDSA_PRIV_FILENAME;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
(void)0;
|
||||
}
|
||||
|
||||
if (readhostkey(fn, svr_opts.hostkey, &type) == DROPBEAR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
fn_temp = m_malloc(strlen(fn) + 20);
|
||||
snprintf(fn_temp, strlen(fn)+20, "%s.tmp%d", fn, getpid());
|
||||
|
||||
if (signkey_generate(type, 0, fn_temp) == DROPBEAR_FAILURE) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (link(fn_temp, fn) < 0) {
|
||||
/* It's OK to get EEXIST - we probably just lost a race
|
||||
with another connection to generate the key */
|
||||
if (errno != EEXIST) {
|
||||
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", fn,
|
||||
strerror(errno));
|
||||
/* XXX fallback to non-atomic copy for some filesystems? */
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = readhostkey(fn, svr_opts.hostkey, &type);
|
||||
|
||||
out:
|
||||
if (fn_temp) {
|
||||
unlink(fn_temp);
|
||||
m_free(fn_temp);
|
||||
}
|
||||
|
||||
if (ret == DROPBEAR_FAILURE)
|
||||
{
|
||||
dropbear_exit("Couldn't read or generate hostkey %s", fn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate our side of the diffie-hellman key exchange value (dh_f), and
|
||||
* calculate the session key using the diffie-hellman algorithm. Following
|
||||
@ -88,26 +170,50 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
|
||||
|
||||
/* we can start creating the kexdh_reply packet */
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
#ifdef DROPBEAR_DELAY_HOSTKEY
|
||||
if (svr_opts.delay_hostkey)
|
||||
{
|
||||
svr_ensure_hostkey();
|
||||
}
|
||||
#endif
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY);
|
||||
buf_put_pub_key(ses.writepayload, svr_opts.hostkey,
|
||||
ses.newkeys->algo_hostkey);
|
||||
|
||||
if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
|
||||
// Normal diffie-hellman
|
||||
struct kex_dh_param * dh_param = gen_kexdh_param();
|
||||
kexdh_comb_key(dh_param, dh_e, svr_opts.hostkey);
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
case DROPBEAR_KEX_NORMAL_DH:
|
||||
{
|
||||
struct kex_dh_param * dh_param = gen_kexdh_param();
|
||||
kexdh_comb_key(dh_param, dh_e, svr_opts.hostkey);
|
||||
|
||||
/* put f */
|
||||
buf_putmpint(ses.writepayload, &dh_param->pub);
|
||||
free_kexdh_param(dh_param);
|
||||
} else {
|
||||
/* put f */
|
||||
buf_putmpint(ses.writepayload, &dh_param->pub);
|
||||
free_kexdh_param(dh_param);
|
||||
}
|
||||
break;
|
||||
case DROPBEAR_KEX_ECDH:
|
||||
#ifdef DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *ecdh_param = gen_kexecdh_param();
|
||||
kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
|
||||
{
|
||||
struct kex_ecdh_param *ecdh_param = gen_kexecdh_param();
|
||||
kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
|
||||
|
||||
buf_put_ecc_raw_pubkey_string(ses.writepayload, &ecdh_param->key);
|
||||
free_kexecdh_param(ecdh_param);
|
||||
buf_put_ecc_raw_pubkey_string(ses.writepayload, &ecdh_param->key);
|
||||
free_kexecdh_param(ecdh_param);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case DROPBEAR_KEX_CURVE25519:
|
||||
#ifdef DROPBEAR_CURVE25519
|
||||
{
|
||||
struct kex_curve25519_param *param = gen_kexcurve25519_param();
|
||||
kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey);
|
||||
buf_putstring(ses.writepayload, param->pub, CURVE25519_LEN);
|
||||
free_kexcurve25519_param(param);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
/* calc the signature */
|
||||
|
@ -44,13 +44,19 @@ static void printhelp(const char * progname) {
|
||||
"-b bannerfile Display the contents of bannerfile"
|
||||
" before user login\n"
|
||||
" (default: none)\n"
|
||||
"-r keyfile Specify hostkeys (repeatable)\n"
|
||||
" defaults: \n"
|
||||
#ifdef DROPBEAR_DSS
|
||||
"-d dsskeyfile Use dsskeyfile for the DSS host key\n"
|
||||
" (default: %s)\n"
|
||||
" dss %s\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
"-r rsakeyfile Use rsakeyfile for the RSA host key\n"
|
||||
" (default: %s)\n"
|
||||
" rsa %s\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
" ecdsa %s\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_DELAY_HOSTKEY
|
||||
"-R Create hostkeys as required\n"
|
||||
#endif
|
||||
"-F Don't fork into background\n"
|
||||
#ifdef DISABLE_SYSLOG
|
||||
@ -95,6 +101,9 @@ static void printhelp(const char * progname) {
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
RSA_PRIV_FILENAME,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
ECDSA_PRIV_FILENAME,
|
||||
#endif
|
||||
DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE,
|
||||
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
|
||||
@ -122,6 +131,7 @@ void svr_getopts(int argc, char ** argv) {
|
||||
svr_opts.inetdmode = 0;
|
||||
svr_opts.portcount = 0;
|
||||
svr_opts.hostkey = NULL;
|
||||
svr_opts.delay_hostkey = 0;
|
||||
svr_opts.pidfile = DROPBEAR_PIDFILE;
|
||||
#ifdef ENABLE_SVR_LOCALTCPFWD
|
||||
svr_opts.nolocaltcp = 0;
|
||||
@ -180,6 +190,9 @@ void svr_getopts(int argc, char ** argv) {
|
||||
case 'r':
|
||||
next = &keyfile;
|
||||
break;
|
||||
case 'R':
|
||||
svr_opts.delay_hostkey = 1;
|
||||
break;
|
||||
case 'F':
|
||||
svr_opts.forkbg = 0;
|
||||
break;
|
||||
@ -390,37 +403,37 @@ static void loadhostkey_helper(const char *name, void** src, void** dst, int fat
|
||||
/* Must be called after syslog/etc is working */
|
||||
static void loadhostkey(const char *keyfile, int fatal_duplicate) {
|
||||
sign_key * read_key = new_sign_key();
|
||||
int type = DROPBEAR_SIGNKEY_ANY;
|
||||
enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
loadhostkey_helper("RSA", &read_key->rsakey, &svr_opts.hostkey->rsakey, fatal_duplicate);
|
||||
loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
loadhostkey_helper("DSS", &read_key->dsskey, &svr_opts.hostkey->dsskey, fatal_duplicate);
|
||||
loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
|
||||
loadhostkey_helper("ECDSA256", &read_key->ecckey256, &svr_opts.hostkey->ecckey256, fatal_duplicate);
|
||||
loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
|
||||
loadhostkey_helper("ECDSA384", &read_key->ecckey384, &svr_opts.hostkey->ecckey384, fatal_duplicate);
|
||||
loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
|
||||
loadhostkey_helper("ECDSA521", &read_key->ecckey521, &svr_opts.hostkey->ecckey521, fatal_duplicate);
|
||||
loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
#endif // DROPBEAR_ECDSA
|
||||
@ -438,6 +451,7 @@ static void addhostkey(const char *keyfile) {
|
||||
|
||||
void load_all_hostkeys() {
|
||||
int i;
|
||||
int disable_unset_keys = 1;
|
||||
|
||||
svr_opts.hostkey = new_sign_key();
|
||||
|
||||
@ -459,31 +473,47 @@ void load_all_hostkeys() {
|
||||
loadhostkey(ECDSA_PRIV_FILENAME, 0);
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_DELAY_HOSTKEY
|
||||
if (svr_opts.delay_hostkey)
|
||||
{
|
||||
disable_unset_keys = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (!svr_opts.hostkey->rsakey) {
|
||||
if (disable_unset_keys && !svr_opts.hostkey->rsakey) {
|
||||
disablekey(DROPBEAR_SIGNKEY_RSA);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (!svr_opts.hostkey->dsskey) {
|
||||
if (disable_unset_keys && !svr_opts.hostkey->dsskey) {
|
||||
disablekey(DROPBEAR_SIGNKEY_RSA);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (!svr_opts.hostkey->ecckey256) {
|
||||
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 256)
|
||||
&& !svr_opts.hostkey->ecckey256) {
|
||||
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (!svr_opts.hostkey->ecckey384) {
|
||||
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 384)
|
||||
&& !svr_opts.hostkey->ecckey384) {
|
||||
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (!svr_opts.hostkey->ecckey521) {
|
||||
if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 521)
|
||||
&& !svr_opts.hostkey->ecckey521) {
|
||||
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif /* DROPBEAR_ECDSA */
|
||||
|
||||
}
|
||||
|
14
sysoptions.h
14
sysoptions.h
@ -104,21 +104,27 @@
|
||||
#define DROPBEAR_LTC_PRNG
|
||||
#endif
|
||||
|
||||
// hashes which will be linked and registered
|
||||
#if defined(DROPBEAR_SHA2_256_HMAC) || defined(DROPBEAR_ECC_256)
|
||||
/* RSA can be vulnerable to timing attacks which use the time required for
|
||||
* signing to guess the private key. Blinding avoids this attack, though makes
|
||||
* signing operations slightly slower. */
|
||||
#define RSA_BLINDING
|
||||
|
||||
/* hashes which will be linked and registered */
|
||||
#if defined(DROPBEAR_SHA2_256_HMAC) || defined(DROPBEAR_ECC_256) || defined(DROPBEAR_CURVE25519)
|
||||
#define DROPBEAR_SHA256
|
||||
#endif
|
||||
#if defined(DROPBEAR_ECC_384)
|
||||
#define DROPBEAR_SHA384
|
||||
#endif
|
||||
#if defined(DROPBEAR_SHA2_512_HMAC) || defined(DROPBEAR_ECC_521)
|
||||
/* LTC SHA384 depends on SHA512 */
|
||||
#if defined(DROPBEAR_SHA2_512_HMAC) || defined(DROPBEAR_ECC_521) || defined(DROPBEAR_ECC_384)
|
||||
#define DROPBEAR_SHA512
|
||||
#endif
|
||||
#if defined(DROPBEAR_MD5_HMAC)
|
||||
#define DROPBEAR_MD5
|
||||
#endif
|
||||
|
||||
// roughly 2x 521 bits
|
||||
/* roughly 2x 521 bits */
|
||||
#define MAX_ECC_SIZE 140
|
||||
|
||||
#define MAX_NAME_LEN 64 /* maximum length of a protocol name, isn't
|
||||
|
Loading…
Reference in New Issue
Block a user