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