From c6e890eb813ec49433d812ab69ebd783afaaf662 Mon Sep 17 00:00:00 2001 From: Chris Howe Date: Thu, 27 Jun 2019 11:46:16 -0500 Subject: [PATCH] added support for per-share password protection --- slip39.h | 2 ++ slip39_mnemonics.c | 10 ++++++ test_generate_combine.c | 69 ++++++++++++++++++++++++++++++++++++++--- vectors_to_tests.js | 2 +- 4 files changed, 78 insertions(+), 5 deletions(-) diff --git a/slip39.h b/slip39.h index c31b9de..767affc 100644 --- a/slip39.h +++ b/slip39.h @@ -54,6 +54,7 @@ typedef struct group_descriptor_struct { uint8_t threshold; uint8_t count; + const char **passwords; } group_descriptor; typedef struct slip39_share_struct { @@ -249,6 +250,7 @@ int combine_mnemonics( uint32_t mnemonics_words, // number of words in each share uint32_t mnemonics_shares, // total number of shares const char *passphrase, // passphrase to unlock master secret + const char **passwords, // passwords protecting shares uint8_t *buffer, // working space, and place to return secret uint32_t buffer_length // total amount of working space ); diff --git a/slip39_mnemonics.c b/slip39_mnemonics.c index 067a94d..02e6330 100644 --- a/slip39_mnemonics.c +++ b/slip39_mnemonics.c @@ -199,6 +199,10 @@ int generate_mnemonics( share.member_index = j; share.value = value; + if(groups[i].passwords && groups[i].passwords[j]) { + encrypt_share(&share, groups[i].passwords[j]); + } + unsigned int words = encode_mnemonic(&share, mnemonic, remaining_buffer); if(word_count == 0) { @@ -211,6 +215,7 @@ int generate_mnemonics( remaining_buffer -= word_count; share_count++; mnemonic += word_count; + } } @@ -239,6 +244,7 @@ int combine_mnemonics( uint32_t mnemonics_words, // number of words in each share uint32_t mnemonics_shares, // total number of shares const char *passphrase, // passphrase to unlock master secret + const char **passwords, // passwords for the shares uint8_t *buffer, // working space, and place to return secret uint32_t buffer_length // total amount of working space ) { @@ -272,6 +278,10 @@ int combine_mnemonics( return bytes; } + if(passwords && passwords[i]) { + decrypt_share(&share, passwords[i]); + } + // advance pointers into free buffer buffer_remaining -= bytes; secret_length = bytes; diff --git a/test_generate_combine.c b/test_generate_combine.c index b733d9e..1e1c1b7 100644 --- a/test_generate_combine.c +++ b/test_generate_combine.c @@ -1,6 +1,7 @@ #include "slip39.h" void test_generate_combine(void); +void test_generate_combine_passwords(void); void test_generate_combine(void) { char *test = "abcdefghijklmnopqrstuvwxyz."; @@ -11,9 +12,9 @@ void test_generate_combine(void) { unsigned int words_per_share = 0; group_descriptor groups[3] = { - {2,3}, - {1,1}, - {3,5} + {2,3, NULL}, + {1,1, NULL}, + {3,5, NULL} }; int shares = generate_mnemonics(3, groups, 3, (unsigned char *)test, secret_length, @@ -42,7 +43,7 @@ void test_generate_combine(void) { mnemonics + 4*words_per_share, }; - int result = combine_mnemonics(recovery_mnemonics, words_per_share, 6, "", buffer, 1024); + int result = combine_mnemonics(recovery_mnemonics, words_per_share, 6, "", NULL, buffer, 1024); if(result < 0) { printf("Recovery failed.\n"); @@ -51,7 +52,67 @@ void test_generate_combine(void) { printf("%s\n", buffer); } + + + + +void test_generate_combine_passwords(void) { + char *test = "abcdefghijklmnopqrstuvwxyz."; + unsigned int secret_length = strlen(test)+1; + + uint16_t mnemonics[1024]; + unsigned char buffer[1024]; + unsigned int words_per_share = 0; + + const char*p1[] = {"a",NULL,"c"}; + const char*p3[] = {"e","f", "g", "h", "i"}; + group_descriptor groups[3] = { + {2,3, p1}, + {1,1, NULL}, + {3,5, p3} + }; + + int shares = generate_mnemonics(3, groups, 3, (unsigned char *)test, secret_length, + "", 0, + &words_per_share, mnemonics, 1024); + + if(shares < 0) { + printf("An error occurred during generation.\n"); + exit(-1); + } + + for(int i=0; i < shares; ++i) { + print_mnemonic(mnemonics + i*words_per_share, words_per_share); + printf("\n"); + } + + + const uint16_t* recovery_mnemonics[] = { + // two from the first group + mnemonics, mnemonics + words_per_share, + // one from the second + mnemonics + 3*words_per_share, + // three from the third + mnemonics + 6*words_per_share, + mnemonics + 5*words_per_share, + mnemonics + 4*words_per_share, + }; + + const char* passwords[] = {"a", NULL, NULL, "g" ,"f", "e"}; + + int result = combine_mnemonics(recovery_mnemonics, words_per_share, 6, "", passwords, buffer, 1024); + + if(result < 0) { + printf("Recovery failed.\n"); + exit(-1); + } + printf("%s\n", buffer); +} + + + int main(void) { test_generate_combine(); + test_generate_combine_passwords(); return 0; } \ No newline at end of file diff --git a/vectors_to_tests.js b/vectors_to_tests.js index 2029d41..1d97a02 100644 --- a/vectors_to_tests.js +++ b/vectors_to_tests.js @@ -25,7 +25,7 @@ function generate_test(number, name, shares, result) { //if( strlen(expected_result) > 0 ) { printf("%s - ", name); - int length = combine_mnemonics(recovery, n, ${shares.length}, "TREZOR", buffer, 32); + int length = combine_mnemonics(recovery, n, ${shares.length}, "TREZOR", NULL, buffer, 32); if(length > 0) { bufToHex(buffer, length, result, 256);