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