/src/dropbear/src/kex-pqhybrid.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "includes.h" |
2 | | #include "algo.h" |
3 | | #include "buffer.h" |
4 | | #include "session.h" |
5 | | #include "bignum.h" |
6 | | #include "dbrandom.h" |
7 | | #include "crypto_desc.h" |
8 | | #include "curve25519.h" |
9 | | #include "kex.h" |
10 | | |
11 | | #if DROPBEAR_PQHYBRID |
12 | | |
13 | 0 | struct kex_pqhybrid_param *gen_kexpqhybrid_param() { |
14 | 0 | struct kex_pqhybrid_param *param = m_malloc(sizeof(*param)); |
15 | 0 | const struct dropbear_kem_desc *kem = ses.newkeys->algo_kex->details; |
16 | |
|
17 | 0 | param->curve25519 = gen_kexcurve25519_param(); |
18 | |
|
19 | 0 | if (IS_DROPBEAR_CLIENT) { |
20 | 0 | param->kem_cli_secret = buf_new(kem->secret_len); |
21 | 0 | param->concat_public = buf_new(kem->public_len + CURVE25519_LEN); |
22 | 0 | kem->kem_gen( |
23 | 0 | buf_getwriteptr(param->concat_public, kem->public_len), |
24 | 0 | buf_getwriteptr(param->kem_cli_secret, kem->secret_len)); |
25 | 0 | buf_incrwritepos(param->concat_public, kem->public_len); |
26 | 0 | buf_incrwritepos(param->kem_cli_secret, kem->secret_len); |
27 | 0 | buf_setpos(param->kem_cli_secret, 0); |
28 | | /* Append the curve25519 parameter */ |
29 | 0 | buf_putbytes(param->concat_public, param->curve25519->pub, CURVE25519_LEN); |
30 | 0 | } |
31 | |
|
32 | 0 | return param; |
33 | 0 | } |
34 | | |
35 | 0 | void free_kexpqhybrid_param(struct kex_pqhybrid_param *param) { |
36 | 0 | free_kexcurve25519_param(param->curve25519); |
37 | 0 | if (param->kem_cli_secret) { |
38 | 0 | buf_burn_free(param->kem_cli_secret); |
39 | 0 | param->kem_cli_secret = NULL; |
40 | 0 | } |
41 | 0 | buf_free(param->concat_public); |
42 | 0 | m_free(param); |
43 | 0 | } |
44 | | |
45 | | void kexpqhybrid_comb_key(struct kex_pqhybrid_param *param, |
46 | 0 | buffer *buf_pub, sign_key *hostkey) { |
47 | |
|
48 | 0 | const struct dropbear_kem_desc *kem = ses.newkeys->algo_kex->details; |
49 | 0 | const struct ltc_hash_descriptor *hash_desc |
50 | 0 | = ses.newkeys->algo_kex->hash_desc; |
51 | | |
52 | | /* Either public key (from client) or ciphertext (from server) */ |
53 | 0 | unsigned char *remote_pub_kem = NULL; |
54 | 0 | buffer *pub_25519 = NULL; |
55 | 0 | buffer *k_out = NULL; |
56 | 0 | unsigned int remote_len; |
57 | 0 | hash_state hs; |
58 | 0 | const buffer * Q_C = NULL; |
59 | 0 | const buffer * Q_S = NULL; |
60 | | |
61 | | /* Extract input parts from the remote peer */ |
62 | 0 | if (IS_DROPBEAR_CLIENT) { |
63 | | /* S_REPLY = S_CT2 || S_PK1 */ |
64 | 0 | remote_len = kem->ciphertext_len; |
65 | 0 | } else { |
66 | | /* C_INIT = C_PK2 || C_PK1 */ |
67 | 0 | remote_len = kem->public_len; |
68 | 0 | } |
69 | 0 | remote_pub_kem = buf_getptr(buf_pub, remote_len); |
70 | 0 | buf_incrpos(buf_pub, remote_len); |
71 | 0 | pub_25519 = buf_getptrcopy(buf_pub, CURVE25519_LEN); |
72 | 0 | buf_incrpos(buf_pub, CURVE25519_LEN); |
73 | | /* Check all is consumed */ |
74 | 0 | if (buf_pub->pos != buf_pub->len) { |
75 | 0 | dropbear_exit("Bad sntrup"); |
76 | 0 | } |
77 | | |
78 | | /* k_out = K_PQ || K_CL */ |
79 | 0 | k_out = buf_new(kem->output_len + CURVE25519_LEN); |
80 | | |
81 | | /* Derive pq kem part (K_PQ) */ |
82 | 0 | if (IS_DROPBEAR_CLIENT) { |
83 | 0 | kem->kem_dec( |
84 | 0 | buf_getwriteptr(k_out, kem->output_len), |
85 | 0 | remote_pub_kem, |
86 | 0 | buf_getptr(param->kem_cli_secret, kem->secret_len)); |
87 | 0 | buf_burn_free(param->kem_cli_secret); |
88 | 0 | param->kem_cli_secret = NULL; |
89 | 0 | } else { |
90 | | /* Server returns ciphertext */ |
91 | 0 | assert(param->concat_public == NULL); |
92 | 0 | param->concat_public = buf_new(kem->ciphertext_len + CURVE25519_LEN); |
93 | 0 | kem->kem_enc( |
94 | 0 | buf_getwriteptr(param->concat_public, kem->ciphertext_len), |
95 | 0 | buf_getwriteptr(k_out, kem->output_len), |
96 | 0 | remote_pub_kem); |
97 | 0 | buf_incrwritepos(param->concat_public, kem->ciphertext_len); |
98 | | /* Append the curve25519 parameter */ |
99 | 0 | buf_putbytes(param->concat_public, param->curve25519->pub, CURVE25519_LEN); |
100 | 0 | } |
101 | 0 | buf_incrwritepos(k_out, kem->output_len); |
102 | | |
103 | | /* Derive ec part (K_CL) */ |
104 | 0 | kexcurve25519_derive(param->curve25519, pub_25519, |
105 | 0 | buf_getwriteptr(k_out, CURVE25519_LEN)); |
106 | 0 | buf_incrwritepos(k_out, CURVE25519_LEN); |
107 | | |
108 | | /* dh_K_bytes = HASH(k_out) |
109 | | dh_K_bytes is a SSH string with length prefix, since |
110 | | that is what needs to be hashed in gen_new_keys() */ |
111 | 0 | ses.dh_K_bytes = buf_new(4 + hash_desc->hashsize); |
112 | 0 | buf_putint(ses.dh_K_bytes, hash_desc->hashsize); |
113 | 0 | hash_desc->init(&hs); |
114 | 0 | hash_desc->process(&hs, k_out->data, k_out->len); |
115 | 0 | hash_desc->done(&hs, buf_getwriteptr(ses.dh_K_bytes, hash_desc->hashsize)); |
116 | 0 | m_burn(&hs, sizeof(hash_state)); |
117 | 0 | buf_incrwritepos(ses.dh_K_bytes, hash_desc->hashsize); |
118 | | |
119 | | /* Create the remainder of the hash buffer */ |
120 | 0 | if (IS_DROPBEAR_CLIENT) { |
121 | 0 | Q_C = param->concat_public; |
122 | 0 | Q_S = buf_pub; |
123 | 0 | } else { |
124 | 0 | Q_S = param->concat_public; |
125 | 0 | Q_C = buf_pub; |
126 | 0 | } |
127 | | |
128 | | /* K_S, the host key */ |
129 | 0 | buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey); |
130 | 0 | buf_putbufstring(ses.kexhashbuf, Q_C); |
131 | 0 | buf_putbufstring(ses.kexhashbuf, Q_S); |
132 | | /* K, the shared secret */ |
133 | 0 | buf_putbytes(ses.kexhashbuf, ses.dh_K_bytes->data, ses.dh_K_bytes->len); |
134 | | |
135 | | /* calculate the hash H to sign */ |
136 | 0 | finish_kexhashbuf(); |
137 | |
|
138 | 0 | buf_burn_free(k_out); |
139 | 0 | buf_free(pub_25519); |
140 | 0 | } |
141 | | |
142 | | #endif /* DROPBEAR_PQHYBRID */ |