kexsntrup761x25519.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /* $OpenBSD: kexsntrup4591761x25519.c,v 1.3 2019/01/21 10:40:11 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. #include "includes.h"
  26. #ifdef USE_SNTRUP761X25519
  27. #include <sys/types.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <signal.h>
  31. #include "sshkey.h"
  32. #include "kex.h"
  33. #include "sshbuf.h"
  34. #include "digest.h"
  35. #include "ssherr.h"
  36. int
  37. kex_kem_sntrup761x25519_keypair(struct kex *kex)
  38. {
  39. struct sshbuf *buf = NULL;
  40. u_char *cp = NULL;
  41. size_t need;
  42. int r;
  43. if ((buf = sshbuf_new()) == NULL)
  44. return SSH_ERR_ALLOC_FAIL;
  45. need = crypto_kem_sntrup761_PUBLICKEYBYTES + CURVE25519_SIZE;
  46. if ((r = sshbuf_reserve(buf, need, &cp)) != 0)
  47. goto out;
  48. crypto_kem_sntrup761_keypair(cp, kex->sntrup761_client_key);
  49. #ifdef DEBUG_KEXECDH
  50. dump_digest("client public key sntrup761:", cp,
  51. crypto_kem_sntrup761_PUBLICKEYBYTES);
  52. #endif
  53. cp += crypto_kem_sntrup761_PUBLICKEYBYTES;
  54. kexc25519_keygen(kex->c25519_client_key, cp);
  55. #ifdef DEBUG_KEXECDH
  56. dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
  57. #endif
  58. kex->client_pub = buf;
  59. buf = NULL;
  60. out:
  61. sshbuf_free(buf);
  62. return r;
  63. }
  64. int
  65. kex_kem_sntrup761x25519_enc(struct kex *kex,
  66. const struct sshbuf *client_blob, struct sshbuf **server_blobp,
  67. struct sshbuf **shared_secretp)
  68. {
  69. struct sshbuf *server_blob = NULL;
  70. struct sshbuf *buf = NULL;
  71. const u_char *client_pub;
  72. u_char *kem_key, *ciphertext, *server_pub;
  73. u_char server_key[CURVE25519_SIZE];
  74. u_char hash[SSH_DIGEST_MAX_LENGTH];
  75. size_t need;
  76. int r;
  77. *server_blobp = NULL;
  78. *shared_secretp = NULL;
  79. /* client_blob contains both KEM and ECDH client pubkeys */
  80. need = crypto_kem_sntrup761_PUBLICKEYBYTES + CURVE25519_SIZE;
  81. if (sshbuf_len(client_blob) != need) {
  82. r = SSH_ERR_SIGNATURE_INVALID;
  83. goto out;
  84. }
  85. client_pub = sshbuf_ptr(client_blob);
  86. #ifdef DEBUG_KEXECDH
  87. dump_digest("client public key sntrup761:", client_pub,
  88. crypto_kem_sntrup761_PUBLICKEYBYTES);
  89. dump_digest("client public key 25519:",
  90. client_pub + crypto_kem_sntrup761_PUBLICKEYBYTES,
  91. CURVE25519_SIZE);
  92. #endif
  93. /* allocate buffer for concatenation of KEM key and ECDH shared key */
  94. /* the buffer will be hashed and the result is the shared secret */
  95. if ((buf = sshbuf_new()) == NULL) {
  96. r = SSH_ERR_ALLOC_FAIL;
  97. goto out;
  98. }
  99. if ((r = sshbuf_reserve(buf, crypto_kem_sntrup761_BYTES,
  100. &kem_key)) != 0)
  101. goto out;
  102. /* allocate space for encrypted KEM key and ECDH pub key */
  103. if ((server_blob = sshbuf_new()) == NULL) {
  104. r = SSH_ERR_ALLOC_FAIL;
  105. goto out;
  106. }
  107. need = crypto_kem_sntrup761_CIPHERTEXTBYTES + CURVE25519_SIZE;
  108. if ((r = sshbuf_reserve(server_blob, need, &ciphertext)) != 0)
  109. goto out;
  110. /* generate and encrypt KEM key with client key */
  111. crypto_kem_sntrup761_enc(ciphertext, kem_key, client_pub);
  112. /* generate ECDH key pair, store server pubkey after ciphertext */
  113. server_pub = ciphertext + crypto_kem_sntrup761_CIPHERTEXTBYTES;
  114. kexc25519_keygen(server_key, server_pub);
  115. /* append ECDH shared key */
  116. client_pub += crypto_kem_sntrup761_PUBLICKEYBYTES;
  117. if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0)
  118. goto out;
  119. if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
  120. goto out;
  121. #ifdef DEBUG_KEXECDH
  122. dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE);
  123. dump_digest("server cipher text:", ciphertext,
  124. crypto_kem_sntrup761_CIPHERTEXTBYTES);
  125. dump_digest("server kem key:", kem_key, sizeof(kem_key));
  126. dump_digest("concatenation of KEM key and ECDH shared key:",
  127. sshbuf_ptr(buf), sshbuf_len(buf));
  128. #endif
  129. /* string-encoded hash is resulting shared secret */
  130. sshbuf_reset(buf);
  131. if ((r = sshbuf_put_string(buf, hash,
  132. ssh_digest_bytes(kex->hash_alg))) != 0)
  133. goto out;
  134. #ifdef DEBUG_KEXECDH
  135. dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
  136. #endif
  137. *server_blobp = server_blob;
  138. *shared_secretp = buf;
  139. server_blob = NULL;
  140. buf = NULL;
  141. out:
  142. explicit_bzero(hash, sizeof(hash));
  143. explicit_bzero(server_key, sizeof(server_key));
  144. sshbuf_free(server_blob);
  145. sshbuf_free(buf);
  146. return r;
  147. }
  148. int
  149. kex_kem_sntrup761x25519_dec(struct kex *kex,
  150. const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
  151. {
  152. struct sshbuf *buf = NULL;
  153. u_char *kem_key = NULL;
  154. const u_char *ciphertext, *server_pub;
  155. u_char hash[SSH_DIGEST_MAX_LENGTH];
  156. size_t need;
  157. int r, decoded;
  158. *shared_secretp = NULL;
  159. need = crypto_kem_sntrup761_CIPHERTEXTBYTES + CURVE25519_SIZE;
  160. if (sshbuf_len(server_blob) != need) {
  161. r = SSH_ERR_SIGNATURE_INVALID;
  162. goto out;
  163. }
  164. ciphertext = sshbuf_ptr(server_blob);
  165. server_pub = ciphertext + crypto_kem_sntrup761_CIPHERTEXTBYTES;
  166. #ifdef DEBUG_KEXECDH
  167. dump_digest("server cipher text:", ciphertext,
  168. crypto_kem_sntrup761_CIPHERTEXTBYTES);
  169. dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE);
  170. #endif
  171. /* hash concatenation of KEM key and ECDH shared key */
  172. if ((buf = sshbuf_new()) == NULL) {
  173. r = SSH_ERR_ALLOC_FAIL;
  174. goto out;
  175. }
  176. if ((r = sshbuf_reserve(buf, crypto_kem_sntrup761_BYTES,
  177. &kem_key)) != 0)
  178. goto out;
  179. decoded = crypto_kem_sntrup761_dec(kem_key, ciphertext,
  180. kex->sntrup761_client_key);
  181. if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
  182. buf, 1)) < 0)
  183. goto out;
  184. if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
  185. goto out;
  186. #ifdef DEBUG_KEXECDH
  187. dump_digest("client kem key:", kem_key, crypto_kem_sntrup761_BYTES);
  188. dump_digest("concatenation of KEM key and ECDH shared key:",
  189. sshbuf_ptr(buf), sshbuf_len(buf));
  190. #endif
  191. sshbuf_reset(buf);
  192. if ((r = sshbuf_put_string(buf, hash,
  193. ssh_digest_bytes(kex->hash_alg))) != 0)
  194. goto out;
  195. #ifdef DEBUG_KEXECDH
  196. dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
  197. #endif
  198. if (decoded != 0) {
  199. r = SSH_ERR_SIGNATURE_INVALID;
  200. goto out;
  201. }
  202. *shared_secretp = buf;
  203. buf = NULL;
  204. out:
  205. explicit_bzero(hash, sizeof(hash));
  206. sshbuf_free(buf);
  207. return r;
  208. }
  209. #else
  210. #include "ssherr.h"
  211. struct kex;
  212. struct sshbuf;
  213. struct sshkey;
  214. int
  215. kex_kem_sntrup761x25519_keypair(struct kex *kex)
  216. {
  217. return SSH_ERR_SIGN_ALG_UNSUPPORTED;
  218. }
  219. int
  220. kex_kem_sntrup761x25519_enc(struct kex *kex,
  221. const struct sshbuf *client_blob, struct sshbuf **server_blobp,
  222. struct sshbuf **shared_secretp)
  223. {
  224. return SSH_ERR_SIGN_ALG_UNSUPPORTED;
  225. }
  226. int
  227. kex_kem_sntrup761x25519_dec(struct kex *kex,
  228. const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
  229. {
  230. return SSH_ERR_SIGN_ALG_UNSUPPORTED;
  231. }
  232. #endif /* USE_SNTRUP761X25519 */