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 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 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 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 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 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 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