Skip to content

Commit 1d27497

Browse files
committed
Add keypair derivation from password #410
1 parent 1d14a1a commit 1d27497

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

src/keygen.c

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,47 @@
1919

2020

2121
#include <stdio.h>
22+
#include <string.h>
2223
#include <sodium.h>
2324
#include <fcntl.h>
2425
#include <unistd.h>
2526

2627
#include <sys/ioctl.h>
2728
#include <linux/random.h>
2829

29-
int main(void)
30+
int main(int argc, char** argv)
3031
{
3132
unsigned char drone_publickey[crypto_box_PUBLICKEYBYTES];
3233
unsigned char drone_secretkey[crypto_box_SECRETKEYBYTES];
3334
unsigned char gs_publickey[crypto_box_PUBLICKEYBYTES];
3435
unsigned char gs_secretkey[crypto_box_SECRETKEYBYTES];
3536
FILE *fp;
37+
char *password = NULL;
3638

39+
if(argc == 2)
40+
{
41+
password = argv[1];
42+
}
43+
44+
if(argc > 2)
45+
{
46+
fprintf(stderr, "Usage: %s [password]\n", argv[0]);
47+
return 1;
48+
}
49+
50+
// check for enough entropy and warn if sodium_init() can freeze
3751
{
3852
int fd;
3953
int c;
4054

41-
if ((fd = open("/dev/random", O_RDONLY)) != -1) {
42-
if (ioctl(fd, RNDGETENTCNT, &c) == 0 && c < 160) {
55+
if ((fd = open("/dev/random", O_RDONLY)) != -1)
56+
{
57+
if (ioctl(fd, RNDGETENTCNT, &c) == 0 && c < 160)
58+
{
4359
fprintf(stderr, "This system doesn't provide enough entropy to quickly generate high-quality random numbers.\n"
4460
"Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.\n"
4561
"On virtualized Linux environments, also consider using virtio-rng.\n"
46-
"The service will not start until enough entropy has been collected.\n");
62+
"This command will wait until enough entropy has been collected.\n");
4763
}
4864
(void) close(fd);
4965
}
@@ -55,11 +71,38 @@ int main(void)
5571
return 1;
5672
}
5773

58-
if (crypto_box_keypair(drone_publickey, drone_secretkey) !=0 ||
59-
crypto_box_keypair(gs_publickey, gs_secretkey) != 0)
74+
if (password != NULL)
6075
{
61-
fprintf(stderr, "Unable to generate keys\n");
62-
return 1;
76+
unsigned char salt[crypto_pwhash_argon2i_SALTBYTES] = \
77+
{'w','i','f','i','b','r','o','a','d','c','a','s','t','k','e','y'};
78+
79+
unsigned char seed[crypto_box_SEEDBYTES];
80+
if (crypto_pwhash_argon2i
81+
(seed, sizeof(seed), password, strlen(password), salt,
82+
crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE, // Low CPU usage
83+
crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE, // 64MB or RAM is required
84+
crypto_pwhash_ALG_ARGON2I13) != 0) // Ensure compatibility with old libsodium versions
85+
{
86+
fprintf(stderr, "Unable to derive seed from password\n");
87+
return 1;
88+
}
89+
if (crypto_box_seed_keypair(drone_publickey, drone_secretkey, seed) !=0 ||
90+
crypto_box_seed_keypair(gs_publickey, gs_secretkey, seed) != 0)
91+
{
92+
fprintf(stderr, "Unable to derive keys\n");
93+
return 1;
94+
}
95+
fprintf(stderr, "Keypair derived from provided password\n");
96+
}
97+
else
98+
{
99+
if (crypto_box_keypair(drone_publickey, drone_secretkey) !=0 ||
100+
crypto_box_keypair(gs_publickey, gs_secretkey) != 0)
101+
{
102+
fprintf(stderr, "Unable to generate keys\n");
103+
return 1;
104+
}
105+
fprintf(stderr, "Keypair generated from random seed\n");
63106
}
64107

65108
if((fp = fopen("drone.key", "w")) == NULL)

wfb_ng/tests/test_txrx.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import struct
77
import errno
8+
import hashlib
89

910
from twisted.python import log
1011
from twisted.trial import unittest
@@ -360,3 +361,17 @@ def test_cmd_radio_invalid_args(self):
360361

361362
yield df_sleep(0.1)
362363
self.assertEqual([b'm%d' % (i + 1,) for i in range(7)], self.rxp.rxq)
364+
365+
366+
class KeyDerivationTestCase(unittest.TestCase):
367+
@defer.inlineCallbacks
368+
def setUp(self):
369+
bindir = os.path.join(os.path.dirname(__file__), '../..')
370+
yield call_and_check_rc(os.path.join(bindir, 'wfb_keygen'), 'secret password')
371+
372+
373+
def test_keys(self):
374+
keys = [open(k, 'rb').read() for k in ('gs.key', 'drone.key')]
375+
self.assertEqual(len(keys), 2)
376+
self.assertEqual(keys[0], keys[1])
377+
self.assertEqual(hashlib.sha1(keys[0]).hexdigest(), '07d6f6998486d99db626b755e026f80ef17f6e77')

0 commit comments

Comments
 (0)