1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
#include <sodium.h>
#include "common-sodium.h"
#include "logging.h"
#include "protocol.h"
void log_bin2hex_sodium(enum log_priority log_prio,
char const * const prefix,
uint8_t const * const buffer,
size_t size)
{
char hexstr[2 * size + 1];
if (log_prio >= lower_prio) {
LOG(log_prio, "%s: %s", prefix, sodium_bin2hex(hexstr, sizeof(hexstr), buffer, size));
sodium_memzero(hexstr, sizeof(hexstr));
}
}
struct longterm_keypair * generate_keypair_sodium(void)
{
struct longterm_keypair * keypair = (struct longterm_keypair *)malloc(sizeof(*keypair));
if (keypair == NULL) {
return NULL;
}
sodium_memzero(keypair->publickey, crypto_kx_PUBLICKEYBYTES);
sodium_memzero(keypair->secretkey, crypto_kx_SECRETKEYBYTES);
crypto_kx_keypair(keypair->publickey, keypair->secretkey);
sodium_mlock(keypair, sizeof(*keypair));
return keypair;
}
struct longterm_keypair * generate_keypair_from_secretkey_hexstr_sodium(char const * const secretkey_hexstr,
size_t secretkey_hexstr_len)
{
struct longterm_keypair * keypair = (struct longterm_keypair *)malloc(sizeof(*keypair));
if (keypair == NULL) {
return NULL;
}
if (sodium_hex2bin(
keypair->secretkey, sizeof(keypair->secretkey), secretkey_hexstr, secretkey_hexstr_len, NULL, NULL, NULL) !=
0) {
LOG(ERROR, "Could not parse private key: %s", secretkey_hexstr);
goto error;
}
if (crypto_scalarmult_base(keypair->publickey, keypair->secretkey) != 0) {
LOG(ERROR, "Could not extract public key from a secret key");
goto error;
}
sodium_mlock(keypair, sizeof(*keypair));
return keypair;
error:
free(keypair);
return NULL;
}
int generate_session_keypair_sodium(struct connection * const state)
{
if (state->session_keys != NULL) {
LOG(ERROR, "Session initialization invoked twice, abort");
return 1;
}
state->session_keys = (struct session_keys *)malloc(sizeof(*(state->session_keys)));
if (state->session_keys == NULL) {
return 1;
}
if (state->is_server_side != 0 && crypto_kx_server_session_keys(state->session_keys->rx,
state->session_keys->tx,
state->my_keypair->publickey,
state->my_keypair->secretkey,
state->peer_publickey) != 0) {
LOG(ERROR, "Session key creation failed");
return 1;
} else if (state->is_server_side == 0 && crypto_kx_client_session_keys(state->session_keys->rx,
state->session_keys->tx,
state->my_keypair->publickey,
state->my_keypair->secretkey,
state->peer_publickey) != 0) {
LOG(ERROR, "Session key creation failed");
return 1;
}
log_bin2hex_sodium(NOTICE, "Generated session rx key", state->session_keys->rx, crypto_kx_SESSIONKEYBYTES);
log_bin2hex_sodium(NOTICE, "Generated session tx key", state->session_keys->tx, crypto_kx_SESSIONKEYBYTES);
return 0;
}
int init_crypto_server(struct connection * const state,
unsigned char const * const server_rx_header,
size_t server_rx_header_size)
{
if (server_rx_header_size != crypto_secretstream_xchacha20poly1305_HEADERBYTES) {
LOG(ERROR,
"Invalid Sodium RX header size: %zu != %zu",
server_rx_header_size,
crypto_secretstream_xchacha20poly1305_HEADERBYTES);
return 1;
}
if (generate_session_keypair_sodium(state) != 0) {
LOG(ERROR, "Client session keypair generation failed");
return 1;
}
crypto_secretstream_xchacha20poly1305_init_pull(&state->crypto_rx_state, server_rx_header, state->session_keys->rx);
return 0;
}
int init_crypto_client(struct connection * const state,
unsigned char const * const client_rx_header,
size_t client_rx_header_size)
{
if (client_rx_header_size != crypto_secretstream_xchacha20poly1305_HEADERBYTES) {
LOG(ERROR,
"Invalid Sodium RX header size: %zu != %zu",
client_rx_header_size,
crypto_secretstream_xchacha20poly1305_HEADERBYTES);
return 1;
}
crypto_secretstream_xchacha20poly1305_init_pull(&state->crypto_rx_state, client_rx_header, state->session_keys->rx);
return 0;
}
|