forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhsm_encryption.c
155 lines (133 loc) · 4.48 KB
/
hsm_encryption.c
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include "config.h"
#include <ccan/tal/str/str.h>
#include <common/errcode.h>
#include <common/hsm_encryption.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
int hsm_secret_encryption_key_with_exitcode(const char *pass, struct secret *key,
char **err_msg)
{
u8 salt[16] = "c-lightning\0\0\0\0\0";
/* Don't swap the encryption key ! */
if (sodium_mlock(key->data, sizeof(key->data)) != 0) {
*err_msg = "Could not lock hsm_secret encryption key memory.";
return EXITCODE_HSM_GENERIC_ERROR;
}
/* Check bounds. */
if (strlen(pass) < crypto_pwhash_argon2id_PASSWD_MIN) {
*err_msg = "Password too short to be able to derive a key from it.";
return EXITCODE_HSM_BAD_PASSWORD;
} else if (strlen(pass) > crypto_pwhash_argon2id_PASSWD_MAX) {
*err_msg = "Password too long to be able to derive a key from it.";
return EXITCODE_HSM_BAD_PASSWORD;
}
/* Now derive the key. */
if (crypto_pwhash(key->data, sizeof(key->data), pass, strlen(pass), salt,
/* INTERACTIVE needs 64 MiB of RAM, MODERATE needs 256,
* and SENSITIVE needs 1024. */
crypto_pwhash_argon2id_OPSLIMIT_MODERATE,
crypto_pwhash_argon2id_MEMLIMIT_MODERATE,
crypto_pwhash_ALG_ARGON2ID13) != 0) {
*err_msg = "Could not derive a key from the password.";
return EXITCODE_HSM_BAD_PASSWORD;
}
return 0;
}
bool encrypt_hsm_secret(const struct secret *encryption_key,
const struct secret *hsm_secret,
struct encrypted_hsm_secret *output)
{
crypto_secretstream_xchacha20poly1305_state crypto_state;
if (crypto_secretstream_xchacha20poly1305_init_push(&crypto_state, output->data,
encryption_key->data) != 0)
return false;
if (crypto_secretstream_xchacha20poly1305_push(&crypto_state,
output->data + HS_HEADER_LEN,
NULL, hsm_secret->data,
sizeof(hsm_secret->data),
/* Additional data and tag */
NULL, 0, 0))
return false;
return true;
}
bool decrypt_hsm_secret(const struct secret *encryption_key,
const struct encrypted_hsm_secret *cipher,
struct secret *output)
{
crypto_secretstream_xchacha20poly1305_state crypto_state;
/* The header part */
if (crypto_secretstream_xchacha20poly1305_init_pull(&crypto_state, cipher->data,
encryption_key->data) != 0)
return false;
/* The ciphertext part */
if (crypto_secretstream_xchacha20poly1305_pull(&crypto_state, output->data,
NULL, 0,
cipher->data + HS_HEADER_LEN,
HS_CIPHERTEXT_LEN,
NULL, 0) != 0)
return false;
return true;
}
/* Returns -1 on error (and sets errno), 0 if not encrypted, 1 if it is */
int is_hsm_secret_encrypted(const char *path)
{
struct stat st;
if (stat(path, &st) != 0)
return -1;
return st.st_size == ENCRYPTED_HSM_SECRET_LEN;
}
void discard_key(struct secret *key TAKES)
{
/* sodium_munlock() also zeroes the memory. */
sodium_munlock(key->data, sizeof(key->data));
if (taken(key))
tal_free(key);
}
/* Read a line from stdin, do not take the newline character into account. */
static bool getline_stdin_pass(char **passwd, size_t *passwd_size)
{
if (getline(passwd, passwd_size, stdin) < 0)
return false;
if ((*passwd)[strlen(*passwd) - 1] == '\n')
(*passwd)[strlen(*passwd) - 1] = '\0';
return true;
}
char *read_stdin_pass_with_exit_code(char **reason, int *exit_code)
{
struct termios current_term, temp_term;
char *passwd = NULL;
size_t passwd_size = 0;
if (isatty(fileno(stdin))) {
/* Set a temporary term, same as current but with ECHO disabled. */
if (tcgetattr(fileno(stdin), ¤t_term) != 0) {
*reason = "Could not get current terminal options.";
*exit_code = EXITCODE_HSM_PASSWORD_INPUT_ERR;
return NULL;
}
temp_term = current_term;
temp_term.c_lflag &= ~ECHO;
if (tcsetattr(fileno(stdin), TCSANOW, &temp_term) != 0) {
*reason = "Could not disable pass echoing.";
*exit_code = EXITCODE_HSM_PASSWORD_INPUT_ERR;
return NULL;
}
if (!getline_stdin_pass(&passwd, &passwd_size)) {
*reason = "Could not read pass from stdin.";
*exit_code = EXITCODE_HSM_PASSWORD_INPUT_ERR;
return NULL;
}
/* Restore the original terminal */
if (tcsetattr(fileno(stdin), TCSANOW, ¤t_term) != 0) {
*reason = "Could not restore terminal options.";
free(passwd);
*exit_code = EXITCODE_HSM_PASSWORD_INPUT_ERR;
return NULL;
}
} else if (!getline_stdin_pass(&passwd, &passwd_size)) {
*reason = "Could not read pass from stdin.";
*exit_code = EXITCODE_HSM_PASSWORD_INPUT_ERR;
return NULL;
}
return passwd;
}