xref: /freebsd/crypto/openssh/kexsntrup761x25519.c (revision 1323ec571215a77ddd21294f0871979d5ad6b992)
1*1323ec57SEd Maste /* $OpenBSD: kexsntrup761x25519.c,v 1.2 2021/12/05 12:28:27 jsg Exp $ */
219261079SEd Maste /*
319261079SEd Maste  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
419261079SEd Maste  *
519261079SEd Maste  * Redistribution and use in source and binary forms, with or without
619261079SEd Maste  * modification, are permitted provided that the following conditions
719261079SEd Maste  * are met:
819261079SEd Maste  * 1. Redistributions of source code must retain the above copyright
919261079SEd Maste  *    notice, this list of conditions and the following disclaimer.
1019261079SEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
1119261079SEd Maste  *    notice, this list of conditions and the following disclaimer in the
1219261079SEd Maste  *    documentation and/or other materials provided with the distribution.
1319261079SEd Maste  *
1419261079SEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1519261079SEd Maste  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1619261079SEd Maste  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1719261079SEd Maste  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1819261079SEd Maste  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1919261079SEd Maste  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2019261079SEd Maste  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2119261079SEd Maste  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2219261079SEd Maste  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2319261079SEd Maste  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2419261079SEd Maste  */
2519261079SEd Maste 
2619261079SEd Maste #include "includes.h"
2719261079SEd Maste 
2819261079SEd Maste #ifdef USE_SNTRUP761X25519
2919261079SEd Maste 
3019261079SEd Maste #include <sys/types.h>
3119261079SEd Maste 
3219261079SEd Maste #include <stdio.h>
3319261079SEd Maste #include <string.h>
3419261079SEd Maste #include <signal.h>
3519261079SEd Maste 
3619261079SEd Maste #include "sshkey.h"
3719261079SEd Maste #include "kex.h"
3819261079SEd Maste #include "sshbuf.h"
3919261079SEd Maste #include "digest.h"
4019261079SEd Maste #include "ssherr.h"
4119261079SEd Maste 
4219261079SEd Maste int
kex_kem_sntrup761x25519_keypair(struct kex * kex)4319261079SEd Maste kex_kem_sntrup761x25519_keypair(struct kex *kex)
4419261079SEd Maste {
4519261079SEd Maste 	struct sshbuf *buf = NULL;
4619261079SEd Maste 	u_char *cp = NULL;
4719261079SEd Maste 	size_t need;
4819261079SEd Maste 	int r;
4919261079SEd Maste 
5019261079SEd Maste 	if ((buf = sshbuf_new()) == NULL)
5119261079SEd Maste 		return SSH_ERR_ALLOC_FAIL;
5219261079SEd Maste 	need = crypto_kem_sntrup761_PUBLICKEYBYTES + CURVE25519_SIZE;
5319261079SEd Maste 	if ((r = sshbuf_reserve(buf, need, &cp)) != 0)
5419261079SEd Maste 		goto out;
5519261079SEd Maste 	crypto_kem_sntrup761_keypair(cp, kex->sntrup761_client_key);
5619261079SEd Maste #ifdef DEBUG_KEXECDH
5719261079SEd Maste 	dump_digest("client public key sntrup761:", cp,
5819261079SEd Maste 	    crypto_kem_sntrup761_PUBLICKEYBYTES);
5919261079SEd Maste #endif
6019261079SEd Maste 	cp += crypto_kem_sntrup761_PUBLICKEYBYTES;
6119261079SEd Maste 	kexc25519_keygen(kex->c25519_client_key, cp);
6219261079SEd Maste #ifdef DEBUG_KEXECDH
6319261079SEd Maste 	dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
6419261079SEd Maste #endif
6519261079SEd Maste 	kex->client_pub = buf;
6619261079SEd Maste 	buf = NULL;
6719261079SEd Maste  out:
6819261079SEd Maste 	sshbuf_free(buf);
6919261079SEd Maste 	return r;
7019261079SEd Maste }
7119261079SEd Maste 
7219261079SEd Maste int
kex_kem_sntrup761x25519_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)7319261079SEd Maste kex_kem_sntrup761x25519_enc(struct kex *kex,
7419261079SEd Maste    const struct sshbuf *client_blob, struct sshbuf **server_blobp,
7519261079SEd Maste    struct sshbuf **shared_secretp)
7619261079SEd Maste {
7719261079SEd Maste 	struct sshbuf *server_blob = NULL;
7819261079SEd Maste 	struct sshbuf *buf = NULL;
7919261079SEd Maste 	const u_char *client_pub;
8019261079SEd Maste 	u_char *kem_key, *ciphertext, *server_pub;
8119261079SEd Maste 	u_char server_key[CURVE25519_SIZE];
8219261079SEd Maste 	u_char hash[SSH_DIGEST_MAX_LENGTH];
8319261079SEd Maste 	size_t need;
8419261079SEd Maste 	int r;
8519261079SEd Maste 
8619261079SEd Maste 	*server_blobp = NULL;
8719261079SEd Maste 	*shared_secretp = NULL;
8819261079SEd Maste 
8919261079SEd Maste 	/* client_blob contains both KEM and ECDH client pubkeys */
9019261079SEd Maste 	need = crypto_kem_sntrup761_PUBLICKEYBYTES + CURVE25519_SIZE;
9119261079SEd Maste 	if (sshbuf_len(client_blob) != need) {
9219261079SEd Maste 		r = SSH_ERR_SIGNATURE_INVALID;
9319261079SEd Maste 		goto out;
9419261079SEd Maste 	}
9519261079SEd Maste 	client_pub = sshbuf_ptr(client_blob);
9619261079SEd Maste #ifdef DEBUG_KEXECDH
9719261079SEd Maste 	dump_digest("client public key sntrup761:", client_pub,
9819261079SEd Maste 	    crypto_kem_sntrup761_PUBLICKEYBYTES);
9919261079SEd Maste 	dump_digest("client public key 25519:",
10019261079SEd Maste 	    client_pub + crypto_kem_sntrup761_PUBLICKEYBYTES,
10119261079SEd Maste 	    CURVE25519_SIZE);
10219261079SEd Maste #endif
10319261079SEd Maste 	/* allocate buffer for concatenation of KEM key and ECDH shared key */
10419261079SEd Maste 	/* the buffer will be hashed and the result is the shared secret */
10519261079SEd Maste 	if ((buf = sshbuf_new()) == NULL) {
10619261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
10719261079SEd Maste 		goto out;
10819261079SEd Maste 	}
10919261079SEd Maste 	if ((r = sshbuf_reserve(buf, crypto_kem_sntrup761_BYTES,
11019261079SEd Maste 	    &kem_key)) != 0)
11119261079SEd Maste 		goto out;
11219261079SEd Maste 	/* allocate space for encrypted KEM key and ECDH pub key */
11319261079SEd Maste 	if ((server_blob = sshbuf_new()) == NULL) {
11419261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
11519261079SEd Maste 		goto out;
11619261079SEd Maste 	}
11719261079SEd Maste 	need = crypto_kem_sntrup761_CIPHERTEXTBYTES + CURVE25519_SIZE;
11819261079SEd Maste 	if ((r = sshbuf_reserve(server_blob, need, &ciphertext)) != 0)
11919261079SEd Maste 		goto out;
12019261079SEd Maste 	/* generate and encrypt KEM key with client key */
12119261079SEd Maste 	crypto_kem_sntrup761_enc(ciphertext, kem_key, client_pub);
12219261079SEd Maste 	/* generate ECDH key pair, store server pubkey after ciphertext */
12319261079SEd Maste 	server_pub = ciphertext + crypto_kem_sntrup761_CIPHERTEXTBYTES;
12419261079SEd Maste 	kexc25519_keygen(server_key, server_pub);
12519261079SEd Maste 	/* append ECDH shared key */
12619261079SEd Maste 	client_pub += crypto_kem_sntrup761_PUBLICKEYBYTES;
12719261079SEd Maste 	if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0)
12819261079SEd Maste 		goto out;
12919261079SEd Maste 	if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
13019261079SEd Maste 		goto out;
13119261079SEd Maste #ifdef DEBUG_KEXECDH
13219261079SEd Maste 	dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE);
13319261079SEd Maste 	dump_digest("server cipher text:", ciphertext,
13419261079SEd Maste 	    crypto_kem_sntrup761_CIPHERTEXTBYTES);
135*1323ec57SEd Maste 	dump_digest("server kem key:", kem_key, crypto_kem_sntrup761_BYTES);
13619261079SEd Maste 	dump_digest("concatenation of KEM key and ECDH shared key:",
13719261079SEd Maste 	    sshbuf_ptr(buf), sshbuf_len(buf));
13819261079SEd Maste #endif
13919261079SEd Maste 	/* string-encoded hash is resulting shared secret */
14019261079SEd Maste 	sshbuf_reset(buf);
14119261079SEd Maste 	if ((r = sshbuf_put_string(buf, hash,
14219261079SEd Maste 	    ssh_digest_bytes(kex->hash_alg))) != 0)
14319261079SEd Maste 		goto out;
14419261079SEd Maste #ifdef DEBUG_KEXECDH
14519261079SEd Maste 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
14619261079SEd Maste #endif
14719261079SEd Maste 	*server_blobp = server_blob;
14819261079SEd Maste 	*shared_secretp = buf;
14919261079SEd Maste 	server_blob = NULL;
15019261079SEd Maste 	buf = NULL;
15119261079SEd Maste  out:
15219261079SEd Maste 	explicit_bzero(hash, sizeof(hash));
15319261079SEd Maste 	explicit_bzero(server_key, sizeof(server_key));
15419261079SEd Maste 	sshbuf_free(server_blob);
15519261079SEd Maste 	sshbuf_free(buf);
15619261079SEd Maste 	return r;
15719261079SEd Maste }
15819261079SEd Maste 
15919261079SEd Maste int
kex_kem_sntrup761x25519_dec(struct kex * kex,const struct sshbuf * server_blob,struct sshbuf ** shared_secretp)16019261079SEd Maste kex_kem_sntrup761x25519_dec(struct kex *kex,
16119261079SEd Maste     const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
16219261079SEd Maste {
16319261079SEd Maste 	struct sshbuf *buf = NULL;
16419261079SEd Maste 	u_char *kem_key = NULL;
16519261079SEd Maste 	const u_char *ciphertext, *server_pub;
16619261079SEd Maste 	u_char hash[SSH_DIGEST_MAX_LENGTH];
16719261079SEd Maste 	size_t need;
16819261079SEd Maste 	int r, decoded;
16919261079SEd Maste 
17019261079SEd Maste 	*shared_secretp = NULL;
17119261079SEd Maste 
17219261079SEd Maste 	need = crypto_kem_sntrup761_CIPHERTEXTBYTES + CURVE25519_SIZE;
17319261079SEd Maste 	if (sshbuf_len(server_blob) != need) {
17419261079SEd Maste 		r = SSH_ERR_SIGNATURE_INVALID;
17519261079SEd Maste 		goto out;
17619261079SEd Maste 	}
17719261079SEd Maste 	ciphertext = sshbuf_ptr(server_blob);
17819261079SEd Maste 	server_pub = ciphertext + crypto_kem_sntrup761_CIPHERTEXTBYTES;
17919261079SEd Maste #ifdef DEBUG_KEXECDH
18019261079SEd Maste 	dump_digest("server cipher text:", ciphertext,
18119261079SEd Maste 	    crypto_kem_sntrup761_CIPHERTEXTBYTES);
18219261079SEd Maste 	dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE);
18319261079SEd Maste #endif
18419261079SEd Maste 	/* hash concatenation of KEM key and ECDH shared key */
18519261079SEd Maste 	if ((buf = sshbuf_new()) == NULL) {
18619261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
18719261079SEd Maste 		goto out;
18819261079SEd Maste 	}
18919261079SEd Maste 	if ((r = sshbuf_reserve(buf, crypto_kem_sntrup761_BYTES,
19019261079SEd Maste 	    &kem_key)) != 0)
19119261079SEd Maste 		goto out;
19219261079SEd Maste 	decoded = crypto_kem_sntrup761_dec(kem_key, ciphertext,
19319261079SEd Maste 	    kex->sntrup761_client_key);
19419261079SEd Maste 	if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
19519261079SEd Maste 	    buf, 1)) < 0)
19619261079SEd Maste 		goto out;
19719261079SEd Maste 	if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
19819261079SEd Maste 		goto out;
19919261079SEd Maste #ifdef DEBUG_KEXECDH
20019261079SEd Maste 	dump_digest("client kem key:", kem_key, crypto_kem_sntrup761_BYTES);
20119261079SEd Maste 	dump_digest("concatenation of KEM key and ECDH shared key:",
20219261079SEd Maste 	    sshbuf_ptr(buf), sshbuf_len(buf));
20319261079SEd Maste #endif
20419261079SEd Maste 	sshbuf_reset(buf);
20519261079SEd Maste 	if ((r = sshbuf_put_string(buf, hash,
20619261079SEd Maste 	    ssh_digest_bytes(kex->hash_alg))) != 0)
20719261079SEd Maste 		goto out;
20819261079SEd Maste #ifdef DEBUG_KEXECDH
20919261079SEd Maste 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
21019261079SEd Maste #endif
21119261079SEd Maste 	if (decoded != 0) {
21219261079SEd Maste 		r = SSH_ERR_SIGNATURE_INVALID;
21319261079SEd Maste 		goto out;
21419261079SEd Maste 	}
21519261079SEd Maste 	*shared_secretp = buf;
21619261079SEd Maste 	buf = NULL;
21719261079SEd Maste  out:
21819261079SEd Maste 	explicit_bzero(hash, sizeof(hash));
21919261079SEd Maste 	sshbuf_free(buf);
22019261079SEd Maste 	return r;
22119261079SEd Maste }
22219261079SEd Maste 
22319261079SEd Maste #else
22419261079SEd Maste 
22519261079SEd Maste #include "ssherr.h"
22619261079SEd Maste 
22719261079SEd Maste struct kex;
22819261079SEd Maste struct sshbuf;
22919261079SEd Maste struct sshkey;
23019261079SEd Maste 
23119261079SEd Maste int
kex_kem_sntrup761x25519_keypair(struct kex * kex)23219261079SEd Maste kex_kem_sntrup761x25519_keypair(struct kex *kex)
23319261079SEd Maste {
23419261079SEd Maste 	return SSH_ERR_SIGN_ALG_UNSUPPORTED;
23519261079SEd Maste }
23619261079SEd Maste 
23719261079SEd Maste int
kex_kem_sntrup761x25519_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)23819261079SEd Maste kex_kem_sntrup761x25519_enc(struct kex *kex,
23919261079SEd Maste    const struct sshbuf *client_blob, struct sshbuf **server_blobp,
24019261079SEd Maste    struct sshbuf **shared_secretp)
24119261079SEd Maste {
24219261079SEd Maste 	return SSH_ERR_SIGN_ALG_UNSUPPORTED;
24319261079SEd Maste }
24419261079SEd Maste 
24519261079SEd Maste int
kex_kem_sntrup761x25519_dec(struct kex * kex,const struct sshbuf * server_blob,struct sshbuf ** shared_secretp)24619261079SEd Maste kex_kem_sntrup761x25519_dec(struct kex *kex,
24719261079SEd Maste     const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
24819261079SEd Maste {
24919261079SEd Maste 	return SSH_ERR_SIGN_ALG_UNSUPPORTED;
25019261079SEd Maste }
25119261079SEd Maste #endif /* USE_SNTRUP761X25519 */
252