xref: /freebsd/crypto/openssh/kexsntrup761x25519.c (revision 19261079b74319502c6ffa1249920079f0f69a72)
1*19261079SEd Maste /* $OpenBSD: kexsntrup761x25519.c,v 1.1 2020/12/29 00:59:15 djm Exp $ */
2*19261079SEd Maste /*
3*19261079SEd Maste  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
4*19261079SEd Maste  *
5*19261079SEd Maste  * Redistribution and use in source and binary forms, with or without
6*19261079SEd Maste  * modification, are permitted provided that the following conditions
7*19261079SEd Maste  * are met:
8*19261079SEd Maste  * 1. Redistributions of source code must retain the above copyright
9*19261079SEd Maste  *    notice, this list of conditions and the following disclaimer.
10*19261079SEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11*19261079SEd Maste  *    notice, this list of conditions and the following disclaimer in the
12*19261079SEd Maste  *    documentation and/or other materials provided with the distribution.
13*19261079SEd Maste  *
14*19261079SEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*19261079SEd Maste  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*19261079SEd Maste  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*19261079SEd Maste  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*19261079SEd Maste  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*19261079SEd Maste  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*19261079SEd Maste  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*19261079SEd Maste  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*19261079SEd Maste  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*19261079SEd Maste  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*19261079SEd Maste  */
25*19261079SEd Maste 
26*19261079SEd Maste #include "includes.h"
27*19261079SEd Maste 
28*19261079SEd Maste #ifdef USE_SNTRUP761X25519
29*19261079SEd Maste 
30*19261079SEd Maste #include <sys/types.h>
31*19261079SEd Maste 
32*19261079SEd Maste #include <stdio.h>
33*19261079SEd Maste #include <string.h>
34*19261079SEd Maste #include <signal.h>
35*19261079SEd Maste 
36*19261079SEd Maste #include "sshkey.h"
37*19261079SEd Maste #include "kex.h"
38*19261079SEd Maste #include "sshbuf.h"
39*19261079SEd Maste #include "digest.h"
40*19261079SEd Maste #include "ssherr.h"
41*19261079SEd Maste 
42*19261079SEd Maste int
43*19261079SEd Maste kex_kem_sntrup761x25519_keypair(struct kex *kex)
44*19261079SEd Maste {
45*19261079SEd Maste 	struct sshbuf *buf = NULL;
46*19261079SEd Maste 	u_char *cp = NULL;
47*19261079SEd Maste 	size_t need;
48*19261079SEd Maste 	int r;
49*19261079SEd Maste 
50*19261079SEd Maste 	if ((buf = sshbuf_new()) == NULL)
51*19261079SEd Maste 		return SSH_ERR_ALLOC_FAIL;
52*19261079SEd Maste 	need = crypto_kem_sntrup761_PUBLICKEYBYTES + CURVE25519_SIZE;
53*19261079SEd Maste 	if ((r = sshbuf_reserve(buf, need, &cp)) != 0)
54*19261079SEd Maste 		goto out;
55*19261079SEd Maste 	crypto_kem_sntrup761_keypair(cp, kex->sntrup761_client_key);
56*19261079SEd Maste #ifdef DEBUG_KEXECDH
57*19261079SEd Maste 	dump_digest("client public key sntrup761:", cp,
58*19261079SEd Maste 	    crypto_kem_sntrup761_PUBLICKEYBYTES);
59*19261079SEd Maste #endif
60*19261079SEd Maste 	cp += crypto_kem_sntrup761_PUBLICKEYBYTES;
61*19261079SEd Maste 	kexc25519_keygen(kex->c25519_client_key, cp);
62*19261079SEd Maste #ifdef DEBUG_KEXECDH
63*19261079SEd Maste 	dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
64*19261079SEd Maste #endif
65*19261079SEd Maste 	kex->client_pub = buf;
66*19261079SEd Maste 	buf = NULL;
67*19261079SEd Maste  out:
68*19261079SEd Maste 	sshbuf_free(buf);
69*19261079SEd Maste 	return r;
70*19261079SEd Maste }
71*19261079SEd Maste 
72*19261079SEd Maste int
73*19261079SEd Maste kex_kem_sntrup761x25519_enc(struct kex *kex,
74*19261079SEd Maste    const struct sshbuf *client_blob, struct sshbuf **server_blobp,
75*19261079SEd Maste    struct sshbuf **shared_secretp)
76*19261079SEd Maste {
77*19261079SEd Maste 	struct sshbuf *server_blob = NULL;
78*19261079SEd Maste 	struct sshbuf *buf = NULL;
79*19261079SEd Maste 	const u_char *client_pub;
80*19261079SEd Maste 	u_char *kem_key, *ciphertext, *server_pub;
81*19261079SEd Maste 	u_char server_key[CURVE25519_SIZE];
82*19261079SEd Maste 	u_char hash[SSH_DIGEST_MAX_LENGTH];
83*19261079SEd Maste 	size_t need;
84*19261079SEd Maste 	int r;
85*19261079SEd Maste 
86*19261079SEd Maste 	*server_blobp = NULL;
87*19261079SEd Maste 	*shared_secretp = NULL;
88*19261079SEd Maste 
89*19261079SEd Maste 	/* client_blob contains both KEM and ECDH client pubkeys */
90*19261079SEd Maste 	need = crypto_kem_sntrup761_PUBLICKEYBYTES + CURVE25519_SIZE;
91*19261079SEd Maste 	if (sshbuf_len(client_blob) != need) {
92*19261079SEd Maste 		r = SSH_ERR_SIGNATURE_INVALID;
93*19261079SEd Maste 		goto out;
94*19261079SEd Maste 	}
95*19261079SEd Maste 	client_pub = sshbuf_ptr(client_blob);
96*19261079SEd Maste #ifdef DEBUG_KEXECDH
97*19261079SEd Maste 	dump_digest("client public key sntrup761:", client_pub,
98*19261079SEd Maste 	    crypto_kem_sntrup761_PUBLICKEYBYTES);
99*19261079SEd Maste 	dump_digest("client public key 25519:",
100*19261079SEd Maste 	    client_pub + crypto_kem_sntrup761_PUBLICKEYBYTES,
101*19261079SEd Maste 	    CURVE25519_SIZE);
102*19261079SEd Maste #endif
103*19261079SEd Maste 	/* allocate buffer for concatenation of KEM key and ECDH shared key */
104*19261079SEd Maste 	/* the buffer will be hashed and the result is the shared secret */
105*19261079SEd Maste 	if ((buf = sshbuf_new()) == NULL) {
106*19261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
107*19261079SEd Maste 		goto out;
108*19261079SEd Maste 	}
109*19261079SEd Maste 	if ((r = sshbuf_reserve(buf, crypto_kem_sntrup761_BYTES,
110*19261079SEd Maste 	    &kem_key)) != 0)
111*19261079SEd Maste 		goto out;
112*19261079SEd Maste 	/* allocate space for encrypted KEM key and ECDH pub key */
113*19261079SEd Maste 	if ((server_blob = sshbuf_new()) == NULL) {
114*19261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
115*19261079SEd Maste 		goto out;
116*19261079SEd Maste 	}
117*19261079SEd Maste 	need = crypto_kem_sntrup761_CIPHERTEXTBYTES + CURVE25519_SIZE;
118*19261079SEd Maste 	if ((r = sshbuf_reserve(server_blob, need, &ciphertext)) != 0)
119*19261079SEd Maste 		goto out;
120*19261079SEd Maste 	/* generate and encrypt KEM key with client key */
121*19261079SEd Maste 	crypto_kem_sntrup761_enc(ciphertext, kem_key, client_pub);
122*19261079SEd Maste 	/* generate ECDH key pair, store server pubkey after ciphertext */
123*19261079SEd Maste 	server_pub = ciphertext + crypto_kem_sntrup761_CIPHERTEXTBYTES;
124*19261079SEd Maste 	kexc25519_keygen(server_key, server_pub);
125*19261079SEd Maste 	/* append ECDH shared key */
126*19261079SEd Maste 	client_pub += crypto_kem_sntrup761_PUBLICKEYBYTES;
127*19261079SEd Maste 	if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0)
128*19261079SEd Maste 		goto out;
129*19261079SEd Maste 	if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
130*19261079SEd Maste 		goto out;
131*19261079SEd Maste #ifdef DEBUG_KEXECDH
132*19261079SEd Maste 	dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE);
133*19261079SEd Maste 	dump_digest("server cipher text:", ciphertext,
134*19261079SEd Maste 	    crypto_kem_sntrup761_CIPHERTEXTBYTES);
135*19261079SEd Maste 	dump_digest("server kem key:", kem_key, sizeof(kem_key));
136*19261079SEd Maste 	dump_digest("concatenation of KEM key and ECDH shared key:",
137*19261079SEd Maste 	    sshbuf_ptr(buf), sshbuf_len(buf));
138*19261079SEd Maste #endif
139*19261079SEd Maste 	/* string-encoded hash is resulting shared secret */
140*19261079SEd Maste 	sshbuf_reset(buf);
141*19261079SEd Maste 	if ((r = sshbuf_put_string(buf, hash,
142*19261079SEd Maste 	    ssh_digest_bytes(kex->hash_alg))) != 0)
143*19261079SEd Maste 		goto out;
144*19261079SEd Maste #ifdef DEBUG_KEXECDH
145*19261079SEd Maste 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
146*19261079SEd Maste #endif
147*19261079SEd Maste 	*server_blobp = server_blob;
148*19261079SEd Maste 	*shared_secretp = buf;
149*19261079SEd Maste 	server_blob = NULL;
150*19261079SEd Maste 	buf = NULL;
151*19261079SEd Maste  out:
152*19261079SEd Maste 	explicit_bzero(hash, sizeof(hash));
153*19261079SEd Maste 	explicit_bzero(server_key, sizeof(server_key));
154*19261079SEd Maste 	sshbuf_free(server_blob);
155*19261079SEd Maste 	sshbuf_free(buf);
156*19261079SEd Maste 	return r;
157*19261079SEd Maste }
158*19261079SEd Maste 
159*19261079SEd Maste int
160*19261079SEd Maste kex_kem_sntrup761x25519_dec(struct kex *kex,
161*19261079SEd Maste     const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
162*19261079SEd Maste {
163*19261079SEd Maste 	struct sshbuf *buf = NULL;
164*19261079SEd Maste 	u_char *kem_key = NULL;
165*19261079SEd Maste 	const u_char *ciphertext, *server_pub;
166*19261079SEd Maste 	u_char hash[SSH_DIGEST_MAX_LENGTH];
167*19261079SEd Maste 	size_t need;
168*19261079SEd Maste 	int r, decoded;
169*19261079SEd Maste 
170*19261079SEd Maste 	*shared_secretp = NULL;
171*19261079SEd Maste 
172*19261079SEd Maste 	need = crypto_kem_sntrup761_CIPHERTEXTBYTES + CURVE25519_SIZE;
173*19261079SEd Maste 	if (sshbuf_len(server_blob) != need) {
174*19261079SEd Maste 		r = SSH_ERR_SIGNATURE_INVALID;
175*19261079SEd Maste 		goto out;
176*19261079SEd Maste 	}
177*19261079SEd Maste 	ciphertext = sshbuf_ptr(server_blob);
178*19261079SEd Maste 	server_pub = ciphertext + crypto_kem_sntrup761_CIPHERTEXTBYTES;
179*19261079SEd Maste #ifdef DEBUG_KEXECDH
180*19261079SEd Maste 	dump_digest("server cipher text:", ciphertext,
181*19261079SEd Maste 	    crypto_kem_sntrup761_CIPHERTEXTBYTES);
182*19261079SEd Maste 	dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE);
183*19261079SEd Maste #endif
184*19261079SEd Maste 	/* hash concatenation of KEM key and ECDH shared key */
185*19261079SEd Maste 	if ((buf = sshbuf_new()) == NULL) {
186*19261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
187*19261079SEd Maste 		goto out;
188*19261079SEd Maste 	}
189*19261079SEd Maste 	if ((r = sshbuf_reserve(buf, crypto_kem_sntrup761_BYTES,
190*19261079SEd Maste 	    &kem_key)) != 0)
191*19261079SEd Maste 		goto out;
192*19261079SEd Maste 	decoded = crypto_kem_sntrup761_dec(kem_key, ciphertext,
193*19261079SEd Maste 	    kex->sntrup761_client_key);
194*19261079SEd Maste 	if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
195*19261079SEd Maste 	    buf, 1)) < 0)
196*19261079SEd Maste 		goto out;
197*19261079SEd Maste 	if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
198*19261079SEd Maste 		goto out;
199*19261079SEd Maste #ifdef DEBUG_KEXECDH
200*19261079SEd Maste 	dump_digest("client kem key:", kem_key, crypto_kem_sntrup761_BYTES);
201*19261079SEd Maste 	dump_digest("concatenation of KEM key and ECDH shared key:",
202*19261079SEd Maste 	    sshbuf_ptr(buf), sshbuf_len(buf));
203*19261079SEd Maste #endif
204*19261079SEd Maste 	sshbuf_reset(buf);
205*19261079SEd Maste 	if ((r = sshbuf_put_string(buf, hash,
206*19261079SEd Maste 	    ssh_digest_bytes(kex->hash_alg))) != 0)
207*19261079SEd Maste 		goto out;
208*19261079SEd Maste #ifdef DEBUG_KEXECDH
209*19261079SEd Maste 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
210*19261079SEd Maste #endif
211*19261079SEd Maste 	if (decoded != 0) {
212*19261079SEd Maste 		r = SSH_ERR_SIGNATURE_INVALID;
213*19261079SEd Maste 		goto out;
214*19261079SEd Maste 	}
215*19261079SEd Maste 	*shared_secretp = buf;
216*19261079SEd Maste 	buf = NULL;
217*19261079SEd Maste  out:
218*19261079SEd Maste 	explicit_bzero(hash, sizeof(hash));
219*19261079SEd Maste 	sshbuf_free(buf);
220*19261079SEd Maste 	return r;
221*19261079SEd Maste }
222*19261079SEd Maste 
223*19261079SEd Maste #else
224*19261079SEd Maste 
225*19261079SEd Maste #include "ssherr.h"
226*19261079SEd Maste 
227*19261079SEd Maste struct kex;
228*19261079SEd Maste struct sshbuf;
229*19261079SEd Maste struct sshkey;
230*19261079SEd Maste 
231*19261079SEd Maste int
232*19261079SEd Maste kex_kem_sntrup761x25519_keypair(struct kex *kex)
233*19261079SEd Maste {
234*19261079SEd Maste 	return SSH_ERR_SIGN_ALG_UNSUPPORTED;
235*19261079SEd Maste }
236*19261079SEd Maste 
237*19261079SEd Maste int
238*19261079SEd Maste kex_kem_sntrup761x25519_enc(struct kex *kex,
239*19261079SEd Maste    const struct sshbuf *client_blob, struct sshbuf **server_blobp,
240*19261079SEd Maste    struct sshbuf **shared_secretp)
241*19261079SEd Maste {
242*19261079SEd Maste 	return SSH_ERR_SIGN_ALG_UNSUPPORTED;
243*19261079SEd Maste }
244*19261079SEd Maste 
245*19261079SEd Maste int
246*19261079SEd Maste kex_kem_sntrup761x25519_dec(struct kex *kex,
247*19261079SEd Maste     const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
248*19261079SEd Maste {
249*19261079SEd Maste 	return SSH_ERR_SIGN_ALG_UNSUPPORTED;
250*19261079SEd Maste }
251*19261079SEd Maste #endif /* USE_SNTRUP761X25519 */
252