├── randombytes.c ├── randombytes.h ├── .gitmodules ├── memzero.h ├── .editorconfig ├── .github └── workflows │ └── ccpp.yml ├── test_random.c ├── .gitignore ├── .travis.yml ├── test_hazmat.c ├── test_sss.c ├── LICENSE ├── test_slip39_shamir.c ├── test_slip39_wordlist.c ├── memzero.c ├── test_slip39_encrypt.c ├── slip39_buffer.c ├── sss.h ├── vectors_to_tests.js ├── slip39_rs1024.c ├── hmac.h ├── test_gf256.c ├── options.h ├── pbkdf2.h ├── test_generate_combine.c ├── slip39_encrypt.c ├── test_slip39_buffer.c ├── slip39_shamir.c ├── Makefile ├── sss.c ├── hazmat.h ├── slip39_cli.c ├── sha2.h ├── test_interpolate.c ├── slip39_wordlist.c ├── hmac.c ├── README_slip39.md ├── pbkdf2.c ├── README.md ├── slip39_wordlist_english.h ├── hazmat.c ├── vectors.json ├── slip39_mnemonics.c ├── slip39.h └── tweetnacl.c /randombytes.c: -------------------------------------------------------------------------------- 1 | randombytes/randombytes.c -------------------------------------------------------------------------------- /randombytes.h: -------------------------------------------------------------------------------- 1 | randombytes/randombytes.h -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "randombytes"] 2 | path = randombytes 3 | url = https://github.com/dsprenkels/randombytes.git 4 | -------------------------------------------------------------------------------- /memzero.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMZERO_H__ 2 | #define __MEMZERO_H__ 3 | 4 | #include 5 | 6 | void memzero(void* const pnt, const size_t len); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{c,h}] 2 | indent_style = tab 3 | indent_size = 8 4 | 5 | [Makefile] 6 | indent_style = tab 7 | indent_size = 8 8 | 9 | [*.yml] 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /.github/workflows/ccpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | with: 13 | submodules: recursive 14 | - name: make check 15 | run: make check 16 | 17 | -------------------------------------------------------------------------------- /test_random.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | 3 | // Clearly not so random. Dont use outside of tests. 4 | static uint8_t b = 0; 5 | int randombytes(void *bufv, size_t len) { 6 | uint8_t *buf = (uint8_t *) bufv; 7 | for(uint32_t i=0;i 3 | #include 4 | 5 | 6 | static void test_key_shares(void) 7 | { 8 | uint8_t key[32], restored[32]; 9 | sss_Keyshare key_shares[256]; 10 | size_t idx; 11 | 12 | for (idx = 0; idx < 32; idx++) { 13 | key[idx] = idx; 14 | } 15 | 16 | sss_create_keyshares(key_shares, key, 1, 1); 17 | sss_combine_keyshares(restored, (const sss_Keyshare*) key_shares, 1); 18 | assert(memcmp(key, restored, 32) == 0); 19 | 20 | sss_create_keyshares(key_shares, key, 3, 2); 21 | sss_combine_keyshares(restored, (const sss_Keyshare*) key_shares[1], 2); 22 | assert(memcmp(key, restored, 32) == 0); 23 | 24 | sss_create_keyshares(key_shares, key, 255, 127); 25 | sss_combine_keyshares(restored, (const sss_Keyshare*) key_shares[128], 127); 26 | assert(memcmp(key, restored, 32) == 0); 27 | 28 | sss_create_keyshares(key_shares, key, 255, 255); 29 | sss_combine_keyshares(restored, (const sss_Keyshare*) key_shares, 255); 30 | assert(memcmp(key, restored, 32) == 0); 31 | } 32 | 33 | 34 | int main(void) 35 | { 36 | test_key_shares(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /test_sss.c: -------------------------------------------------------------------------------- 1 | #include "sss.h" 2 | #include 3 | #include 4 | 5 | int main(void) 6 | { 7 | unsigned char data[sss_MLEN] = { 42 }, restored[sss_MLEN]; 8 | sss_Share shares[256]; 9 | int tmp; 10 | 11 | /* Normal operation */ 12 | sss_create_shares(shares, data, 1, 1); 13 | tmp = sss_combine_shares(restored, (const sss_Share*) shares, 1); 14 | assert(tmp == 0); 15 | assert(memcmp(restored, data, sss_MLEN) == 0); 16 | 17 | /* A lot of shares */ 18 | sss_create_shares(shares, data, 255, 255); 19 | tmp = sss_combine_shares(restored, (const sss_Share*) shares, 255); 20 | assert(tmp == 0); 21 | assert(memcmp(restored, data, sss_MLEN) == 0); 22 | 23 | /* Not enough shares to restore secret */ 24 | sss_create_shares(shares, data, 100, 100); 25 | tmp = sss_combine_shares(restored, (const sss_Share*) shares, 99); 26 | assert(tmp == -1); 27 | 28 | /* Too many secrets should also restore the secret */ 29 | sss_create_shares(shares, data, 200, 100); 30 | tmp = sss_combine_shares(restored, (const sss_Share*) shares, 200); 31 | assert(tmp == 0); 32 | assert(memcmp(restored, data, sss_MLEN) == 0); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2017 Daan Sprenkels 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /test_slip39_shamir.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | uint8_t test_split_recover(void); 3 | 4 | uint8_t test_split_recover(void) { 5 | uint8_t fail = 0; 6 | // secret can only be 32 bytes long... 7 | char *test = "The quick brown fox jumped ove"; //r the lazy dog."; 8 | 9 | uint8_t shares[512]; 10 | uint8_t secret[50]; 11 | 12 | uint32_t secret_length = strlen(test)+1; 13 | 14 | int8_t share_count = split_secret(3, 10, (uint8_t *)test, secret_length, shares); 15 | 16 | if(share_count != 10) { 17 | printf("expected share_count to be 10\n"); 18 | fail = 1; 19 | } 20 | 21 | uint8_t *sh[10]; 22 | for(uint8_t i=0;i<10;++i) { 23 | sh[i] = shares + i*secret_length; 24 | } 25 | 26 | for(uint8_t i=0;i<8;++i) { 27 | for(uint8_t j=i+1;j<9;++j) { 28 | for(uint8_t k=j+1; k<10;++k) { 29 | uint8_t x[] = {j, i, k}; 30 | const uint8_t *y[] = {sh[j], sh[i], sh[k]}; 31 | 32 | int recovery = recover_secret(3, x, y, secret_length, secret); 33 | 34 | if(recovery < 0 || strcmp((char *)test, (char *)secret) != 0) { 35 | printf("secret recovery failed\n"); 36 | fail = 1; 37 | } 38 | } 39 | } 40 | } 41 | 42 | return fail; 43 | } 44 | 45 | int main(void) { 46 | uint8_t fail = 0; 47 | uint8_t t; 48 | 49 | t = test_split_recover(); 50 | fail = fail || t; 51 | printf("test split and recover: %s\n", t ? "fail" : "pass" ); 52 | 53 | return fail; 54 | } -------------------------------------------------------------------------------- /test_slip39_wordlist.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | 3 | uint8_t test_toWords_fromWords(void); 4 | uint8_t test_lookups(void); 5 | 6 | #include "slip39_wordlist_english.h" 7 | 8 | uint8_t test_lookups(void) { 9 | uint8_t fail = 0; 10 | 11 | for(uint16_t i=0; i<1024; ++i) { 12 | int16_t j = lookup(wordlist[i]); 13 | if(i != j) { 14 | fail = 1; 15 | } 16 | } 17 | 18 | if(lookup("foobar") != -1) { 19 | fail = 1; 20 | } 21 | 22 | if(lookup("aaa") != -1) { 23 | fail = 1; 24 | } 25 | 26 | if(lookup("zzz") != -1) { 27 | fail = 1; 28 | } 29 | 30 | if(lookup("") != -1) { 31 | fail = 1; 32 | } 33 | 34 | return fail; 35 | } 36 | 37 | uint8_t test_toWords_fromWords(void) { 38 | uint8_t fail = 0; 39 | char *x = " abcdefghijklmnopqrstuvwxyz"; 40 | uint16_t words[25]; 41 | uint8_t results[30]; 42 | 43 | int32_t w; 44 | 45 | for(uint8_t i=0; i<26; i+=2) { 46 | w = to_words((uint8_t *)x+i , strlen(x+i)+1, words, 25); 47 | from_words(words, w, results, 30); 48 | 49 | if(strcmp((char *)results,x+i) !=0) { 50 | printf("Fail: '%s' != '%s'\n", x+i, results); 51 | //return; 52 | for(unsigned char j=0;j 7 | 8 | #ifdef _WIN32 9 | #include 10 | #endif 11 | 12 | #ifdef __unix__ 13 | #include 14 | #include 15 | #endif 16 | 17 | // C11's bounds-checking interface. 18 | #if defined(__STDC_LIB_EXT1__) 19 | #define HAVE_MEMSET_S 1 20 | #endif 21 | 22 | // GNU C Library version 2.25 or later. 23 | #if defined(__GLIBC__) && \ 24 | (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) 25 | #define HAVE_EXPLICIT_BZERO 1 26 | #endif 27 | 28 | // Newlib 29 | #if defined(__NEWLIB__) 30 | #define HAVE_EXPLICIT_BZERO 1 31 | #endif 32 | 33 | // FreeBSD version 11.0 or later. 34 | #if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 35 | #define HAVE_EXPLICIT_BZERO 1 36 | #endif 37 | 38 | // OpenBSD version 5.5 or later. 39 | #if defined(__OpenBSD__) && OpenBSD >= 201405 40 | #define HAVE_EXPLICIT_BZERO 1 41 | #endif 42 | 43 | // NetBSD version 7.2 or later. 44 | #if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 45 | #define HAVE_EXPLICIT_MEMSET 1 46 | #endif 47 | 48 | // Adapted from 49 | // https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 50 | 51 | void memzero(void *const pnt, const size_t len) { 52 | #ifdef _WIN32 53 | SecureZeroMemory(pnt, len); 54 | #elif defined(HAVE_MEMSET_S) 55 | memset_s(pnt, (rsize_t)len, 0, (rsize_t)len); 56 | #elif defined(HAVE_EXPLICIT_BZERO) 57 | bzero(pnt, len); 58 | #elif defined(HAVE_EXPLICIT_MEMSET) 59 | explicit_memset(pnt, 0, len); 60 | #else 61 | volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt; 62 | size_t i = (size_t)0U; 63 | 64 | while (i < len) { 65 | pnt_[i++] = 0U; 66 | } 67 | #endif 68 | } 69 | -------------------------------------------------------------------------------- /test_slip39_encrypt.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | 3 | uint8_t test_round_function(void); 4 | uint8_t test_encrypt_function(void); 5 | 6 | 7 | uint8_t test_round_function(void) { 8 | uint8_t fail = 0; 9 | 10 | // data from this test was taken from running the round function 11 | // on pass one of encrypting the string "abcd" with the empty 12 | // password, and a group identifier of 1234 13 | uint8_t salt[] = { 's', 'h', 'a', 'm', 'i', 'r', 4, 210 }; 14 | uint8_t r[] = { 'c', 'd' }; 15 | uint8_t d[2]; 16 | 17 | round_function(0,"",0,salt,8,r,2,d,2); 18 | 19 | if(!(d[0] == 183 && d[1] == 32)) { 20 | fail = 1; 21 | } 22 | 23 | round_function(0,"TREZOR",0,salt,8,r,2,d,2); 24 | if(!(d[0] == 156 && d[1] == 169)) { 25 | fail = 1; 26 | } 27 | 28 | return fail; 29 | } 30 | 31 | uint8_t test_encrypt_function(void) { 32 | uint8_t fail = 0; 33 | 34 | // Data for this test was generated by running the equivalent 35 | // _encrypt() function in the python reference code 36 | char *input = "abcd"; 37 | uint8_t output[4]; 38 | 39 | slip39_encrypt((uint8_t *)input, 4, "", 0, 1234, output); 40 | 41 | if(!(output[0] == 167 && output[1] == 251 && output[2]==61 && output[3] == 147)) { 42 | fail = 1; 43 | } 44 | 45 | 46 | slip39_encrypt((uint8_t *)input, 4, "TREZOR", 0, 1234, output); 47 | if( !(output[0] == 41 && output[1] == 155 && output[2]==1 && output[3] == 50) ) { 48 | fail = 1; 49 | } 50 | 51 | return fail; 52 | } 53 | 54 | int main(void) { 55 | uint8_t fail = 0; 56 | uint8_t t; 57 | 58 | t=test_round_function(); 59 | fail = fail || t; 60 | printf("test round function: %s\n", t ? "fail" : "pass"); 61 | 62 | t=test_encrypt_function(); 63 | fail = fail || t; 64 | printf("test encrypt function: %s\n", t ? "fail" : "pass"); 65 | 66 | return fail; 67 | } 68 | -------------------------------------------------------------------------------- /slip39_buffer.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | 3 | int decode_binary_shard( 4 | slip39_shard *shard, 5 | const uint8_t *buffer, 6 | uint32_t buffer_length 7 | ) { 8 | if(buffer_length < 12 || buffer[0] != 0x48 || buffer[1] != 0xbd || buffer[2] != 0xfd) { 9 | return ERROR_INVALID_SHARD_BUFFER; 10 | } 11 | 12 | shard->identifier = (buffer[3] << 8) | buffer[4]; 13 | shard->iteration_exponent = buffer[5]; 14 | shard->group_index = buffer[6]; 15 | shard->group_threshold = buffer[7]; 16 | shard->group_count = buffer[8]; 17 | shard->member_index = buffer[9]; 18 | shard->member_threshold = buffer[10]; 19 | shard->value_length= buffer[11]; 20 | 21 | if(shard->value_length < 16) { 22 | return ERROR_SECRET_TOO_SHORT; 23 | } 24 | 25 | if(shard->value_length > 32) { 26 | return ERROR_SECRET_TOO_LONG; 27 | } 28 | 29 | if(buffer_length < (uint32_t) shard->value_length + 12) { 30 | return ERROR_INVALID_SHARD_BUFFER; 31 | } 32 | 33 | memset(shard->value, 0, 32); 34 | memcpy(shard->value, buffer+12, shard->value_length); 35 | 36 | return shard->value_length + 12; 37 | } 38 | 39 | int encode_binary_shard( 40 | uint8_t *buffer, 41 | uint32_t buffer_length, 42 | const slip39_shard *shard 43 | ) { 44 | if(buffer_length < (uint32_t) shard->value_length + 12) { 45 | return ERROR_INVALID_SHARD_BUFFER; 46 | } 47 | 48 | buffer[0] = 0x48; 49 | buffer[1] = 0xbd; 50 | buffer[2] = 0xfd; 51 | buffer[3] = (uint8_t) (shard->identifier >> 8); 52 | buffer[4] = (uint8_t) (shard->identifier & 0xff); 53 | buffer[5] = shard->iteration_exponent; 54 | buffer[6] = shard->group_index; 55 | buffer[7] = shard->group_threshold; 56 | buffer[8] = shard->group_count; 57 | buffer[9] = shard->member_index; 58 | buffer[10] = shard->member_threshold; 59 | buffer[11] = shard->value_length; 60 | 61 | memcpy(buffer+12, shard->value, shard->value_length); 62 | 63 | return shard->value_length + 12; 64 | } 65 | -------------------------------------------------------------------------------- /sss.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Intermediate level API for Daan Sprenkels' Shamir secret sharing library 3 | * Copyright (c) 2017 Daan Sprenkels 4 | */ 5 | 6 | 7 | #ifndef sss_SSS_H_ 8 | #define sss_SSS_H_ 9 | 10 | #include "hazmat.h" 11 | #include "tweetnacl.h" 12 | #include 13 | 14 | 15 | #ifndef sss_MLEN 16 | /* 17 | Length of the message (must be known at compile-time) 18 | */ 19 | #define sss_MLEN sizeof(uint8_t[64]) 20 | #endif 21 | 22 | 23 | /* 24 | * Length of the ciphertext, including the message authentication code 25 | */ 26 | #define sss_CLEN (sss_MLEN + 16) 27 | 28 | 29 | /* 30 | * Length of a SSS share 31 | */ 32 | #define sss_SHARE_LEN (sss_CLEN + sss_KEYSHARE_LEN) 33 | 34 | 35 | /* 36 | * One share of a secret which is shared using Shamir's 37 | * the `sss_create_shares` function. 38 | */ 39 | typedef uint8_t sss_Share[sss_SHARE_LEN]; 40 | 41 | 42 | /* 43 | * Create `n` shares of the secret data `data`. Share such that `k` or more 44 | * shares will be able to restore the secret. 45 | * 46 | * This function will put the resulting shares in the array pointed to by 47 | * `out`. The caller has to guarantee that this array will fit at least `n` 48 | * instances of `sss_Share`. 49 | */ 50 | void sss_create_shares(sss_Share *out, 51 | const uint8_t *data, 52 | uint8_t n, 53 | uint8_t k); 54 | 55 | 56 | /* 57 | * Combine the `k` shares pointed to by `shares` and put the resulting secret 58 | * data in `data`. The caller has to ensure that the `data` array will fit 59 | * at least `sss_MLEN` (default: 64) bytes. 60 | * 61 | * On success, this function will return 0. If combining the secret fails, 62 | * this function will return a nonzero return code. On failure, the value 63 | * in `data` may have been altered, but must still be considered secret. 64 | */ 65 | int sss_combine_shares(uint8_t *data, 66 | const sss_Share *shares, 67 | uint8_t k); 68 | 69 | 70 | #endif /* sss_SSS_H_ */ 71 | -------------------------------------------------------------------------------- /vectors_to_tests.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function generate_test(number, name, shares, result) { 4 | share_code = shares.map(x=>` 5 | "${x}",`).join(''); 6 | 7 | parse_code = shares.map((x,i)=> ` 8 | unsigned short words_${i}[${x.split(' ').length}]; 9 | n = parse_words(shares[${i}], words_${i}, ${x.split(' ').length});`).join('') 10 | 11 | recovery_values = shares.map((x,i) => `words_${i}`).join(', '); 12 | return ` 13 | void test_vector_${number}(void); 14 | void test_vector_${number}(void) { 15 | char *name = "${name}"; 16 | unsigned int n; 17 | char *shares[] = {${share_code} 18 | }; 19 | char *expected_result = "${result}"; 20 | ${parse_code} 21 | const unsigned short *recovery[] = { ${recovery_values} }; 22 | unsigned char buffer[32]; 23 | char result[256]; 24 | 25 | //if( strlen(expected_result) > 0 ) { 26 | 27 | printf("%s - ", name); 28 | int length = combine_mnemonics(recovery, n, ${shares.length}, "TREZOR", NULL, buffer, 32); 29 | 30 | if(length > 0) { 31 | bufToHex(buffer, length, result, 256); 32 | } else { 33 | result[0] = 0; 34 | } 35 | 36 | if(strcmp(result,expected_result) != 0) { 37 | printf("fail\\nexpected: '%s'\\ngot: '%s'\\n\\n", expected_result, result); 38 | } else { 39 | printf("pass\\n"); 40 | } 41 | //} 42 | } 43 | ` 44 | } 45 | 46 | vectors = require('./vectors.json') 47 | 48 | 49 | console.log('#include "slip39.h"') 50 | 51 | console.log(` 52 | void bufToHex(unsigned char *buf, unsigned int length, char *output, int out_length); 53 | void bufToHex(unsigned char *buf, unsigned int length, char *output, int out_length) { 54 | for(unsigned int i=0; i `test_vector_${i}();`).join(' \n'); 65 | console.log(` 66 | int main(void) { 67 | ${call_tests} 68 | return 0; 69 | } 70 | `) 71 | -------------------------------------------------------------------------------- /slip39_rs1024.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | 3 | ////////////////////////////////////////////////// 4 | // rs1024 checksum functions 5 | 6 | static const uint32_t generator[] = { 7 | 0x00E0E040, 8 | 0x01C1C080, 9 | 0x03838100, 10 | 0x07070200, 11 | 0x0E0E0009, 12 | 0x1C0C2412, 13 | 0x38086C24, 14 | 0x3090FC48, 15 | 0x21B1F890, 16 | 0x03F3F120, 17 | }; 18 | 19 | static const uint8_t customization[] = { 20 | 's', 'h', 'a', 'm', 'i', 'r', 21 | }; 22 | 23 | 24 | // We need 30 bits of checksum to get 3 words worth (CHECKSUM_LENGTH_WORDS) 25 | uint32_t rs1024_polymod( 26 | const uint16_t *values, // values - 10 bit words 27 | uint32_t values_length // number of entries in the values array 28 | ) { 29 | // there are a bunch of hard coded magic numbers in this 30 | // that would have to be changed if the value of CHECKSUM_LENGTH_WORDS 31 | // were to change. 32 | 33 | // unsigned ints are assumed to be 32 bits, which is enough to hold 34 | // CHECKSUM_LENGTH_WORDS * RADIX_BITS 35 | uint32_t chk = 1; 36 | 37 | // initialize with the customization string 38 | for(uint32_t i=0; i<6; ++i) { 39 | // 20 = (CHESUM_LENGTH_WORDS - 1) * RADIX_BITS 40 | uint32_t b = chk >> 20; 41 | // 0xFFFFF = (1 << ((CHECKSUM_LENGTH_WORDS-1)*RADIX_BITS)) - 1 42 | // 10 = RADIX_BITS 43 | chk = ((chk & 0xFFFFF) << 10 ) ^ customization[i]; 44 | for(unsigned int j=0; j<10; ++j, b>>=1) { 45 | chk ^= generator[j] * (b&1); 46 | } 47 | } 48 | 49 | // continue with the values 50 | for(uint32_t i=0; i> 20; 52 | chk = ((chk & 0xFFFFF) << 10 ) ^ values[i]; 53 | for(unsigned int j=0; j<10; ++j, b>>=1) { 54 | chk ^= generator[j] * (b&1); 55 | } 56 | } 57 | 58 | return chk; 59 | } 60 | 61 | 62 | void rs1024_create_checksum( 63 | uint16_t *values, // data words (10 bit) 64 | uint32_t n // length of the data array, including three checksum word 65 | ) { 66 | // Set the last three words to zero 67 | values[n-3] = 0; 68 | values[n-2] = 0; 69 | values[n-1] = 0; 70 | 71 | // compute the checkum 72 | uint32_t polymod = rs1024_polymod(values, n) ^ 1; 73 | 74 | // fix up the last three words to make the checksum come out to the right number 75 | values[n-3] = (polymod >> 20) & 1023; 76 | values[n-2] = (polymod >> 10) & 1023; 77 | values[n-1] = (polymod) & 1023; 78 | } 79 | 80 | 81 | uint8_t rs1024_verify_checksum( 82 | const uint16_t *values, // data words 83 | uint32_t n // length of the data array 84 | ) { 85 | return rs1024_polymod(values, n) == 1; 86 | } 87 | -------------------------------------------------------------------------------- /hmac.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef __HMAC_H__ 25 | #define __HMAC_H__ 26 | 27 | #include 28 | #include "sha2.h" 29 | 30 | typedef struct _HMAC_SHA256_CTX { 31 | uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; 32 | SHA256_CTX ctx; 33 | } HMAC_SHA256_CTX; 34 | 35 | typedef struct _HMAC_SHA512_CTX { 36 | uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; 37 | SHA512_CTX ctx; 38 | } HMAC_SHA512_CTX; 39 | 40 | void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, 41 | const uint32_t keylen); 42 | void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, 43 | const uint32_t msglen); 44 | void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac); 45 | void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, 46 | const uint32_t msglen, uint8_t *hmac); 47 | void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, 48 | uint32_t *opad_digest, uint32_t *ipad_digest); 49 | 50 | void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, 51 | const uint32_t keylen); 52 | void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, 53 | const uint32_t msglen); 54 | void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac); 55 | void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, 56 | const uint32_t msglen, uint8_t *hmac); 57 | void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, 58 | uint64_t *opad_digest, uint64_t *ipad_digest); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /test_gf256.c: -------------------------------------------------------------------------------- 1 | 2 | #include "gf256.h" 3 | #include 4 | 5 | #define ASSERT(x, args...) if(!(x)) {printf(args); fail=1;} 6 | 7 | uint8_t test_exp_log_inverses(void); 8 | uint8_t test_additive_inverses(void); 9 | uint8_t test_additive_identity(void); 10 | uint8_t test_multiplicitive_inverses(void); 11 | uint8_t test_multiplicitive_identity(void); 12 | 13 | uint8_t test_exp_log_inverses(void) { 14 | uint8_t fail = 0; 15 | 16 | for(uint16_t i=1; i<256; i++) { 17 | uint8_t a = i; 18 | ASSERT(gf256_exp(gf256_log(a)) == a, "Exp as inverse of log failed for %d.", a) 19 | } 20 | 21 | printf("Exp/Log Inverse: %s\n", fail ? "fail" : "pass"); 22 | return fail; 23 | } 24 | 25 | uint8_t test_additive_inverses(void) { 26 | uint8_t fail = 0; 27 | 28 | for(uint16_t i=0; i<256; i++) { 29 | uint8_t a = i; 30 | ASSERT(gf256_add(a,a)==0, "Additive inverse property failed for %d.\n", a) 31 | } 32 | 33 | printf("Additive Inverse: %s\n", fail ? "fail" : "pass"); 34 | return fail; 35 | } 36 | 37 | uint8_t test_additive_identity(void) { 38 | uint8_t fail = 0; 39 | 40 | for(uint16_t i=0; i<256; i++) { 41 | uint8_t a = i; 42 | ASSERT(gf256_add(a,0)==a, "Additive identity property failed for %d.\n", a) 43 | ASSERT(gf256_add(0,a)==a, "Additive identity property failed for %d.\n", a) 44 | } 45 | 46 | printf("Additive Identity: %s\n", fail ? "fail" : "pass"); 47 | return fail; 48 | } 49 | 50 | uint8_t test_multiplicitive_inverses(void) { 51 | uint8_t fail = 0; 52 | 53 | for(uint16_t i=1; i<256; i++) { 54 | uint8_t a = i; 55 | uint8_t b = gf256_div(1,a); 56 | 57 | ASSERT(gf256_div(a,a)==1, "Multiplicitive inverse property failed for %d.", a) 58 | ASSERT(gf256_mult(a,b)==1, "Multiplicitive inverse property failed for %d.", a) 59 | ASSERT(gf256_mult(b,a)==1, "Multiplicitive inverse property failed for %d.", a) 60 | } 61 | 62 | printf("Multiplicitive Inverse: %s\n", fail ? "fail" : "pass"); 63 | return fail; 64 | } 65 | 66 | uint8_t test_multiplicitive_identity(void) { 67 | uint8_t fail = 0; 68 | 69 | for(uint16_t i=1; i<256; i++) { 70 | uint8_t a = i; 71 | ASSERT(gf256_mult(a,1)==a, "Multiplicitive identity property failed for %d.", a) 72 | ASSERT(gf256_mult(1,a)==a, "Multiplicitive identity property failed for %d.", a) 73 | ASSERT(gf256_div(a,1)==a, "Multiplicitive identity property failed for %d.", a) 74 | } 75 | 76 | printf("Multiplicitive Identity: %s\n", fail ? "fail" : "pass"); 77 | return fail; 78 | } 79 | 80 | int main(void) { 81 | uint8_t fail = 0; 82 | 83 | fail = test_exp_log_inverses() || fail; 84 | fail = test_additive_inverses() || fail; 85 | fail = test_additive_identity() || fail; 86 | fail = test_multiplicitive_inverses() || fail; 87 | fail = test_multiplicitive_identity() || fail; 88 | 89 | return fail; 90 | } -------------------------------------------------------------------------------- /options.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Pavol Rusnak 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included 12 | * in all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 18 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | * OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef __OPTIONS_H__ 24 | #define __OPTIONS_H__ 25 | 26 | // use precomputed Curve Points (some scalar multiples of curve base point G) 27 | #ifndef USE_PRECOMPUTED_CP 28 | #define USE_PRECOMPUTED_CP 1 29 | #endif 30 | 31 | // use fast inverse method 32 | #ifndef USE_INVERSE_FAST 33 | #define USE_INVERSE_FAST 1 34 | #endif 35 | 36 | // support for printing bignum256 structures via printf 37 | #ifndef USE_BN_PRINT 38 | #define USE_BN_PRINT 0 39 | #endif 40 | 41 | // use deterministic signatures 42 | #ifndef USE_RFC6979 43 | #define USE_RFC6979 1 44 | #endif 45 | 46 | // implement BIP32 caching 47 | #ifndef USE_BIP32_CACHE 48 | #define USE_BIP32_CACHE 1 49 | #define BIP32_CACHE_SIZE 10 50 | #define BIP32_CACHE_MAXDEPTH 8 51 | #endif 52 | 53 | // support constructing BIP32 nodes from ed25519 and curve25519 curves. 54 | #ifndef USE_BIP32_25519_CURVES 55 | #define USE_BIP32_25519_CURVES 1 56 | #endif 57 | 58 | // implement BIP39 caching 59 | #ifndef USE_BIP39_CACHE 60 | #define USE_BIP39_CACHE 1 61 | #define BIP39_CACHE_SIZE 4 62 | #endif 63 | 64 | // support Ethereum operations 65 | #ifndef USE_ETHEREUM 66 | #define USE_ETHEREUM 0 67 | #endif 68 | 69 | // support Graphene operations (STEEM, BitShares) 70 | #ifndef USE_GRAPHENE 71 | #define USE_GRAPHENE 0 72 | #endif 73 | 74 | // support NEM operations 75 | #ifndef USE_NEM 76 | #define USE_NEM 0 77 | #endif 78 | 79 | // support MONERO operations 80 | #ifndef USE_MONERO 81 | #define USE_MONERO 0 82 | #endif 83 | 84 | // support CARDANO operations 85 | #ifndef USE_CARDANO 86 | #define USE_CARDANO 0 87 | #endif 88 | 89 | // support Keccak hashing 90 | #ifndef USE_KECCAK 91 | #define USE_KECCAK 1 92 | #endif 93 | 94 | // add way how to mark confidential data 95 | #ifndef CONFIDENTIAL 96 | #define CONFIDENTIAL 97 | #endif 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /pbkdf2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef __PBKDF2_H__ 25 | #define __PBKDF2_H__ 26 | 27 | #include 28 | #include "sha2.h" 29 | 30 | typedef struct _PBKDF2_HMAC_SHA256_CTX { 31 | uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; 32 | uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; 33 | uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; 34 | uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; 35 | char first; 36 | } PBKDF2_HMAC_SHA256_CTX; 37 | 38 | typedef struct _PBKDF2_HMAC_SHA512_CTX { 39 | uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; 40 | uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; 41 | uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; 42 | uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; 43 | char first; 44 | } PBKDF2_HMAC_SHA512_CTX; 45 | 46 | void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, 47 | int passlen, const uint8_t *salt, int saltlen, 48 | uint32_t blocknr); 49 | void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, 50 | uint32_t iterations); 51 | void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key); 52 | void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, 53 | int saltlen, uint32_t iterations, uint8_t *key, 54 | int keylen); 55 | 56 | void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, 57 | int passlen, const uint8_t *salt, int saltlen, 58 | uint32_t blocknr); 59 | void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, 60 | uint32_t iterations); 61 | void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key); 62 | void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, 63 | int saltlen, uint32_t iterations, uint8_t *key, 64 | int keylen); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /test_generate_combine.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | 3 | void test_generate_combine(void); 4 | void test_generate_combine_passwords(void); 5 | 6 | void test_generate_combine(void) { 7 | char *test = "abcdefghijklmnopqrstuvwxyz."; 8 | unsigned int secret_length = strlen(test)+1; 9 | 10 | uint16_t mnemonics[1024]; 11 | unsigned char buffer[1024]; 12 | unsigned int words_per_share = 0; 13 | 14 | group_descriptor groups[3] = { 15 | {2,3, NULL}, 16 | {1,1, NULL}, 17 | {3,5, NULL} 18 | }; 19 | 20 | int shares = generate_mnemonics(3, groups, 3, (unsigned char *)test, secret_length, 21 | "", 0, 22 | &words_per_share, mnemonics, 1024); 23 | 24 | if(shares < 0) { 25 | printf("An error occurred during generation.\n"); 26 | exit(-1); 27 | } 28 | 29 | for(int i=0; i < shares; ++i) { 30 | print_mnemonic(mnemonics + i*words_per_share, words_per_share); 31 | printf("\n"); 32 | } 33 | 34 | 35 | const uint16_t* recovery_mnemonics[] = { 36 | // two from the first group 37 | mnemonics, mnemonics + words_per_share, 38 | // one from the second 39 | mnemonics + 3*words_per_share, 40 | // three from the third 41 | mnemonics + 6*words_per_share, 42 | mnemonics + 5*words_per_share, 43 | mnemonics + 4*words_per_share, 44 | }; 45 | 46 | int result = combine_mnemonics(recovery_mnemonics, words_per_share, 6, "", NULL, buffer, 1024); 47 | 48 | if(result < 0) { 49 | 50 | printf("Recovery failed. %d\n", result); 51 | exit(-1); 52 | } 53 | printf("%s\n", buffer); 54 | } 55 | 56 | 57 | 58 | 59 | 60 | void test_generate_combine_passwords(void) { 61 | char *test = "abcdefghijklmnopqrstuvwxyz."; 62 | unsigned int secret_length = strlen(test)+1; 63 | 64 | uint16_t mnemonics[1024]; 65 | unsigned char buffer[1024]; 66 | unsigned int words_per_share = 0; 67 | 68 | const char*p1[] = {"a",NULL,"c"}; 69 | const char*p3[] = {"e","f", "g", "h", "i"}; 70 | group_descriptor groups[3] = { 71 | {2,3, p1}, 72 | {1,1, NULL}, 73 | {3,5, p3} 74 | }; 75 | 76 | int shares = generate_mnemonics(3, groups, 3, (unsigned char *)test, secret_length, 77 | "", 0, 78 | &words_per_share, mnemonics, 1024); 79 | 80 | if(shares < 0) { 81 | printf("An error occurred during generation.\n"); 82 | exit(-1); 83 | } 84 | 85 | for(int i=0; i < shares; ++i) { 86 | print_mnemonic(mnemonics + i*words_per_share, words_per_share); 87 | printf("\n"); 88 | } 89 | 90 | 91 | const uint16_t* recovery_mnemonics[] = { 92 | // two from the first group 93 | mnemonics, mnemonics + words_per_share, 94 | // one from the second 95 | mnemonics + 3*words_per_share, 96 | // three from the third 97 | mnemonics + 6*words_per_share, 98 | mnemonics + 5*words_per_share, 99 | mnemonics + 4*words_per_share, 100 | }; 101 | 102 | const char* passwords[] = {"a", NULL, NULL, "g" ,"f", "e"}; 103 | 104 | int result = combine_mnemonics(recovery_mnemonics, words_per_share, 6, "", passwords, buffer, 1024); 105 | 106 | if(result < 0) { 107 | printf("Recovery failed.\n"); 108 | exit(-1); 109 | } 110 | printf("%s\n", buffer); 111 | } 112 | 113 | 114 | 115 | int main(void) { 116 | test_generate_combine(); 117 | test_generate_combine_passwords(); 118 | return 0; 119 | } -------------------------------------------------------------------------------- /slip39_encrypt.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | #include "pbkdf2.h" 3 | 4 | ////////////////////////////////////////////////// 5 | // encrypt/decrypt 6 | // 7 | 8 | // #include 9 | // #include 10 | // crypto.h used for the version 11 | // #include 12 | 13 | static const uint8_t customization[] = { 14 | 's', 'h', 'a', 'm', 'i', 'r', 15 | }; 16 | 17 | int32_t _get_salt( uint16_t identifier, uint8_t *result, uint32_t result_length); 18 | void feistel(uint8_t forward, const uint8_t *input, uint32_t input_length, const char *passphrase, 19 | uint8_t iteration_exponent, uint16_t identifier, uint8_t *output); 20 | 21 | int32_t _get_salt( 22 | uint16_t identifier, 23 | uint8_t *result, 24 | uint32_t result_length 25 | ) { 26 | if(result_length < 8) { 27 | return -1; 28 | } 29 | 30 | for(unsigned int i=0; i<6; ++i) { 31 | result[i] = customization[i]; 32 | } 33 | 34 | result[6] = identifier >> 8; 35 | result[7] = identifier & 0xff; 36 | return 8; 37 | } 38 | 39 | void round_function( 40 | uint8_t i, 41 | const char *passphrase, 42 | uint8_t exp, 43 | const uint8_t *salt, 44 | uint32_t salt_length, 45 | const uint8_t *r, 46 | uint32_t r_length, 47 | uint8_t *dest, 48 | uint32_t dest_length 49 | ) { 50 | uint32_t pass_length = strlen(passphrase) + 1; 51 | uint8_t pass[pass_length+2]; 52 | sprintf( (char *) (pass+1), "%s", passphrase); 53 | pass[0] = i; 54 | uint32_t iterations = BASE_ITERATION_COUNT << exp; 55 | uint8_t saltr[salt_length + r_length]; 56 | 57 | memcpy(saltr, salt, salt_length); 58 | memcpy(saltr+salt_length, r, r_length); 59 | 60 | pbkdf2_hmac_sha256(pass, pass_length, 61 | saltr, salt_length+r_length, 62 | iterations, 63 | dest, dest_length); 64 | } 65 | 66 | void feistel( 67 | uint8_t forward, 68 | const uint8_t *input, 69 | uint32_t input_length, 70 | const char *passphrase, 71 | uint8_t iteration_exponent, 72 | uint16_t identifier, 73 | uint8_t *output 74 | ) { 75 | uint32_t half_length = input_length / 2; 76 | uint8_t *l, *r, *t, f[half_length]; 77 | uint8_t salt[8]; 78 | 79 | memcpy(output, input+half_length, half_length); 80 | memcpy(output + half_length, input, half_length); 81 | 82 | r = output; 83 | l = output+half_length; 84 | 85 | _get_salt(identifier, salt, 8); 86 | 87 | for(uint8_t i=0; i 3 | 4 | slip39_shard shard1 = { 5 | 1234, // identifier 6 | 5, // iteration exponent 7 | 0, // group index 8 | 2, // group threshold 9 | 4, // group count 10 | 3, // member index 11 | 5, // member threshold 12 | 32, // value_length 13 | { // value 14 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 15 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f 16 | } 17 | }; 18 | 19 | slip39_shard shard2= { 20 | 4321, // identifier 21 | 3, // iteration exponent 22 | 1, // group index 23 | 2, // group threshold 24 | 5, // group count 25 | 6, // member index 26 | 7, // member threshold 27 | 16, // value_length 28 | { // value 29 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 31 | } 32 | }; 33 | 34 | int shards_equal(slip39_shard *a, slip39_shard *b); 35 | 36 | int shards_equal(slip39_shard *a, slip39_shard *b) { 37 | if( a->identifier != b->identifier || 38 | a->iteration_exponent != b->iteration_exponent || 39 | a->group_index != b->group_index || 40 | a->group_threshold != b->group_threshold || 41 | a->group_count != b->group_count || 42 | a->member_index != b->member_index || 43 | a->member_threshold != b->member_threshold || 44 | a->value_length != b->value_length ) { 45 | return 0; 46 | } 47 | for(int i=0; ivalue_length; ++i) { 48 | if(a->value[i] != b->value[i]) { 49 | return 0; 50 | } 51 | } 52 | 53 | return 1; 54 | } 55 | 56 | int test_encode_decode_buffer() { 57 | uint8_t buffer[50]; 58 | slip39_shard decode; 59 | int result; 60 | 61 | // test encoding and decoding a 32 byte secret shard 62 | result = encode_binary_shard(buffer, 50, &shard1); 63 | if(result != 44) { 64 | // fail 65 | printf("shard1 encoding gave unexpected length\n"); 66 | return 1; 67 | } 68 | 69 | 70 | result = decode_binary_shard(&decode, buffer, 50); 71 | if(result != 44) { 72 | printf("shard1 decoding gave unexpected length\n"); 73 | return 1; 74 | } 75 | 76 | if( !shards_equal(&shard1, &decode)) { 77 | printf("shard1 decode not equal to original\n"); 78 | return 1; 79 | } 80 | 81 | // test encoding and decoding a 16 byte secret shard 82 | result = encode_binary_shard(buffer, 50, &shard2); 83 | if(result != 28) { 84 | printf("shard2 encoding gave unexpected length\n"); 85 | return 1; 86 | } 87 | 88 | result = decode_binary_shard(&decode, buffer, 50); 89 | if(result != 28) { 90 | printf("shard2 decoding gave unexpected length\n"); 91 | return 1; 92 | } 93 | 94 | if( !shards_equal(&shard2, &decode)) { 95 | printf("shard2 decode not equal to original\n"); 96 | return 1; 97 | } 98 | 99 | return 0; 100 | } 101 | 102 | 103 | int main(void) { 104 | uint8_t fail = 0; 105 | uint8_t t; 106 | 107 | 108 | t = test_encode_decode_buffer(); 109 | fail = fail || t; 110 | printf("test encode decode buffer: %s\n", t ? "fail" : "pass" ); 111 | 112 | //t = test_bad_buffer(); 113 | //fail = fail || t; 114 | //printf("test bad buffer: %s\n", t ? "fail" : "pass" ); 115 | 116 | return fail; 117 | } 118 | -------------------------------------------------------------------------------- /slip39_shamir.c: -------------------------------------------------------------------------------- 1 | #include "slip39.h" 2 | #include "hazmat.h" 3 | 4 | #include "hmac.h" 5 | 6 | ////////////////////////////////////////////////// 7 | // hmac sha256 8 | 9 | uint8_t * create_digest( 10 | const uint8_t *random_data, 11 | uint32_t rdlen, 12 | const uint8_t *shared_secret, 13 | uint32_t sslen, 14 | uint8_t *result 15 | ) { 16 | uint8_t buf[32]; 17 | 18 | hmac_sha256(random_data, rdlen, shared_secret, sslen, buf); 19 | 20 | for(uint8_t j=0; j<4; ++j) { 21 | result[j] = buf[j]; 22 | } 23 | 24 | return result; 25 | } 26 | 27 | 28 | ////////////////////////////////////////////////// 29 | // shamir sharing 30 | int32_t split_secret( 31 | uint8_t threshold, 32 | uint8_t shard_count, 33 | const uint8_t *secret, 34 | uint32_t secret_length, 35 | uint8_t *result 36 | ) { 37 | if( shard_count > MAX_SHARD_COUNT) { 38 | return ERROR_TOO_MANY_SHARDS; 39 | } 40 | 41 | if(threshold == 1) { 42 | // just return shard_count copies of the secret 43 | uint8_t *share = result; 44 | for(uint8_t i=0; i< shard_count; ++i, share += secret_length) { 45 | for(uint8_t j=0; j&2 ; \ 25 | exit 1 ; \ 26 | fi 27 | $(MAKE) -C randombytes librandombytes.a 28 | 29 | # Force unrolling loops on hazmat.c 30 | hazmat.o: CFLAGS += -funroll-loops 31 | 32 | %.out: %.o randombytes/librandombytes.a 33 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) 34 | $(MEMCHECK) ./$@ 35 | 36 | test_hazmat.out: $(OBJS) 37 | test_sss.out: $(OBJS) 38 | 39 | 40 | libslip39.so: libslip39.a 41 | $(CC) -shared $(CFLAGS) $^ -o $@ 42 | 43 | libslip39.a: randombytes/librandombytes.a $(OBJS) 44 | $(LINK) $@ $^ 45 | 46 | slip39_tests.c: vectors_to_tests.js vectors.json 47 | node vectors_to_tests.js > slip39_tests.c 48 | 49 | slip39_tests.o: slip39_tests.c 50 | 51 | slip39_tests.out: slip39_tests.o hazmat.o slip39_wordlist.o slip39_rs1024.o \ 52 | slip39_shamir.o slip39_mnemonics.o test_random.o slip39_encrypt.o \ 53 | randombytes/librandombytes.a hmac.o memzero.o pbkdf2.o sha2.o 54 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ 55 | $(MEMCHECK) ./$@ 56 | 57 | test_interpolate.o: test_interpolate.c 58 | 59 | test_interpolate.out: hazmat.o test_interpolate.o randombytes/librandombytes.a 60 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) 61 | $(MEMCHECK) ./$@ 62 | 63 | test_slip39_wordlist.o: slip39.h test_slip39_wordlist.c 64 | 65 | slip39_wordlist.o: slip39.h slip39_wordlist.c slip39_wordlist_english.h 66 | 67 | test_slip39_wordlist.out: test_slip39_wordlist.o slip39_wordlist.o randombytes/librandombytes.a 68 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) 69 | $(MEMCHECK) ./$@ 70 | 71 | 72 | test_slip39_buffer.o: slip39.h test_slip39_buffer.c 73 | 74 | test_slip39_buffer.out: test_slip39_buffer.o slip39_buffer.o randombytes/librandombytes.a 75 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) 76 | $(MEMCHECK) ./$@ 77 | 78 | test_random.o: test_random.c 79 | 80 | test_slip39_shamir.o: test_slip39_shamir.c slip39.h 81 | 82 | slip39_shamir.o: slip39_shamir.c slip39.h 83 | 84 | test_slip39_shamir.out: test_slip39_shamir.o slip39_shamir.o hazmat.o test_random.o hmac.o memzero.o pbkdf2.o sha2.o 85 | gcc $^ -o $@ 86 | ./$@ 87 | 88 | slip39_encrypt.o: slip39_encrypt.c slip39.h 89 | 90 | test_slip39_encrypt.out: test_slip39_encrypt.o slip39_encrypt.o randombytes/librandombytes.a hmac.o memzero.o pbkdf2.o sha2.o 91 | gcc $^ -o $@ 92 | ./$@ 93 | 94 | 95 | test_generate_combine.o: test_generate_combine.c 96 | 97 | test_generate_combine.out: test_generate_combine.o hazmat.o slip39_wordlist.o \ 98 | slip39_rs1024.o slip39_shamir.o slip39_mnemonics.o slip39_encrypt.o randombytes/librandombytes.a hmac.o memzero.o pbkdf2.o sha2.o 99 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) 100 | $(MEMCHECK) ./$@ 101 | 102 | slip39: slip39_cli.c libslip39.a randombytes/librandombytes.a 103 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) 104 | 105 | .PHONY: check 106 | check: test_hazmat.out test_sss.out \ 107 | test_interpolate.out test_slip39_wordlist.out \ 108 | test_slip39_buffer.out \ 109 | test_slip39_shamir.out test_slip39_encrypt.out test_generate_combine.out slip39_tests.out 110 | 111 | .PHONY: check check_slip39 112 | 113 | .PHONY: clean 114 | clean: 115 | $(MAKE) -C randombytes $@ 116 | $(RM) *.o *.gch *.a *.out slip39 slip39_tests.c 117 | 118 | -------------------------------------------------------------------------------- /sss.c: -------------------------------------------------------------------------------- 1 | /* 2 | * AEAD wrapper around the Secret shared data 3 | * 4 | * Author: Daan Sprenkels 5 | * 6 | * This module implements a AEAD wrapper around some secret shared data, 7 | * allowing the data to be in any format. (Directly secret-sharing requires the 8 | * message to be picked uniformly in the message space.) 9 | * 10 | * The NaCl cryptographic library is used for the encryption. The encryption 11 | * scheme that is used for wrapping the message is salsa20/poly1305. Because 12 | * we are using an ephemeral key, we are using a zero'd nonce. 13 | */ 14 | 15 | 16 | #include "randombytes.h" 17 | #include "tweetnacl.h" 18 | #include "sss.h" 19 | #include "tweetnacl.h" 20 | #include 21 | #include 22 | 23 | 24 | /* 25 | * These assertions may be considered overkill, but would if the tweetnacl API 26 | * ever change we *really* want to prevent buffer overflow vulnerabilities. 27 | */ 28 | #if crypto_secretbox_KEYBYTES != 32 29 | # error "crypto_secretbox_KEYBYTES size is invalid" 30 | #endif 31 | 32 | 33 | /* 34 | * Nonce for the `crypto_secretbox` authenticated encryption. 35 | * The nonce is constant (zero), because we are using an ephemeral key. 36 | */ 37 | static const unsigned char nonce[crypto_secretbox_NONCEBYTES] = { 0 }; 38 | 39 | 40 | /* 41 | * Return a mutable pointer to the ciphertext part of this Share 42 | */ 43 | static uint8_t* get_ciphertext(sss_Share *share) 44 | { 45 | return &((uint8_t*) share)[sss_KEYSHARE_LEN]; 46 | } 47 | 48 | 49 | /* 50 | * Return a mutable pointer to the Keyshare part of this Share 51 | */ 52 | static sss_Keyshare* get_keyshare(sss_Share *share) 53 | { 54 | return (sss_Keyshare*) &share[0]; 55 | } 56 | 57 | 58 | /* 59 | * Return a const pointer to the ciphertext part of this Share 60 | */ 61 | static const uint8_t* get_ciphertext_const(const sss_Share *share) 62 | { 63 | return &((const uint8_t*) share)[sss_KEYSHARE_LEN]; 64 | } 65 | 66 | 67 | /* 68 | * Return a const pointer to the Keyshare part of this Share 69 | */ 70 | static const sss_Keyshare* get_keyshare_const(const sss_Share *share) 71 | { 72 | return (const sss_Keyshare*) &share[0]; 73 | } 74 | 75 | 76 | /* 77 | * Create `n` shares with theshold `k` and write them to `out` 78 | */ 79 | void sss_create_shares(sss_Share *out, const unsigned char *data, 80 | uint8_t n, uint8_t k) 81 | { 82 | unsigned char key[32]; 83 | unsigned char m[crypto_secretbox_ZEROBYTES + sss_MLEN] = { 0 }; 84 | unsigned long long mlen = sizeof(m); /* length includes zero-bytes */ 85 | unsigned char c[mlen]; 86 | int tmp; 87 | sss_Keyshare keyshares[n]; 88 | size_t idx; 89 | 90 | /* Generate a random encryption key */ 91 | randombytes(key, sizeof(key)); 92 | 93 | /* AEAD encrypt the data with the key */ 94 | memcpy(&m[crypto_secretbox_ZEROBYTES], data, sss_MLEN); 95 | tmp = crypto_secretbox(c, m, mlen, nonce, key); 96 | assert(tmp == 0); /* should always happen */ 97 | 98 | /* Generate KeyShares */ 99 | sss_create_keyshares(keyshares, key, n, k); 100 | 101 | /* Build regular shares */ 102 | for (idx = 0; idx < n; idx++) { 103 | memcpy(get_keyshare((sss_Share*) &out[idx]), &keyshares[idx][0], 104 | sss_KEYSHARE_LEN); 105 | memcpy(get_ciphertext((sss_Share*) &out[idx]), 106 | &c[crypto_secretbox_BOXZEROBYTES], sss_CLEN); 107 | } 108 | } 109 | 110 | 111 | /* 112 | * Combine `k` shares pointed to by `shares` and write the result to `data` 113 | * 114 | * This function returns -1 if any of the shares were corrupted or if the number 115 | * of shares was too low. It is not possible to detect which of these errors 116 | * did occur. 117 | */ 118 | int sss_combine_shares(uint8_t *data, const sss_Share *shares, uint8_t k) 119 | { 120 | unsigned char key[crypto_secretbox_KEYBYTES]; 121 | unsigned char c[crypto_secretbox_BOXZEROBYTES + sss_CLEN] = { 0 }; 122 | unsigned long long clen = sizeof(c); 123 | unsigned char m[clen]; 124 | sss_Keyshare keyshares[k]; 125 | size_t idx; 126 | int ret = 0; 127 | 128 | /* Check if all ciphertexts are the same */ 129 | if (k < 1) return -1; 130 | for (idx = 1; idx < k; idx++) { 131 | if (memcmp(get_ciphertext_const(&shares[0]), 132 | get_ciphertext_const(&shares[idx]), sss_CLEN) != 0) { 133 | return -1; 134 | } 135 | } 136 | 137 | /* Restore the key */ 138 | for (idx = 0; idx < k; idx++) { 139 | memcpy(&keyshares[idx], get_keyshare_const(&shares[idx]), 140 | sss_KEYSHARE_LEN); 141 | } 142 | sss_combine_keyshares(key, (const sss_Keyshare*) keyshares, k); 143 | 144 | /* Decrypt the ciphertext */ 145 | memcpy(&c[crypto_secretbox_BOXZEROBYTES], 146 | &shares[0][sss_KEYSHARE_LEN], sss_CLEN); 147 | ret |= crypto_secretbox_open(m, c, clen, nonce, key); 148 | memcpy(data, &m[crypto_secretbox_ZEROBYTES], sss_MLEN); 149 | 150 | return ret; 151 | } 152 | -------------------------------------------------------------------------------- /hazmat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Low level API for Daan Sprenkels' Shamir secret sharing library 3 | * Copyright (c) 2017 Daan Sprenkels 4 | * 5 | * Usage of this API is hazardous and is only reserved for beings with a 6 | * good understanding of the Shamir secret sharing scheme and who know how 7 | * crypto code is implemented. If you are unsure about this, use the 8 | * intermediate level API. You have been warned! 9 | */ 10 | 11 | 12 | #ifndef sss_HAZMAT_H_ 13 | #define sss_HAZMAT_H_ 14 | 15 | #include 16 | 17 | 18 | #define sss_KEYSHARE_LEN 33 /* 1 + 32 */ 19 | 20 | 21 | /* 22 | * One share of a cryptographic key which is shared using Shamir's 23 | * the `sss_create_keyshares` function. 24 | */ 25 | typedef uint8_t sss_Keyshare[sss_KEYSHARE_LEN]; 26 | 27 | 28 | /* 29 | * Share the secret given in `key` into `n` shares with a treshold value given 30 | * in `k`. The resulting shares are written to `out`. 31 | * 32 | * The share generation that is done in this function is only secure if the key 33 | * that is given is indeed a cryptographic key. This means that it should be 34 | * randomly and uniformly generated string of 32 bytes. 35 | * 36 | * Also, for performance reasons, this function assumes that both `n` and `k` 37 | * are *public* values. 38 | * 39 | * If you are looking for a function that *just* creates shares of arbitrary 40 | * data, you should use the `sss_create_shares` function in `sss.h`. 41 | */ 42 | void sss_create_keyshares(sss_Keyshare *out, 43 | const uint8_t key[32], 44 | uint8_t n, 45 | uint8_t k); 46 | 47 | 48 | /* 49 | * Combine the `k` shares provided in `shares` and write the resulting key to 50 | * `key`. The amount of shares used to restore a secret may be larger than the 51 | * threshold needed to restore them. 52 | * 53 | * This function does *not* do *any* checking for integrity. If any of the 54 | * shares not original, this will result in an invalid resored value. 55 | * All values written to `key` should be treated as secret. Even if some of the 56 | * shares that were provided as input were incorrect, the resulting key *still* 57 | * allows an attacker to gain information about the real key. 58 | * 59 | * This function treats `shares` and `key` as secret values. `k` is treated as 60 | * a public value (for performance reasons). 61 | * 62 | * If you are looking for a function that combines shares of arbitrary 63 | * data, you should use the `sss_combine_shares` function in `sss.h`. 64 | */ 65 | void sss_combine_keyshares(uint8_t key[32], 66 | const sss_Keyshare *shares, 67 | uint8_t k); 68 | 69 | 70 | 71 | #include 72 | #include "slip39.h" 73 | 74 | /* 75 | * calculate the lagrange basis coefficients for the lagrange polynomial 76 | * defined byt the x coordinates xc at the value x. 77 | * 78 | * inputs: values: pointer to an array to write the values 79 | * n: number of points - length of the xc array, 0 < n <= 32 80 | * xc: array of x components to use as interpolating points 81 | * x: x coordinate to evaluate lagrange polynomials at 82 | * 83 | * After the function runs, the values array should hold data satisfying 84 | * the following: 85 | * --- (x-xc[j]) 86 | * values[i] = | | ------------- 87 | * j != i (xc[i]-xc[j]) 88 | */ 89 | void 90 | hazmat_lagrange_basis(uint8_t *values, 91 | uint8_t n, 92 | const uint8_t *xc, 93 | uint8_t x); 94 | 95 | /** 96 | * safely interpolate the polynomial going through 97 | * the points (x0 [y0_0 y0_1 y0_2 ... y0_31]) , (x1 [y1_0 ...]), ... 98 | * 99 | * where 100 | * xi points to [x0 x1 ... xn-1 ] 101 | * y contains an array of pointers to 32-bit arrays of y values 102 | * y contains [y0 y1 y2 ... yn-1] 103 | * and each of the yi arrays contain [yi_0 yi_i ... yi_31]. 104 | * 105 | * returns: on success, the number of bytes written to result 106 | * on failure, a negative error code 107 | * 108 | * inputs: n: number of points to interpolate 109 | * xi: x coordinates for points (array of length n) 110 | * yl: length of y coordinate arrays 111 | * yij: array of n pointers to arrays of length yl 112 | * x: coordinate to interpolate at 113 | * result: space for yl bytes of interpolate data 114 | */ 115 | int16_t 116 | interpolate( 117 | uint8_t n, // number of points to interpolate 118 | const uint8_t* xi, // x coordinates for points (array of length n) 119 | uint32_t yl, // length of y coordinate array 120 | const uint8_t **yij, // n arrays of yl bytes representing y values 121 | uint8_t x, // x coordinate to interpolate 122 | uint8_t* result // space for yl bytes of results 123 | ); 124 | 125 | #endif /* sss_HAZMAT_H_ */ 126 | -------------------------------------------------------------------------------- /slip39_cli.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include "slip39.h" 5 | 6 | int help(void); 7 | int generate(int, char**, char*, char *); 8 | int combine(char *); 9 | 10 | int help(void) { 11 | printf("slip39 - generate or combine slip39 style shamir shared secrets.\n\n"); 12 | printf("usage: slip39 combine {-p password}\n"); 13 | printf(" slip39 generate {-p password} {-s secret} k1ofn1 k2ofn2 ...\n"); 14 | // slip39cli generate 5 2of3 2of3 1of1 -p password 15 | // slip39cli combine -p password 16 | 17 | return -1; 18 | } 19 | 20 | void print_words(uint16_t *, int32_t); 21 | 22 | void print_words(uint16_t *words, int32_t count) { 23 | if(count > 0) { 24 | printf("%s", slip39_word(words[0])); 25 | for(int32_t i=1; i 0) { 107 | mnems[mnemonic_count++] = mnem; 108 | 109 | mnem += word_count; 110 | mnemonic_length = word_count; 111 | remaining -= word_count; 112 | } 113 | } 114 | 115 | if (line) 116 | free(line); 117 | 118 | uint8_t output[256]; 119 | int count = combine_mnemonics(mnems, mnemonic_length, mnemonic_count, password, NULL, output, 256); 120 | 121 | if(count < 0) { 122 | printf("%d", count); 123 | return count; 124 | } 125 | printf("%s\n", output); 126 | 127 | return 0; 128 | } 129 | 130 | 131 | int main(int argc, char **argv) { 132 | 133 | int i=1; 134 | 135 | if(argc < 2) { 136 | return help(); 137 | } 138 | 139 | char *password = NULL; 140 | char *secret = NULL; 141 | char *command = NULL; 142 | char *command_args[argc-2]; 143 | int c = 0; 144 | 145 | command = argv[1]; 146 | i = 2; 147 | 148 | 149 | // parse command line arguments 150 | while(i 0 || secret) { 165 | return help(); 166 | } 167 | return combine(password); 168 | } else if(strcmp("generate", command) == 0) { 169 | if(c < 2) { 170 | return help(); 171 | } 172 | 173 | return generate(c, command_args, password, secret); 174 | } else { 175 | return help(); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /sha2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2000-2001 Aaron D. Gifford 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the copyright holder nor the names of contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __SHA2_H__ 32 | #define __SHA2_H__ 33 | 34 | #include 35 | #include 36 | 37 | #define SHA1_BLOCK_LENGTH 64 38 | #define SHA1_DIGEST_LENGTH 20 39 | #define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) 40 | #define SHA256_BLOCK_LENGTH 64 41 | #define SHA256_DIGEST_LENGTH 32 42 | #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) 43 | #define SHA512_BLOCK_LENGTH 128 44 | #define SHA512_DIGEST_LENGTH 64 45 | #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) 46 | 47 | typedef struct _SHA1_CTX { 48 | uint32_t state[5]; 49 | uint64_t bitcount; 50 | uint32_t buffer[SHA1_BLOCK_LENGTH/sizeof(uint32_t)]; 51 | } SHA1_CTX; 52 | typedef struct _SHA256_CTX { 53 | uint32_t state[8]; 54 | uint64_t bitcount; 55 | uint32_t buffer[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; 56 | } SHA256_CTX; 57 | typedef struct _SHA512_CTX { 58 | uint64_t state[8]; 59 | uint64_t bitcount[2]; 60 | uint64_t buffer[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; 61 | } SHA512_CTX; 62 | 63 | /*** ENDIAN REVERSAL MACROS *******************************************/ 64 | #ifndef LITTLE_ENDIAN 65 | #define LITTLE_ENDIAN 1234 66 | #define BIG_ENDIAN 4321 67 | #endif 68 | 69 | #ifndef BYTE_ORDER 70 | #define BYTE_ORDER LITTLE_ENDIAN 71 | #endif 72 | 73 | #if BYTE_ORDER == LITTLE_ENDIAN 74 | #define REVERSE32(w,x) { \ 75 | uint32_t tmp = (w); \ 76 | tmp = (tmp >> 16) | (tmp << 16); \ 77 | (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ 78 | } 79 | #define REVERSE64(w,x) { \ 80 | uint64_t tmp = (w); \ 81 | tmp = (tmp >> 32) | (tmp << 32); \ 82 | tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ 83 | ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ 84 | (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ 85 | ((tmp & 0x0000ffff0000ffffULL) << 16); \ 86 | } 87 | #endif /* BYTE_ORDER == LITTLE_ENDIAN */ 88 | 89 | extern const uint32_t sha256_initial_hash_value[8]; 90 | extern const uint64_t sha512_initial_hash_value[8]; 91 | 92 | void sha1_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); 93 | void sha1_Init(SHA1_CTX *); 94 | void sha1_Update(SHA1_CTX*, const uint8_t*, size_t); 95 | void sha1_Final(SHA1_CTX*, uint8_t[SHA1_DIGEST_LENGTH]); 96 | char* sha1_End(SHA1_CTX*, char[SHA1_DIGEST_STRING_LENGTH]); 97 | void sha1_Raw(const uint8_t*, size_t, uint8_t[SHA1_DIGEST_LENGTH]); 98 | char* sha1_Data(const uint8_t*, size_t, char[SHA1_DIGEST_STRING_LENGTH]); 99 | 100 | void sha256_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); 101 | void sha256_Init(SHA256_CTX *); 102 | void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); 103 | void sha256_Final(SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH]); 104 | char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); 105 | void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); 106 | char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); 107 | 108 | void sha512_Transform(const uint64_t* state_in, const uint64_t* data, uint64_t* state_out); 109 | void sha512_Init(SHA512_CTX*); 110 | void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); 111 | void sha512_Final(SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH]); 112 | char* sha512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); 113 | void sha512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); 114 | char* sha512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /test_interpolate.c: -------------------------------------------------------------------------------- 1 | #include "hazmat.h" 2 | #include 3 | 4 | uint8_t test_lagrange_orthogonality(void); 5 | uint8_t test_lagrange_zero_one_uniqueness(void); 6 | uint8_t test_interpolation(void); 7 | uint8_t test_simple_interpolation(void); 8 | 9 | int16_t lagrange( 10 | uint8_t n, // number of points to interpolate 11 | uint8_t m, // index of this point 12 | const uint8_t *xi, // x coordinates of all points (array of size n) 13 | uint8_t x // x coordinate to evaluate 14 | ); 15 | 16 | int16_t lagrange( 17 | uint8_t n, // number of points to interpolate 18 | uint8_t m, // index of this point 19 | const uint8_t *xi, // x coordinates of all points (array of size n) 20 | uint8_t x // x coordinate to evaluate 21 | ) { 22 | uint8_t values[n]; 23 | 24 | hazmat_lagrange_basis(values, n, xi, x); 25 | 26 | return values[m]; 27 | } 28 | 29 | 30 | uint8_t test_lagrange_orthogonality(void) { 31 | uint8_t fail = 0; 32 | 33 | uint8_t xi[3]; 34 | 35 | for(int16_t i=0; i<16; ++i) { 36 | xi[0] = i; 37 | for(int16_t j=128; j<144; ++j) { 38 | xi[1] = j; 39 | for(int16_t k=250; k<256; ++k) { 40 | xi[2] = k; 41 | 42 | // Test the essential orthogonality property of the 43 | // lagrange polynomials with three parameters 44 | if( 45 | lagrange(3,0,xi,i) != 1 || 46 | lagrange(3,0,xi,j) != 0 || 47 | lagrange(3,0,xi,k) != 0 || 48 | 49 | lagrange(3,1,xi,i) != 0 || 50 | lagrange(3,1,xi,j) != 1 || 51 | lagrange(3,1,xi,k) != 0 || 52 | 53 | lagrange(3,2,xi,i) != 0 || 54 | lagrange(3,2,xi,j) != 0 || 55 | lagrange(3,2,xi,k) != 1 56 | ) { 57 | printf("lagrange failure %d %d %d\n", i, j, k); 58 | fail = 1; 59 | } 60 | } 61 | } 62 | } 63 | 64 | return fail; 65 | } 66 | 67 | uint8_t test_lagrange_zero_one_uniqueness(void) { 68 | uint8_t fail = 0; 69 | uint8_t xi[2]; 70 | 71 | for(int16_t i=0; i<16; ++i) { 72 | xi[0] = i; 73 | for(int16_t j=16; j<32; ++j) { 74 | xi[1] = j; 75 | // For two parameter lagrange polynomials, test to see that 76 | // zero one results do not result unless x in [xi] 77 | for(int16_t l=0;l<256;++l) { 78 | if( l!=i && l!=j && 79 | ( lagrange(2,0,xi,l) == 0 || 80 | lagrange(2,1,xi,l) == 0 || 81 | lagrange(2,0,xi,l) == 1 || 82 | lagrange(2,1,xi,l) == 1 83 | ) 84 | ) { 85 | printf("lagrange failure 2 %d %d %d\n", i, j, l); 86 | fail = 1; 87 | } 88 | } 89 | } 90 | } 91 | return fail; 92 | } 93 | 94 | 95 | uint8_t test_simple_interpolation(void) { 96 | uint8_t fail = 0; 97 | uint8_t x[] = { 1, 10 }; 98 | uint8_t y0[] = { 1 }; 99 | uint8_t y1[] = { 10 }; 100 | const uint8_t *y[] = {y0, y1}; 101 | 102 | uint8_t yr[256]; 103 | 104 | // Interpolate the entire range of the polynomial 105 | for(uint8_t i=0; i<255; ++i) { 106 | interpolate(2,x,1,y,i,yr+i); 107 | } 108 | 109 | for(uint8_t i=0; i<255; ++i) { 110 | if(yr[i] != i) { 111 | printf("simple interpolation failure %d %d\n", i, yr[i]); 112 | fail = 1; 113 | } 114 | } 115 | return fail; 116 | } 117 | 118 | uint8_t test_interpolation(void) { 119 | uint8_t fail = 0; 120 | uint8_t x[] = { 0, 1 }; 121 | uint8_t y0[] = { 1 }; 122 | uint8_t y1[] = { 2 }; 123 | const uint8_t *y[] = {y0, y1}; 124 | uint8_t tx[] = { 0, 0 }; 125 | uint8_t res[] = {0}; 126 | 127 | uint8_t yr[256]; 128 | const uint8_t *ty[] = { yr+0, yr+1 }; 129 | 130 | // Interpolate the entire range of the polynomial 131 | for(uint8_t i=0; i<255; ++i) { 132 | interpolate(2,x,1,y,i,yr+i); 133 | } 134 | 135 | // pick any two points on the curve 136 | for(uint8_t j = 0; j<100; ++j) { 137 | for(uint8_t k = j+1; k<101; ++k) { 138 | tx[0] = j; 139 | tx[1] = k; 140 | ty[0] = yr + j; 141 | ty[1] = yr + k; 142 | // make sure that interpolating a curve through those 143 | // tow points has the same x=0 value 144 | interpolate(2,tx,1,ty,0,res); 145 | if(res[0] != 1) { 146 | printf("interpolation failure %d %d %d\n",j,k,res[0]); 147 | fail = 1; 148 | } 149 | } 150 | } 151 | 152 | return fail; 153 | } 154 | 155 | 156 | int main(void) { 157 | uint8_t fail = 0; 158 | uint8_t t; 159 | 160 | 161 | t = test_lagrange_orthogonality(); 162 | fail = fail || t; 163 | printf("test lagrage orthogonality: %s\n", t ? "fail" : "pass" ); 164 | 165 | t = test_lagrange_zero_one_uniqueness(); 166 | fail = fail || t; 167 | printf("test lagrage zeros and ones: %s\n", t ? "fail" : "pass" ); 168 | 169 | t = test_simple_interpolation(); 170 | fail = fail || t; 171 | printf("test simple interpolation: %s\n", t ? "fail" : "pass" ); 172 | /* 173 | t = test_interpolation(); 174 | fail = fail || t; 175 | printf("test interpolation: %s\n", t ? "fail" : "pass" ); 176 | */ 177 | return fail; 178 | } 179 | -------------------------------------------------------------------------------- /slip39_wordlist.c: -------------------------------------------------------------------------------- 1 | 2 | #include "slip39.h" 3 | 4 | #include "slip39_wordlist_english.h" 5 | 6 | ////////////////////////////////////////////////// 7 | // slip39 words 8 | // 9 | int16_t lookup(const char *word) { 10 | int16_t hi=WORDLIST_SIZE; 11 | int16_t lo=-1; 12 | 13 | while(hi>lo+1) { 14 | int16_t mid = (hi + lo) / 2; 15 | int16_t cmp = strcmp(word, wordlist[mid]); 16 | if(cmp > 0) { 17 | lo = mid; 18 | } else if(cmp < 0){ 19 | hi = mid; 20 | } else { 21 | return mid; 22 | } 23 | } 24 | return -1; 25 | } 26 | 27 | const char *slip39_word(int16_t word) { 28 | if(word < 1024) { 29 | return wordlist[word]; 30 | } 31 | 32 | return ""; 33 | } 34 | 35 | uint32_t parse_words( 36 | const char *words_string, 37 | uint16_t *words, 38 | uint32_t words_length 39 | ) { 40 | char buf[16]; 41 | uint8_t i=0; 42 | uint32_t j=0; 43 | 44 | 45 | const char *p = words_string; 46 | 47 | while(*p) { 48 | for(i=0; *p>='a' && *p<='z'; i++, p++) { 49 | if(i<15) { 50 | buf[i] = *p; 51 | } else { 52 | buf[15] = 0; 53 | } 54 | } 55 | if(i<15) { 56 | buf[i] = 0; 57 | } 58 | 59 | if(j'z')) { 71 | p++; 72 | } 73 | } 74 | 75 | return j; 76 | } 77 | 78 | // convert a buffer of bytes into 10-bit mnemonic words 79 | // returns the number of words written or -1 if there was an error 80 | int32_t to_words( 81 | const uint8_t *buffer, // byte buffer to encode into 10-bit words 82 | uint32_t size, // buffer size 83 | uint16_t *words, // destination for words 84 | uint32_t max // maximum number of words to write 85 | ) { 86 | // The bottom bit of the last byte should always line up with 87 | // the bottom bit of the last word. 88 | 89 | // calculate the padding bits to add to the first byte to get 90 | // the last byte and the last word bottom bits to align 91 | // 92 | // bytes 5 4 3 2 1 0 93 | // |...,...|...,...|...,...|...,...|...,...+ 94 | // X X X X * 95 | // words 4 3 2 1 0 96 | // 97 | // Looks like the number of zero bit padding to add 98 | // is 2x the remainder when your divide the number of 99 | // bytes by 5. 100 | 101 | uint32_t byte = 0; 102 | uint32_t word = 0; 103 | 104 | uint8_t bits = (size % 5) * 2; // padded so that bottom bits align 105 | 106 | uint16_t i = 0; 107 | 108 | if(max < bytes_to_words(size)) { 109 | printf("Not enough space to encode into 10-bit words \n"); 110 | return -1; 111 | } 112 | 113 | while(byte < size && word < max) { 114 | while(bits < 10) { 115 | i = i << 8; 116 | bits += 8; 117 | if(byte < size) { 118 | i = i | buffer[byte++]; 119 | } 120 | } 121 | 122 | words[word++] = (i >> (bits-10)); 123 | i = i & ((1<<(bits-10))-1); 124 | bits -= 10; 125 | } 126 | 127 | return word; 128 | } 129 | 130 | // returns the number of bytes written, or -1 if there was an error 131 | int32_t from_words( 132 | const uint16_t *words, // words to decode 133 | uint32_t wordsize, // number of words to decode 134 | uint8_t *buffer, // space for result 135 | size_t size // total space available 136 | ) { 137 | 138 | 139 | // The bottom bit of the last byte will always show up in 140 | // the bottom bit of the last word. 141 | 142 | // calculate the padding bits to add to the first byte to get 143 | // the last byte and the last word bottom bits to align 144 | // 145 | // bytes 5 4 3 2 1 0 146 | // |...,...|...,...|...,...|...,...|...,...+ 147 | // X X X X * 148 | // words 4 3 2 1 0 149 | // 150 | 151 | 152 | uint32_t word = 0; 153 | int16_t bits = -2*(wordsize%4); 154 | 155 | // A negiative number indicates a number of padding bits. Those bits 156 | // must be zero. 157 | if(bits <0 && (words[0] & (1023 << (10+bits)))) { 158 | return ERROR_INVALID_PADDING; 159 | } 160 | 161 | // If the number of words is an odd multiple of 5, and the top 162 | // byte is all zeros, we should probably discard it to get a 163 | // resulting buffer that is an even number of bytes 164 | 165 | uint8_t discard_top_zeros = (wordsize%4 == 0) && (wordsize & 4); 166 | uint32_t byte = 0; 167 | uint16_t i = 0; 168 | 169 | if(size < words_to_bytes(wordsize)) { 170 | return ERROR_INSUFFICIENT_SPACE; 171 | } 172 | 173 | while(word < wordsize && byte < size) { 174 | i = (i << 10) | words[word++]; 175 | bits += 10; 176 | 177 | if(discard_top_zeros && (i & 1020)==0) { 178 | discard_top_zeros = 0; 179 | bits -= 8; 180 | } 181 | 182 | while(bits >= 8 && byte < size) { 183 | buffer[byte++] = (i >> (bits -8)); 184 | i = i & ((1<<(bits-8))-1); 185 | bits -= 8; 186 | } 187 | } 188 | 189 | return byte; 190 | } 191 | 192 | -------------------------------------------------------------------------------- /hmac.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | 26 | #include "hmac.h" 27 | #include "memzero.h" 28 | #include "options.h" 29 | 30 | void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, 31 | const uint32_t keylen) { 32 | static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; 33 | memzero(i_key_pad, SHA256_BLOCK_LENGTH); 34 | if (keylen > SHA256_BLOCK_LENGTH) { 35 | sha256_Raw(key, keylen, i_key_pad); 36 | } else { 37 | memcpy(i_key_pad, key, keylen); 38 | } 39 | for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { 40 | hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; 41 | i_key_pad[i] ^= 0x36; 42 | } 43 | sha256_Init(&(hctx->ctx)); 44 | sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); 45 | memzero(i_key_pad, sizeof(i_key_pad)); 46 | } 47 | 48 | void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, 49 | const uint32_t msglen) { 50 | sha256_Update(&(hctx->ctx), msg, msglen); 51 | } 52 | 53 | void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) { 54 | sha256_Final(&(hctx->ctx), hmac); 55 | sha256_Init(&(hctx->ctx)); 56 | sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); 57 | sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); 58 | sha256_Final(&(hctx->ctx), hmac); 59 | memzero(hctx, sizeof(HMAC_SHA256_CTX)); 60 | } 61 | 62 | void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, 63 | const uint32_t msglen, uint8_t *hmac) { 64 | static CONFIDENTIAL HMAC_SHA256_CTX hctx; 65 | hmac_sha256_Init(&hctx, key, keylen); 66 | hmac_sha256_Update(&hctx, msg, msglen); 67 | hmac_sha256_Final(&hctx, hmac); 68 | } 69 | 70 | void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, 71 | uint32_t *opad_digest, uint32_t *ipad_digest) { 72 | static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; 73 | 74 | memzero(key_pad, sizeof(key_pad)); 75 | if (keylen > SHA256_BLOCK_LENGTH) { 76 | static CONFIDENTIAL SHA256_CTX context; 77 | sha256_Init(&context); 78 | sha256_Update(&context, key, keylen); 79 | sha256_Final(&context, (uint8_t *)key_pad); 80 | } else { 81 | memcpy(key_pad, key, keylen); 82 | } 83 | 84 | /* compute o_key_pad and its digest */ 85 | for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { 86 | uint32_t data = 0; 87 | #if BYTE_ORDER == LITTLE_ENDIAN 88 | REVERSE32(key_pad[i], data); 89 | #else 90 | data = key_pad[i]; 91 | #endif 92 | key_pad[i] = data ^ 0x5c5c5c5c; 93 | } 94 | sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest); 95 | 96 | /* convert o_key_pad to i_key_pad and compute its digest */ 97 | for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { 98 | key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; 99 | } 100 | sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); 101 | memzero(key_pad, sizeof(key_pad)); 102 | } 103 | 104 | void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, 105 | const uint32_t keylen) { 106 | static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; 107 | memzero(i_key_pad, SHA512_BLOCK_LENGTH); 108 | if (keylen > SHA512_BLOCK_LENGTH) { 109 | sha512_Raw(key, keylen, i_key_pad); 110 | } else { 111 | memcpy(i_key_pad, key, keylen); 112 | } 113 | for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) { 114 | hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; 115 | i_key_pad[i] ^= 0x36; 116 | } 117 | sha512_Init(&(hctx->ctx)); 118 | sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); 119 | memzero(i_key_pad, sizeof(i_key_pad)); 120 | } 121 | 122 | void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, 123 | const uint32_t msglen) { 124 | sha512_Update(&(hctx->ctx), msg, msglen); 125 | } 126 | 127 | void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) { 128 | sha512_Final(&(hctx->ctx), hmac); 129 | sha512_Init(&(hctx->ctx)); 130 | sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); 131 | sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); 132 | sha512_Final(&(hctx->ctx), hmac); 133 | memzero(hctx, sizeof(HMAC_SHA512_CTX)); 134 | } 135 | 136 | void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, 137 | const uint32_t msglen, uint8_t *hmac) { 138 | HMAC_SHA512_CTX hctx = {0}; 139 | hmac_sha512_Init(&hctx, key, keylen); 140 | hmac_sha512_Update(&hctx, msg, msglen); 141 | hmac_sha512_Final(&hctx, hmac); 142 | } 143 | 144 | void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, 145 | uint64_t *opad_digest, uint64_t *ipad_digest) { 146 | static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; 147 | 148 | memzero(key_pad, sizeof(key_pad)); 149 | if (keylen > SHA512_BLOCK_LENGTH) { 150 | static CONFIDENTIAL SHA512_CTX context; 151 | sha512_Init(&context); 152 | sha512_Update(&context, key, keylen); 153 | sha512_Final(&context, (uint8_t *)key_pad); 154 | } else { 155 | memcpy(key_pad, key, keylen); 156 | } 157 | 158 | /* compute o_key_pad and its digest */ 159 | for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { 160 | uint64_t data = 0; 161 | #if BYTE_ORDER == LITTLE_ENDIAN 162 | REVERSE64(key_pad[i], data); 163 | #else 164 | data = key_pad[i]; 165 | #endif 166 | key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; 167 | } 168 | sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest); 169 | 170 | /* convert o_key_pad to i_key_pad and compute its digest */ 171 | for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { 172 | key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; 173 | } 174 | sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); 175 | memzero(key_pad, sizeof(key_pad)); 176 | } 177 | -------------------------------------------------------------------------------- /README_slip39.md: -------------------------------------------------------------------------------- 1 | # C Implementation for SLIP-0039 2 | 3 | There has recently been a growing interest in applying Shamir's Secret-Sharing Scheme 4 | to protecting and distributing the underlying secrets for cryptocurrency hierarchical 5 | deterministic (HD) wallets. The folks over at Satoshi Labs have proposed an interoperable 6 | standard for doing so: 7 | [SLIP-0039: Shamir's Secret-Sharing for Mnemonic Codes](https://github.com/satoshilabs/slips/blob/master/slip-0039.md) 8 | 9 | Along with the proposed specification, they also have provided a 10 | [python reference implementation](https://github.com/trezor/python-shamir-mnemonic) 11 | and a set of 12 | [sest vectors](https://github.com/trezor/python-shamir-mnemonic/blob/master/vectors.json). 13 | 14 | This branch intends to provide an implementation of the specification in C. Note that SLIP39 15 | differs from standard implementations of Shamir Sharing in a couple of ways - it adds some 16 | digest checking that allows you to give you some assurance that the result is correct at 17 | the expense of a few bits of security, it has a two-level grouping scheme, etc. At its heart, 18 | it ends up making more use of polynomical interpolation than other implementations do. 19 | 20 | The file vectors_to_tests.js contains some javascript that uses the published test vectors 21 | to produce C code that can be used to verify that the code implements the spec. 22 | 23 | hazmat.c provides a side-channel attack resistant implementation of gf256 operations 24 | 32 elements at a time, with a couple of additional functions dealing with lagrange 25 | polynomials and polynomial interpolation. Note that this file was copied from 26 | the Daan's original implementation of the hazmat code in the outer directory, and 27 | then his inperpolation functions were removed and new lagrange and interpolation 28 | functions added. 29 | 30 | test_random.c implements some code to act as filler for random number generation when testing. 31 | It is clearly not designed to be used in any real life application. 32 | 33 | slip_encrypt.c implements the four-round fiestel network described in slip39, but it requires 34 | pbkd2 and sha256 impementations, currently imported from openssl. 35 | 36 | slip39_rs1024.c implements the 10-bit, three word Reed Solomon checksum described in slip39. 37 | 38 | slip39_shamir.c implements the single level secret sharing scheme used by slip39. This includes 39 | imbedding a digest into the shares which requires a sha256. Again this implementation relies 40 | on openssl for sha256. 41 | 42 | slip39_wordlists.c implements functions for converting byte buffers to wordlists and 43 | and the encoding and decoding of slip39 words into 10-bit integers. the toWords and 44 | fromWords functions do/check the appropriate left padding of bits described in slip39. 45 | slip39_wordlist_english.h contains the actual word list used. 46 | 47 | There are various and sundry test files that test key parts of the implementation. You can 48 | build and run them all by building the make target 'check'. 49 | 50 | There is also a quick and dirty command line. You can build it with the make target 'slip39'. Here 51 | is a sample of running it to generate a share set and then combine some of those shares 52 | back into the default secret 'totally secret!': 53 | ```bash 54 | chris@rebma:~/projects/shamir/sss/slip39$ ./slip39 generate 2 2of3 3of5 55 | research romp acrobat echo armed decrease slush random cubic miracle dive exchange biology strategy bulb idea shrimp likely machine starting 56 | research romp acrobat email advocate academic gesture herd geology artist crystal liberty scandal smith amount costume endorse genuine steady have 57 | research romp acrobat entrance beam fangs window bolt identify receiver large saver indicate view dive gesture believe salary prize laser 58 | research romp beard eclipse closet jacket argue silver smirk garlic railroad tadpole wireless flame cover blessing worthy criminal penalty upgrade 59 | research romp beard emerald always blanket calcium forecast photo picture election curly quarter coding equip beam always spray goat become 60 | research romp beard envelope award presence adapt engage mustang language domestic ocean sympathy prisoner painting document username view mountain random 61 | research romp beard exact chemical ruin away squeeze wrote remove skin hairy mouse syndrome royal easel airline ancestor famous favorite 62 | research romp beard eyebrow cinema verify skunk oasis senior endless ting round ting sugar inherit sugar true image keyboard estimate 63 | chris@rebma:~/projects/shamir/sss/slip39$ ./slip39 combine 64 | research romp acrobat echo armed decrease slush random cubic miracle dive exchange biology strategy bulb idea shrimp likely machine starting 65 | research romp acrobat email advocate academic gesture herd geology artist crystal liberty scandal smith amount costume endorse genuine steady have 66 | research romp beard envelope award presence adapt engage mustang language domestic ocean sympathy prisoner painting document username view mountain random 67 | research romp beard exact chemical ruin away squeeze wrote remove skin hairy mouse syndrome royal easel airline ancestor famous favorite 68 | research romp beard eyebrow cinema verify skunk oasis senior endless ting round ting sugar inherit sugar true image keyboard estimate 69 | totally secret! 70 | chris@rebma:~/projects/shamir/sss/slip39$ 71 | ``` 72 | 73 | 74 | # Extensions 75 | 76 | Slip39 is designed to allow users to export recovery shards directly from 77 | trusted hardware as a recovery words. In other use cases, it may be useful 78 | to export the same data out to less trusted hardware, or in formats different 79 | from the recovery phrase. 80 | 81 | ## Shard Encryption 82 | 83 | This implementation includes functions to encrypt and decrypt the exported shard 84 | information with a password (using the same encryption algorithm used by SLIP39 85 | to encrypt the recovered secret data with a passphrase.) 86 | 87 | ## Binary format 88 | 89 | This implementation also includes some methods to export and import shards as 90 | binary buffers. This is useful when communicating directly with the library. 91 | 92 | The binary 93 | 94 | 95 | | Field Name | Bytes | Notes | 96 | |--------------------|----------|-----------------------------| 97 | | magic number | 3 | 0x48 0xbd 0xfd | 98 | | identifier | 2 | big endian, 0x0000 - 0x7fff | 99 | | iteration exponent | 1 | 5 bits, 0x00 - 0x1f | 100 | | group index | 1 | 4 bits, 0x00 - 0x0f | 101 | | group threshold | 1 | 4 bits, 0x00 - 0x0f | 102 | | group count | 1 | 4 bits, 0x00 - 0x0f | 103 | | member index | 1 | 4 bits, 0x00 - 0x0f | 104 | | member threshold | 1 | 4 bits, 0x00 - 0x0f | 105 | | value length | 1 | 0x10 or 0x20 | 106 | | value | 16 or 32 | 0x00 .. 0x00 | 107 | 108 | 109 | # External Dependencies 110 | 111 | This implementation of slip39 as a C library currently depends on Openssl. Specifically, 112 | slip39_encrypt.c depends on openssl for its implemnentation of PBKDF2_HMAC for the Fiestel 113 | round function. 114 | 115 | # TODOs: 116 | 117 | This is a list of todos for howech to complete in the near future after 118 | the RWOT9 conference: 119 | 120 | * look at reconsiling readmes 121 | 122 | -------------------------------------------------------------------------------- /pbkdf2.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include "pbkdf2.h" 25 | #include 26 | #include "hmac.h" 27 | #include "memzero.h" 28 | #include "sha2.h" 29 | 30 | void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, 31 | int passlen, const uint8_t *salt, int saltlen, 32 | uint32_t blocknr) { 33 | SHA256_CTX ctx = {0}; 34 | #if BYTE_ORDER == LITTLE_ENDIAN 35 | REVERSE32(blocknr, blocknr); 36 | #endif 37 | 38 | hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); 39 | memzero(pctx->g, sizeof(pctx->g)); 40 | pctx->g[8] = 0x80000000; 41 | pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; 42 | 43 | memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); 44 | ctx.bitcount = SHA256_BLOCK_LENGTH * 8; 45 | sha256_Update(&ctx, salt, saltlen); 46 | sha256_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); 47 | sha256_Final(&ctx, (uint8_t *)pctx->g); 48 | #if BYTE_ORDER == LITTLE_ENDIAN 49 | for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { 50 | REVERSE32(pctx->g[k], pctx->g[k]); 51 | } 52 | #endif 53 | sha256_Transform(pctx->odig, pctx->g, pctx->g); 54 | memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); 55 | pctx->first = 1; 56 | } 57 | 58 | void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, 59 | uint32_t iterations) { 60 | for (uint32_t i = pctx->first; i < iterations; i++) { 61 | sha256_Transform(pctx->idig, pctx->g, pctx->g); 62 | sha256_Transform(pctx->odig, pctx->g, pctx->g); 63 | for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH / sizeof(uint32_t); j++) { 64 | pctx->f[j] ^= pctx->g[j]; 65 | } 66 | } 67 | pctx->first = 0; 68 | } 69 | 70 | void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) { 71 | #if BYTE_ORDER == LITTLE_ENDIAN 72 | for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { 73 | REVERSE32(pctx->f[k], pctx->f[k]); 74 | } 75 | #endif 76 | memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); 77 | memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); 78 | } 79 | 80 | void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, 81 | int saltlen, uint32_t iterations, uint8_t *key, 82 | int keylen) { 83 | uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH; 84 | uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH; 85 | if (last_block_size) { 86 | blocks_count++; 87 | } else { 88 | last_block_size = SHA256_DIGEST_LENGTH; 89 | } 90 | for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { 91 | PBKDF2_HMAC_SHA256_CTX pctx = {0}; 92 | pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); 93 | pbkdf2_hmac_sha256_Update(&pctx, iterations); 94 | uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; 95 | pbkdf2_hmac_sha256_Final(&pctx, digest); 96 | uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; 97 | if (blocknr < blocks_count) { 98 | memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH); 99 | } else { 100 | memcpy(key + key_offset, digest, last_block_size); 101 | } 102 | } 103 | } 104 | 105 | void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, 106 | int passlen, const uint8_t *salt, int saltlen, 107 | uint32_t blocknr) { 108 | SHA512_CTX ctx = {0}; 109 | #if BYTE_ORDER == LITTLE_ENDIAN 110 | REVERSE32(blocknr, blocknr); 111 | #endif 112 | 113 | hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); 114 | memzero(pctx->g, sizeof(pctx->g)); 115 | pctx->g[8] = 0x8000000000000000; 116 | pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; 117 | 118 | memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); 119 | ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8; 120 | ctx.bitcount[1] = 0; 121 | sha512_Update(&ctx, salt, saltlen); 122 | sha512_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); 123 | sha512_Final(&ctx, (uint8_t *)pctx->g); 124 | #if BYTE_ORDER == LITTLE_ENDIAN 125 | for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { 126 | REVERSE64(pctx->g[k], pctx->g[k]); 127 | } 128 | #endif 129 | sha512_Transform(pctx->odig, pctx->g, pctx->g); 130 | memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); 131 | pctx->first = 1; 132 | } 133 | 134 | void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, 135 | uint32_t iterations) { 136 | for (uint32_t i = pctx->first; i < iterations; i++) { 137 | sha512_Transform(pctx->idig, pctx->g, pctx->g); 138 | sha512_Transform(pctx->odig, pctx->g, pctx->g); 139 | for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) { 140 | pctx->f[j] ^= pctx->g[j]; 141 | } 142 | } 143 | pctx->first = 0; 144 | } 145 | 146 | void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) { 147 | #if BYTE_ORDER == LITTLE_ENDIAN 148 | for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { 149 | REVERSE64(pctx->f[k], pctx->f[k]); 150 | } 151 | #endif 152 | memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); 153 | memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); 154 | } 155 | 156 | void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, 157 | int saltlen, uint32_t iterations, uint8_t *key, 158 | int keylen) { 159 | uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH; 160 | uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH; 161 | if (last_block_size) { 162 | blocks_count++; 163 | } else { 164 | last_block_size = SHA512_DIGEST_LENGTH; 165 | } 166 | for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { 167 | PBKDF2_HMAC_SHA512_CTX pctx = {0}; 168 | pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); 169 | pbkdf2_hmac_sha512_Update(&pctx, iterations); 170 | uint8_t digest[SHA512_DIGEST_LENGTH] = {0}; 171 | pbkdf2_hmac_sha512_Final(&pctx, digest); 172 | uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; 173 | if (blocknr < blocks_count) { 174 | memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH); 175 | } else { 176 | memcpy(key + key_offset, digest, last_block_size); 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shamir secret sharing library 2 | 3 | [![Build Status](https://travis-ci.org/dsprenkels/sss.svg?branch=master)](https://travis-ci.org/dsprenkels/sss) 4 | 5 | _This repo contains a third-party module that has been cloned to the BlockchainCommons repo for ease of installation or compilation of our own projects. The module remains under its original ownership and licensing requirements, and all changes made to this repo fall under that original license._ 6 | 7 | **Original Source:** [dsprenkels sss repo](https://github.com/dsprenkels/sss). 8 | 9 | **Additional Notes:** This repo has since been superceded by the [Blockchain Commons Shamir Secret Sharing](https://github.com/BlockchainCommons/bc-shamir) library. 10 | 11 |
12 | 13 | `sss` is a library that exposes an API to split secret data buffers into 14 | a number of different _shares_. With the possession of some or all of these 15 | shares, the original secret can be restored. It is the schoolbook example of 16 | a cryptographic _threshold scheme_. This library has a [command line 17 | interface][sss-cli]. ([web demo]) 18 | 19 | [sss-cli]: https://github.com/dsprenkels/sss-cli 20 | 21 | ## Table of contents 22 | 23 | 1. [Introduction](#introduction) 24 | 2. [Download](#download) 25 | 3. [Usage](#usage) 26 | 1. [Example](#example) 27 | 4. [Bindings](#bindings) 28 | 5. [Technical details](#technical-details) 29 | 6. [Comparison of secret sharing libraries](#comparison-of-secret-sharing-libraries) 30 | 7. [Questions](#questions) 31 | 32 | ## Introduction 33 | 34 | An example use case is a beer brewery which has a vault which contains their 35 | precious super secret recipe. The 5 board members of this brewery do not trust 36 | all the others well enough that they won't secretly break into the vault and 37 | sell the recipe to a competitor. So they split the code into 5 shares, and 38 | allow 4 shares to restore the original code. Now they are sure that the 39 | majority of the staff will know when the vault is opened, but they can still 40 | open the vault when one of the staff members is abroad or sick at home. 41 | 42 | As often with crypto libraries, there is a lot of Shamir secret sharing code 43 | around that *does not meet cryptographic standards* (a.k.a. is insecure). 44 | Some details—like integrity checks and side-channel resistance—are often 45 | forgotten. But these slip-ups can often fully compromise the security of the 46 | scheme. 47 | With this in mind, I have made this library to: 48 | - Be side channel resistant (timing, branch, cache) 49 | - Secure the shared secret with a MAC 50 | - Use the platform (OS) randomness source 51 | 52 | It should be safe to use this library in "the real world". I currently regard 53 | the API as being stable. Should there be any breaking changes, then I will 54 | update the version number conforming to the [semantic versioning spec][semver]. 55 | 56 | [semver]: http://semver.org/ 57 | 58 | ## Download 59 | 60 | I have released version 0.1.0 of this library, which can be downloaded from 61 | the [releases](https://github.com/dsprenkels/sss/releases) page. However, I 62 | actually recommend cloning the library with git, to also get the necesarry 63 | submodules: 64 | 65 | ```shell 66 | git clone --recursive https://github.com/dsprenkels/sss.git 67 | ``` 68 | 69 | The current version is version 0.1.0, which should be stable enough for now. 70 | The functionality may still change before version 1.0.0, although I will 71 | still fix any security issues before that. 72 | 73 | ## Usage 74 | 75 | Secrets are provided as arrays of 64 bytes long. This should be big enough to 76 | store generally small secrets. If you wish to split larger chunks of data, you 77 | can use symmetric encryption and split the key instead. Shares are generated 78 | from secret data using `sss_create_shares` and shares can be combined again 79 | using the `sss_combine_shares` functions. The shares are octet strings of 80 | 113 bytes each. 81 | 82 | ### Example 83 | 84 | ```c 85 | #include "sss.h" 86 | #include "randombytes.h" 87 | #include 88 | #include 89 | 90 | int main() 91 | { 92 | uint8_t data[sss_MLEN], restored[sss_MLEN]; 93 | sss_Share shares[5]; 94 | size_t idx; 95 | int tmp; 96 | 97 | /* Create a message [42, 42, ..., 42] */ 98 | for (idx = 0; idx < sizeof(data); ++idx) { 99 | data[idx] = 42; 100 | } 101 | 102 | /* Split the secret into 5 shares (with a recombination theshold of 4) */ 103 | sss_create_shares(shares, data, 5, 4); 104 | 105 | /* Combine some of the shares to restore the original secret */ 106 | tmp = sss_combine_shares(restored, shares, 4); 107 | assert(tmp == 0); 108 | assert(memcmp(restored, data, sss_MLEN) == 0); 109 | } 110 | ``` 111 | 112 | ## Bindings 113 | 114 | I have currently written bindings for the following languages: 115 | 116 | - [Node.js](https://github.com/dsprenkels/sss-node) 117 | - [Go](https://github.com/dsprenkels/sss-go) 118 | - [Rust](https://github.com/dsprenkels/sss-rs) 119 | - [WASM](https://github.com/3box/sss-wasm) 120 | - [Android](https://github.com/dsprenkels/sss-android)¹ 121 | - [Haskell](https://github.com/dsprenkels/sss-hs)¹ 122 | - [Swift](https://github.com/dsprenkels/sss-swift)¹ 123 | > ¹ No releases yet. 124 | 125 | ## Technical details 126 | 127 | Shamir secret sharing works by generating a polynomial (e.g. _33x³ + 8x² + 29x + 128 | 42_). The lowest term is the secret and is just filled in. All the 129 | other terms are generated randomly. Then we can pick points on the polynomial 130 | by filling in values for _x_. Each point is put in a share. Afterwards, with _k_ 131 | points we can use interpolation to restore a _k_-degree polynomial. 132 | 133 | In practice there is a wrapper around the secret-sharing part (this is done 134 | because of crypto-technical reasons). This wrapper uses the XSalsa20/Poly1305 135 | authenticated encryption scheme. Because of this, the shares are always a little 136 | bit larger than the original data. 137 | 138 | This library uses a custom [`randombytes`][randombytes] function to generate a 139 | random encapsulation key, which talks directly to the operating system. When 140 | using the high level API, you are not allowed to choose your own key. It _must_ 141 | be uniformly random, because regularities in shared secrets can be exploited. 142 | 143 | With the low level API (`hazmat.h`) you _can_ choose to secret-share a piece of 144 | data of exactly 32 bytes. This produces a set of shares that are much shorter 145 | than the high-level shares (namely 33 bytes each). However, keep in mind that 146 | this module is called `hazmat.h` (for "hazardous materials") for a reason. 147 | Please only use this if you _really_ know what you are doing. Raw "textbook" 148 | Shamir secret sharing is only safe when using a uniformly random secret (with 149 | 128 bits of entropy). Note also that it is entirely insecure for integrity. 150 | Please do not use the low-level API unless you _really_ have no other choice. 151 | 152 | ## Comparison of secret-sharing libraries 153 | 154 | If you would like your library to be added here, please open a pull request. :) 155 | 156 | | Library | Side-channels | Tamper-resistant | Secret length | 157 | |-----------------|---------------|------------------|---------------| 158 | | [B. Poettering] | Insecure¹ | Insecure | 128 bytes | 159 | | [libgfshare] | Insecure² | Insecure | ∞ | 160 | | [blockstack] | ??³ | Insecure | 160 bytes | 161 | | [sssa-golang] | Secure | Secure⁴ | ∞ | 162 | | [sssa-ruby] | ??³ | Secure⁴ | ∞ | 163 | | [snipsco] | Secure | Insecure | Note⁶ | 164 | | [c-sss] | Insecure⁷ | Insecure | ∞ | 165 | | [timtiemens] | Insecure⁸ | Note⁹ | 512 bytes | 166 | | [dsprenkels] | Secure | Secure⁵ | 64 bytes | 167 | 168 | ### Notes 169 | 170 | It is important to note that a limited secret length does not mean 171 | that it is impossible to share longer secrets. The way this is done is 172 | by secret sharing a random key and using this key to encrypt the real 173 | secret. This is a lot faster and the security is not reduced. (This is 174 | actually how [sss-cli] produces variable-length shares.) 175 | 176 | 1. Uses the GNU gmp library. 177 | 2. Uses lookup tables for GF(256) multiplication. 178 | 3. This library is implemented in a high level scripting library which does not 179 | guarantee that its basic operators execute in constant-time. 180 | 4. Uses randomized *x*-coordinates. 181 | 5. Uses randomized *y*-coordinates. 182 | 6. When using the [snipsco] library you will have to specify your own prime. 183 | Computation time is _O(p²)_, so on a normal computer you will be limited to 184 | a secret size of ~1024 bytes. 185 | 7. As mentioned by the [documentation](https://github.com/fletcher/c-sss#security-issues). 186 | 8. Uses Java `BigInteger` class. 187 | 9. Basic usage of this tool does not protect the integrity of the secrets. 188 | However, the project's readme file advises the user to use a hybrid 189 | encryption scheme and secret share the key. Through destroying the ephemeral 190 | key, the example that is listed in the readme file protects prevents an 191 | attacker from arbitrarily inserting a secret. However, inserting a garbled 192 | secret is still possible. To prevent this the user should use a AEAD scheme 193 | (like AES-GCM or ChaCha20-Poly1305) instead of AES-CBC. 194 | 195 | [B. Poettering]: http://point-at-infinity.org/ssss/ 196 | [libgfshare]: https://github.com/jcushman/libgfshare 197 | [blockstack]: https://github.com/blockstack/secret-sharing 198 | [sssa-golang]: https://github.com/SSSaaS/sssa-golang 199 | [sssa-ruby]: https://github.com/SSSaaS/sssa-ruby 200 | [snipsco]: https://github.com/snipsco/rust-threshold-secret-sharing 201 | [c-sss]: https://github.com/fletcher/c-sss 202 | [timtiemens]: https://github.com/timtiemens/secretshare 203 | [dsprenkels]: https://github.com/dsprenkels/sss 204 | 205 | 206 | ## Questions 207 | 208 | ### I do not know a lot about secret sharing. Is Shamir secret sharing useful for me? 209 | 210 | It depends. In the case of threshold schemes (that's what this is) there are 211 | two types: 212 | 213 | 1. The share-holders _cannot_ verify that their shares are valid. 214 | 2. The share-holders _can_ verify that their shares are valid. 215 | 216 | Shamir's scheme is of the first type. This immediately implies that the dealer 217 | could cheat. Indeed, they can distribute a number of shares which are just 218 | random strings. The only way the participants could know is by banding together 219 | and trying to restore the secret. This would show the secret, which would make 220 | the scheme totally pointless. 221 | 222 | **Use Shamir secret sharing only if the dealer _and_ the participants have no 223 | reason to corrupt any shares.** 224 | 225 | Examples where this is _not_ the case: 226 | 227 | - When the secret hides something that is embarrasing for one of the 228 | participants. 229 | - When the shared secret is something like a testament, and the participants 230 | are the heirs. If one of the heirs inherits more wealth when the secret is 231 | not disclosed, they can corrupt their share (and it would be impossible to 232 | check this from the share alone). 233 | 234 | In these cases, you will need a scheme of the second type. See the next 235 | question. 236 | 237 | ### Wait, I need verifiable shares! What should I use instead? 238 | 239 | There are two straightforward options: 240 | 241 | 1. When the secret is fully random—for example, a cryptographic key—use 242 | **Feldman verifiable secret sharing**. 243 | 2. When the secret is not fully random—it _could_ be a message, a number, 244 | etc.—use **Pedersen verifiable secret sharing**. 245 | 246 | ### Other 247 | 248 | For other questions, feel free to open an issue or send me an email on my Github 249 | associated e-mail address. 250 | 251 | [web demo]: http://bakaoh.com/sss-wasm/ 252 | [randombytes]: https://github.com/dsprenkels/randombytes 253 | -------------------------------------------------------------------------------- /slip39_wordlist_english.h: -------------------------------------------------------------------------------- 1 | #ifndef WORDLIST_ENGLISH_H 2 | #define WORDLIST_ENGLISH_H 3 | 4 | #define WORDLIST_SIZE 1024 5 | static const char* const wordlist[] = { 6 | "academic", "acid", "acne", "acquire", "acrobat", 7 | "activity", "actress", "adapt", "adequate", "adjust", 8 | "admit", "adorn", "adult", "advance", "advocate", 9 | "afraid", "again", "agency", "agree", "aide", 10 | "aircraft", "airline", "airport", "ajar", "alarm", 11 | "album", "alcohol", "alien", "alive", "alpha", 12 | "already", "alto", "aluminum", "always", "amazing", 13 | "ambition", "amount", "amuse", "analysis", "anatomy", 14 | "ancestor", "ancient", "angel", "angry", "animal", 15 | "answer", "antenna", "anxiety", "apart", "aquatic", 16 | "arcade", "arena", "argue", "armed", "artist", 17 | "artwork", "aspect", "auction", "august", "aunt", 18 | "average", "aviation", "avoid", "award", "away", 19 | "axis", "axle", "beam", "beard", "beaver", 20 | "become", "bedroom", "behavior", "being", "believe", 21 | "belong", "benefit", "best", "beyond", "bike", 22 | "biology", "birthday", "bishop", "black", "blanket", 23 | "blessing", "blimp", "blind", "blue", "body", 24 | "bolt", "boring", "born", "both", "boundary", 25 | "bracelet", "branch", "brave", "breathe", "briefing", 26 | "broken", "brother", "browser", "bucket", "budget", 27 | "building", "bulb", "bulge", "bumpy", "bundle", 28 | "burden", "burning", "busy", "buyer", "cage", 29 | "calcium", "camera", "campus", "canyon", "capacity", 30 | "capital", "capture", "carbon", "cards", "careful", 31 | "cargo", "carpet", "carve", "category", "cause", 32 | "ceiling", "center", "ceramic", "champion", "change", 33 | "charity", "check", "chemical", "chest", "chew", 34 | "chubby", "cinema", "civil", "class", "clay", 35 | "cleanup", "client", "climate", "clinic", "clock", 36 | "clogs", "closet", "clothes", "club", "cluster", 37 | "coal", "coastal", "coding", "column", "company", 38 | "corner", "costume", "counter", "course", "cover", 39 | "cowboy", "cradle", "craft", "crazy", "credit", 40 | "cricket", "criminal", "crisis", "critical", "crowd", 41 | "crucial", "crunch", "crush", "crystal", "cubic", 42 | "cultural", "curious", "curly", "custody", "cylinder", 43 | "daisy", "damage", "dance", "darkness", "database", 44 | "daughter", "deadline", "deal", "debris", "debut", 45 | "decent", "decision", "declare", "decorate", "decrease", 46 | "deliver", "demand", "density", "deny", "depart", 47 | "depend", "depict", "deploy", "describe", "desert", 48 | "desire", "desktop", "destroy", "detailed", "detect", 49 | "device", "devote", "diagnose", "dictate", "diet", 50 | "dilemma", "diminish", "dining", "diploma", "disaster", 51 | "discuss", "disease", "dish", "dismiss", "display", 52 | "distance", "dive", "divorce", "document", "domain", 53 | "domestic", "dominant", "dough", "downtown", "dragon", 54 | "dramatic", "dream", "dress", "drift", "drink", 55 | "drove", "drug", "dryer", "duckling", "duke", 56 | "duration", "dwarf", "dynamic", "early", "earth", 57 | "easel", "easy", "echo", "eclipse", "ecology", 58 | "edge", "editor", "educate", "either", "elbow", 59 | "elder", "election", "elegant", "element", "elephant", 60 | "elevator", "elite", "else", "email", "emerald", 61 | "emission", "emperor", "emphasis", "employer", "empty", 62 | "ending", "endless", "endorse", "enemy", "energy", 63 | "enforce", "engage", "enjoy", "enlarge", "entrance", 64 | "envelope", "envy", "epidemic", "episode", "equation", 65 | "equip", "eraser", "erode", "escape", "estate", 66 | "estimate", "evaluate", "evening", "evidence", "evil", 67 | "evoke", "exact", "example", "exceed", "exchange", 68 | "exclude", "excuse", "execute", "exercise", "exhaust", 69 | "exotic", "expand", "expect", "explain", "express", 70 | "extend", "extra", "eyebrow", "facility", "fact", 71 | "failure", "faint", "fake", "false", "family", 72 | "famous", "fancy", "fangs", "fantasy", "fatal", 73 | "fatigue", "favorite", "fawn", "fiber", "fiction", 74 | "filter", "finance", "findings", "finger", "firefly", 75 | "firm", "fiscal", "fishing", "fitness", "flame", 76 | "flash", "flavor", "flea", "flexible", "flip", 77 | "float", "floral", "fluff", "focus", "forbid", 78 | "force", "forecast", "forget", "formal", "fortune", 79 | "forward", "founder", "fraction", "fragment", "frequent", 80 | "freshman", "friar", "fridge", "friendly", "frost", 81 | "froth", "frozen", "fumes", "funding", "furl", 82 | "fused", "galaxy", "game", "garbage", "garden", 83 | "garlic", "gasoline", "gather", "general", "genius", 84 | "genre", "genuine", "geology", "gesture", "glad", 85 | "glance", "glasses", "glen", "glimpse", "goat", 86 | "golden", "graduate", "grant", "grasp", "gravity", 87 | "gray", "greatest", "grief", "grill", "grin", 88 | "grocery", "gross", "group", "grownup", "grumpy", 89 | "guard", "guest", "guilt", "guitar", "gums", 90 | "hairy", "hamster", "hand", "hanger", "harvest", 91 | "have", "havoc", "hawk", "hazard", "headset", 92 | "health", "hearing", "heat", "helpful", "herald", 93 | "herd", "hesitate", "hobo", "holiday", "holy", 94 | "home", "hormone", "hospital", "hour", "huge", 95 | "human", "humidity", "hunting", "husband", "hush", 96 | "husky", "hybrid", "idea", "identify", "idle", 97 | "image", "impact", "imply", "improve", "impulse", 98 | "include", "income", "increase", "index", "indicate", 99 | "industry", "infant", "inform", "inherit", "injury", 100 | "inmate", "insect", "inside", "install", "intend", 101 | "intimate", "invasion", "involve", "iris", "island", 102 | "isolate", "item", "ivory", "jacket", "jerky", 103 | "jewelry", "join", "judicial", "juice", "jump", 104 | "junction", "junior", "junk", "jury", "justice", 105 | "kernel", "keyboard", "kidney", "kind", "kitchen", 106 | "knife", "knit", "laden", "ladle", "ladybug", 107 | "lair", "lamp", "language", "large", "laser", 108 | "laundry", "lawsuit", "leader", "leaf", "learn", 109 | "leaves", "lecture", "legal", "legend", "legs", 110 | "lend", "length", "level", "liberty", "library", 111 | "license", "lift", "likely", "lilac", "lily", 112 | "lips", "liquid", "listen", "literary", "living", 113 | "lizard", "loan", "lobe", "location", "losing", 114 | "loud", "loyalty", "luck", "lunar", "lunch", 115 | "lungs", "luxury", "lying", "lyrics", "machine", 116 | "magazine", "maiden", "mailman", "main", "makeup", 117 | "making", "mama", "manager", "mandate", "mansion", 118 | "manual", "marathon", "march", "market", "marvel", 119 | "mason", "material", "math", "maximum", "mayor", 120 | "meaning", "medal", "medical", "member", "memory", 121 | "mental", "merchant", "merit", "method", "metric", 122 | "midst", "mild", "military", "mineral", "minister", 123 | "miracle", "mixed", "mixture", "mobile", "modern", 124 | "modify", "moisture", "moment", "morning", "mortgage", 125 | "mother", "mountain", "mouse", "move", "much", 126 | "mule", "multiple", "muscle", "museum", "music", 127 | "mustang", "nail", "national", "necklace", "negative", 128 | "nervous", "network", "news", "nuclear", "numb", 129 | "numerous", "nylon", "oasis", "obesity", "object", 130 | "observe", "obtain", "ocean", "often", "olympic", 131 | "omit", "oral", "orange", "orbit", "order", 132 | "ordinary", "organize", "ounce", "oven", "overall", 133 | "owner", "paces", "pacific", "package", "paid", 134 | "painting", "pajamas", "pancake", "pants", "papa", 135 | "paper", "parcel", "parking", "party", "patent", 136 | "patrol", "payment", "payroll", "peaceful", "peanut", 137 | "peasant", "pecan", "penalty", "pencil", "percent", 138 | "perfect", "permit", "petition", "phantom", "pharmacy", 139 | "photo", "phrase", "physics", "pickup", "picture", 140 | "piece", "pile", "pink", "pipeline", "pistol", 141 | "pitch", "plains", "plan", "plastic", "platform", 142 | "playoff", "pleasure", "plot", "plunge", "practice", 143 | "prayer", "preach", "predator", "pregnant", "premium", 144 | "prepare", "presence", "prevent", "priest", "primary", 145 | "priority", "prisoner", "privacy", "prize", "problem", 146 | "process", "profile", "program", "promise", "prospect", 147 | "provide", "prune", "public", "pulse", "pumps", 148 | "punish", "puny", "pupal", "purchase", "purple", 149 | "python", "quantity", "quarter", "quick", "quiet", 150 | "race", "racism", "radar", "railroad", "rainbow", 151 | "raisin", "random", "ranked", "rapids", "raspy", 152 | "reaction", "realize", "rebound", "rebuild", "recall", 153 | "receiver", "recover", "regret", "regular", "reject", 154 | "relate", "remember", "remind", "remove", "render", 155 | "repair", "repeat", "replace", "require", "rescue", 156 | "research", "resident", "response", "result", "retailer", 157 | "retreat", "reunion", "revenue", "review", "reward", 158 | "rhyme", "rhythm", "rich", "rival", "river", 159 | "robin", "rocky", "romantic", "romp", "roster", 160 | "round", "royal", "ruin", "ruler", "rumor", 161 | "sack", "safari", "salary", "salon", "salt", 162 | "satisfy", "satoshi", "saver", "says", "scandal", 163 | "scared", "scatter", "scene", "scholar", "science", 164 | "scout", "scramble", "screw", "script", "scroll", 165 | "seafood", "season", "secret", "security", "segment", 166 | "senior", "shadow", "shaft", "shame", "shaped", 167 | "sharp", "shelter", "sheriff", "short", "should", 168 | "shrimp", "sidewalk", "silent", "silver", "similar", 169 | "simple", "single", "sister", "skin", "skunk", 170 | "slap", "slavery", "sled", "slice", "slim", 171 | "slow", "slush", "smart", "smear", "smell", 172 | "smirk", "smith", "smoking", "smug", "snake", 173 | "snapshot", "sniff", "society", "software", "soldier", 174 | "solution", "soul", "source", "space", "spark", 175 | "speak", "species", "spelling", "spend", "spew", 176 | "spider", "spill", "spine", "spirit", "spit", 177 | "spray", "sprinkle", "square", "squeeze", "stadium", 178 | "staff", "standard", "starting", "station", "stay", 179 | "steady", "step", "stick", "stilt", "story", 180 | "strategy", "strike", "style", "subject", "submit", 181 | "sugar", "suitable", "sunlight", "superior", "surface", 182 | "surprise", "survive", "sweater", "swimming", "swing", 183 | "switch", "symbolic", "sympathy", "syndrome", "system", 184 | "tackle", "tactics", "tadpole", "talent", "task", 185 | "taste", "taught", "taxi", "teacher", "teammate", 186 | "teaspoon", "temple", "tenant", "tendency", "tension", 187 | "terminal", "testify", "texture", "thank", "that", 188 | "theater", "theory", "therapy", "thorn", "threaten", 189 | "thumb", "thunder", "ticket", "tidy", "timber", 190 | "timely", "ting", "tofu", "together", "tolerate", 191 | "total", "toxic", "tracks", "traffic", "training", 192 | "transfer", "trash", "traveler", "treat", "trend", 193 | "trial", "tricycle", "trip", "triumph", "trouble", 194 | "true", "trust", "twice", "twin", "type", 195 | "typical", "ugly", "ultimate", "umbrella", "uncover", 196 | "undergo", "unfair", "unfold", "unhappy", "union", 197 | "universe", "unkind", "unknown", "unusual", "unwrap", 198 | "upgrade", "upstairs", "username", "usher", "usual", 199 | "valid", "valuable", "vampire", "vanish", "various", 200 | "vegan", "velvet", "venture", "verdict", "verify", 201 | "very", "veteran", "vexed", "victim", "video", 202 | "view", "vintage", "violence", "viral", "visitor", 203 | "visual", "vitamins", "vocal", "voice", "volume", 204 | "voter", "voting", "walnut", "warmth", "warn", 205 | "watch", "wavy", "wealthy", "weapon", "webcam", 206 | "welcome", "welfare", "western", "width", "wildlife", 207 | "window", "wine", "wireless", "wisdom", "withdraw", 208 | "wits", "wolf", "woman", "work", "worthy", 209 | "wrap", "wrist", "writing", "wrote", "year", 210 | "yelp", "yield", "yoga", "zero", 0, 211 | }; 212 | 213 | #endif -------------------------------------------------------------------------------- /hazmat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of the hazardous parts of the SSS library 3 | * 4 | * Author: Daan Sprenkels 5 | * 6 | * This code contains the actual Shamir secret sharing functionality. The 7 | * implementation of this code is based on the idea that the user likes to 8 | * generate/combine 32 shares (in GF(2^8) at the same time, because a 256 bit 9 | * key will be exactly 32 bytes. Therefore we bitslice all the input and 10 | * unbitslice the output right before returning. 11 | * 12 | * This bitslice approach optimizes natively on all architectures that are 32 13 | * bit or more. Care is taken to use not too many registers, to ensure that no 14 | * values have to be leaked to the stack. 15 | * 16 | * All functions in this module are implemented constant time and constant 17 | * lookup operations, as all proper crypto code must be. 18 | */ 19 | 20 | 21 | #include "randombytes.h" 22 | #include "hazmat.h" 23 | #include 24 | #include 25 | 26 | 27 | typedef struct { 28 | uint8_t x; 29 | uint8_t y; 30 | } ByteShare; 31 | 32 | 33 | static void 34 | bitslice(uint32_t r[8], const uint8_t x[32]) 35 | { 36 | size_t bit_idx, arr_idx; 37 | uint32_t cur; 38 | 39 | memset(r, 0, sizeof(uint32_t[8])); 40 | for (arr_idx = 0; arr_idx < 32; arr_idx++) { 41 | cur = (uint32_t) x[arr_idx]; 42 | for (bit_idx = 0; bit_idx < 8; bit_idx++) { 43 | r[bit_idx] |= ((cur & (1 << bit_idx)) >> bit_idx) << arr_idx; 44 | } 45 | } 46 | } 47 | 48 | 49 | static void 50 | unbitslice(uint8_t r[32], const uint32_t x[8]) 51 | { 52 | size_t bit_idx, arr_idx; 53 | uint32_t cur; 54 | 55 | memset(r, 0, sizeof(uint8_t[32])); 56 | for (bit_idx = 0; bit_idx < 8; bit_idx++) { 57 | cur = (uint32_t) x[bit_idx]; 58 | for (arr_idx = 0; arr_idx < 32; arr_idx++) { 59 | r[arr_idx] |= ((cur & (1 << arr_idx)) >> arr_idx) << bit_idx; 60 | } 61 | } 62 | } 63 | 64 | 65 | static void 66 | bitslice_setall(uint32_t r[8], const uint8_t x) 67 | { 68 | size_t idx; 69 | for (idx = 0; idx < 8; idx++) { 70 | r[idx] = ((int32_t) ((x & (1 << idx)) << (31 - idx))) >> 31; 71 | } 72 | } 73 | 74 | 75 | /* 76 | * Add (XOR) `r` with `x` and store the result in `r`. 77 | */ 78 | static void 79 | gf256_add(uint32_t r[8], const uint32_t x[8]) 80 | { 81 | size_t idx; 82 | for (idx = 0; idx < 8; idx++) r[idx] ^= x[idx]; 83 | } 84 | 85 | 86 | /* 87 | * Safely multiply two bitsliced polynomials in GF(2^8) reduced by 88 | * x^8 + x^4 + x^3 + x + 1. `r` and `a` may overlap, but overlapping of `r` 89 | * and `b` will produce an incorrect result! If you need to square a polynomial 90 | * use `gf256_square` instead. 91 | */ 92 | static void 93 | gf256_mul(uint32_t r[8], const uint32_t a[8], const uint32_t b[8]) 94 | { 95 | /* This function implements Russian Peasant multiplication on two 96 | * bitsliced polynomials. 97 | * 98 | * I personally think that these kinds of long lists of operations 99 | * are often a bit ugly. A double for loop would be nicer and would 100 | * take up a lot less lines of code. 101 | * However, some compilers seem to fail in optimizing these kinds of 102 | * loops. So we will just have to do this by hand. 103 | */ 104 | uint32_t a2[8]; 105 | memcpy(a2, a, sizeof(uint32_t[8])); 106 | 107 | r[0] = a2[0] & b[0]; /* add (assignment, because r is 0) */ 108 | r[1] = a2[1] & b[0]; 109 | r[2] = a2[2] & b[0]; 110 | r[3] = a2[3] & b[0]; 111 | r[4] = a2[4] & b[0]; 112 | r[5] = a2[5] & b[0]; 113 | r[6] = a2[6] & b[0]; 114 | r[7] = a2[7] & b[0]; 115 | a2[0] ^= a2[7]; /* reduce */ 116 | a2[2] ^= a2[7]; 117 | a2[3] ^= a2[7]; 118 | 119 | r[0] ^= a2[7] & b[1]; /* add */ 120 | r[1] ^= a2[0] & b[1]; 121 | r[2] ^= a2[1] & b[1]; 122 | r[3] ^= a2[2] & b[1]; 123 | r[4] ^= a2[3] & b[1]; 124 | r[5] ^= a2[4] & b[1]; 125 | r[6] ^= a2[5] & b[1]; 126 | r[7] ^= a2[6] & b[1]; 127 | a2[7] ^= a2[6]; /* reduce */ 128 | a2[1] ^= a2[6]; 129 | a2[2] ^= a2[6]; 130 | 131 | r[0] ^= a2[6] & b[2]; /* add */ 132 | r[1] ^= a2[7] & b[2]; 133 | r[2] ^= a2[0] & b[2]; 134 | r[3] ^= a2[1] & b[2]; 135 | r[4] ^= a2[2] & b[2]; 136 | r[5] ^= a2[3] & b[2]; 137 | r[6] ^= a2[4] & b[2]; 138 | r[7] ^= a2[5] & b[2]; 139 | a2[6] ^= a2[5]; /* reduce */ 140 | a2[0] ^= a2[5]; 141 | a2[1] ^= a2[5]; 142 | 143 | r[0] ^= a2[5] & b[3]; /* add */ 144 | r[1] ^= a2[6] & b[3]; 145 | r[2] ^= a2[7] & b[3]; 146 | r[3] ^= a2[0] & b[3]; 147 | r[4] ^= a2[1] & b[3]; 148 | r[5] ^= a2[2] & b[3]; 149 | r[6] ^= a2[3] & b[3]; 150 | r[7] ^= a2[4] & b[3]; 151 | a2[5] ^= a2[4]; /* reduce */ 152 | a2[7] ^= a2[4]; 153 | a2[0] ^= a2[4]; 154 | 155 | r[0] ^= a2[4] & b[4]; /* add */ 156 | r[1] ^= a2[5] & b[4]; 157 | r[2] ^= a2[6] & b[4]; 158 | r[3] ^= a2[7] & b[4]; 159 | r[4] ^= a2[0] & b[4]; 160 | r[5] ^= a2[1] & b[4]; 161 | r[6] ^= a2[2] & b[4]; 162 | r[7] ^= a2[3] & b[4]; 163 | a2[4] ^= a2[3]; /* reduce */ 164 | a2[6] ^= a2[3]; 165 | a2[7] ^= a2[3]; 166 | 167 | r[0] ^= a2[3] & b[5]; /* add */ 168 | r[1] ^= a2[4] & b[5]; 169 | r[2] ^= a2[5] & b[5]; 170 | r[3] ^= a2[6] & b[5]; 171 | r[4] ^= a2[7] & b[5]; 172 | r[5] ^= a2[0] & b[5]; 173 | r[6] ^= a2[1] & b[5]; 174 | r[7] ^= a2[2] & b[5]; 175 | a2[3] ^= a2[2]; /* reduce */ 176 | a2[5] ^= a2[2]; 177 | a2[6] ^= a2[2]; 178 | 179 | r[0] ^= a2[2] & b[6]; /* add */ 180 | r[1] ^= a2[3] & b[6]; 181 | r[2] ^= a2[4] & b[6]; 182 | r[3] ^= a2[5] & b[6]; 183 | r[4] ^= a2[6] & b[6]; 184 | r[5] ^= a2[7] & b[6]; 185 | r[6] ^= a2[0] & b[6]; 186 | r[7] ^= a2[1] & b[6]; 187 | a2[2] ^= a2[1]; /* reduce */ 188 | a2[4] ^= a2[1]; 189 | a2[5] ^= a2[1]; 190 | 191 | r[0] ^= a2[1] & b[7]; /* add */ 192 | r[1] ^= a2[2] & b[7]; 193 | r[2] ^= a2[3] & b[7]; 194 | r[3] ^= a2[4] & b[7]; 195 | r[4] ^= a2[5] & b[7]; 196 | r[5] ^= a2[6] & b[7]; 197 | r[6] ^= a2[7] & b[7]; 198 | r[7] ^= a2[0] & b[7]; 199 | } 200 | 201 | 202 | /* 203 | * Square `x` in GF(2^8) and write the result to `r`. `r` and `x` may overlap. 204 | */ 205 | static void 206 | gf256_square(uint32_t r[8], const uint32_t x[8]) 207 | { 208 | uint32_t r8, r10, r12, r14; 209 | /* Use the Freshman's Dream rule to square the polynomial 210 | * Assignments are done from 7 downto 0, because this allows the user 211 | * to execute this function in-place (e.g. `gf256_square(r, r);`). 212 | */ 213 | r14 = x[7]; 214 | r12 = x[6]; 215 | r10 = x[5]; 216 | r8 = x[4]; 217 | r[6] = x[3]; 218 | r[4] = x[2]; 219 | r[2] = x[1]; 220 | r[0] = x[0]; 221 | 222 | /* Reduce with x^8 + x^4 + x^3 + x + 1 until order is less than 8 */ 223 | r[7] = r14; /* r[7] was 0 */ 224 | r[6] ^= r14; 225 | r10 ^= r14; 226 | /* Skip, because r13 is always 0 */ 227 | r[4] ^= r12; 228 | r[5] = r12; /* r[5] was 0 */ 229 | r[7] ^= r12; 230 | r8 ^= r12; 231 | /* Skip, because r11 is always 0 */ 232 | r[2] ^= r10; 233 | r[3] = r10; /* r[3] was 0 */ 234 | r[5] ^= r10; 235 | r[6] ^= r10; 236 | r[1] = r14; /* r[1] was 0 */ 237 | r[2] ^= r14; /* Substitute r9 by r14 because they will always be equal*/ 238 | r[4] ^= r14; 239 | r[5] ^= r14; 240 | r[0] ^= r8; 241 | r[1] ^= r8; 242 | r[3] ^= r8; 243 | r[4] ^= r8; 244 | } 245 | 246 | 247 | /* 248 | * Invert `x` in GF(2^8) and write the result to `r` 249 | */ 250 | static void 251 | gf256_inv(uint32_t r[8], uint32_t x[8]) 252 | { 253 | uint32_t y[8], z[8]; 254 | 255 | gf256_square(y, x); // y = x^2 256 | gf256_square(y, y); // y = x^4 257 | gf256_square(r, y); // r = x^8 258 | gf256_mul(z, r, x); // z = x^9 259 | gf256_square(r, r); // r = x^16 260 | gf256_mul(r, r, z); // r = x^25 261 | gf256_square(r, r); // r = x^50 262 | gf256_square(z, r); // z = x^100 263 | gf256_square(z, z); // z = x^200 264 | gf256_mul(r, r, z); // r = x^250 265 | gf256_mul(r, r, y); // r = x^254 266 | } 267 | 268 | 269 | /* 270 | * Create `k` key shares of the key given in `key`. The caller has to ensure 271 | * that the array `out` has enough space to hold at least `n` sss_Keyshare 272 | * structs. 273 | */ 274 | void 275 | sss_create_keyshares(sss_Keyshare *out, 276 | const uint8_t key[32], 277 | uint8_t n, 278 | uint8_t k) 279 | { 280 | /* Check if the parameters are valid */ 281 | assert(n != 0); 282 | assert(k != 0); 283 | assert(k <= n); 284 | 285 | uint8_t share_idx, coeff_idx, unbitsliced_x; 286 | uint32_t poly0[8], poly[k-1][8], x[8], y[8], xpow[8], tmp[8]; 287 | 288 | /* Put the secret in the bottom part of the polynomial */ 289 | bitslice(poly0, key); 290 | 291 | /* Generate the other terms of the polynomial */ 292 | randombytes((void*) poly, sizeof(poly)); 293 | 294 | for (share_idx = 0; share_idx < n; share_idx++) { 295 | /* x value is in 1..n */ 296 | unbitsliced_x = share_idx + 1; 297 | out[share_idx][0] = unbitsliced_x; 298 | bitslice_setall(x, unbitsliced_x); 299 | 300 | /* Calculate y */ 301 | memset(y, 0, sizeof(y)); 302 | memset(xpow, 0, sizeof(xpow)); 303 | xpow[0] = ~0; 304 | gf256_add(y, poly0); 305 | for (coeff_idx = 0; coeff_idx < (k-1); coeff_idx++) { 306 | gf256_mul(xpow, xpow, x); 307 | gf256_mul(tmp, xpow, poly[coeff_idx]); 308 | gf256_add(y, tmp); 309 | } 310 | unbitslice(&out[share_idx][1], y); 311 | } 312 | } 313 | 314 | 315 | /* 316 | * Restore the `k` sss_Keyshare structs given in `shares` and write the result 317 | * to `key`. 318 | */ 319 | void sss_combine_keyshares(uint8_t key[32], 320 | const sss_Keyshare *key_shares, 321 | uint8_t k) 322 | { 323 | size_t share_idx, idx1, idx2; 324 | uint32_t xs[k][8], ys[k][8]; 325 | uint32_t num[8], denom[8], tmp[8]; 326 | uint32_t secret[8] = {0}; 327 | 328 | /* Collect the x and y values */ 329 | for (share_idx = 0; share_idx < k; share_idx++) { 330 | bitslice_setall(xs[share_idx], key_shares[share_idx][0]); 331 | bitslice(ys[share_idx], &key_shares[share_idx][1]); 332 | } 333 | 334 | /* Use Lagrange basis polynomials to calculate the secret coefficient */ 335 | for (idx1 = 0; idx1 < k; idx1++) { 336 | memset(num, 0, sizeof(num)); 337 | memset(denom, 0, sizeof(denom)); 338 | num[0] = ~0; /* num is the numerator (=1) */ 339 | denom[0] = ~0; /* denom is the numerator (=1) */ 340 | for (idx2 = 0; idx2 < k; idx2++) { 341 | if (idx1 == idx2) continue; 342 | gf256_mul(num, num, xs[idx2]); 343 | memcpy(tmp, xs[idx1], sizeof(uint32_t[8])); 344 | gf256_add(tmp, xs[idx2]); 345 | gf256_mul(denom, denom, tmp); 346 | } 347 | gf256_inv(tmp, denom); /* inverted denominator */ 348 | gf256_mul(num, num, tmp); /* basis polynomial */ 349 | gf256_mul(num, num, ys[idx1]); /* scaled coefficient */ 350 | gf256_add(secret, num); 351 | } 352 | unbitslice(key, secret); 353 | } 354 | 355 | 356 | void 357 | hazmat_lagrange_basis(uint8_t *values, 358 | uint8_t n, 359 | const uint8_t *xc, 360 | uint8_t x) 361 | { 362 | // call the contents of xc [ x0 x1 x2 ... xn-1 ] 363 | uint8_t xx[32 + 16]; 364 | uint8_t i; 365 | 366 | uint32_t x_slice[8], lxi[n][8]; 367 | 368 | uint32_t numerator[8], denominator[8], temp[8]; 369 | 370 | memset(xx, 0, sizeof(xx)); 371 | for(i=0;i 32) { 448 | return ERROR_SECRET_TOO_LONG; 449 | } 450 | 451 | // The hazmat gf256 implementation needs the y-coordinate data 452 | // to be in 32-byte blocks 453 | uint8_t *y[n]; 454 | uint8_t yv[SECRET_SIZE*n]; 455 | uint8_t values[SECRET_SIZE]; 456 | 457 | memset(yv,0,SECRET_SIZE*n); 458 | for(uint8_t i=0; igroup_threshold -1) & 15; 16 | uint16_t gc = (shard->group_count -1) & 15; 17 | uint16_t mi = (shard->member_index) & 15; 18 | uint16_t mt = (shard->member_threshold -1) & 15; 19 | 20 | destination[0] = (shard->identifier >> 5) & 1023; 21 | destination[1] = ((shard->identifier << 5) | shard->iteration_exponent) & 1023; 22 | destination[2] = ((shard->group_index << 6) | (gt << 2) | (gc >> 2)) & 1023; 23 | destination[3] = ((gc << 8) | (mi << 4) | (mt)) & 1023; 24 | 25 | uint32_t words = to_words(shard->value, shard->value_length, destination+4, destination_length - METADATA_LENGTH_WORDS); 26 | rs1024_create_checksum(destination, words + METADATA_LENGTH_WORDS); 27 | 28 | return words+METADATA_LENGTH_WORDS; 29 | } 30 | 31 | ////////////////////////////////////////////////// 32 | // decode mnemonic 33 | int decode_mnemonic( 34 | const uint16_t *mnemonic, 35 | uint32_t mnemonic_length, 36 | slip39_shard *shard 37 | ) { 38 | if(mnemonic_length < MIN_MNEMONIC_LENGTH_WORDS) { 39 | return ERROR_NOT_ENOUGH_MNEMONIC_WORDS; 40 | } 41 | 42 | if( !rs1024_verify_checksum(mnemonic, mnemonic_length) ) { 43 | return ERROR_INVALID_MNEMONIC_CHECKSUM; 44 | } 45 | 46 | uint8_t group_threshold = ((mnemonic[2] >> 2) & 15) +1; 47 | uint8_t group_count = (((mnemonic[2]&3) << 2) | ((mnemonic[3]>>8)&3)) +1; 48 | 49 | if(group_threshold > group_count) { 50 | return ERROR_INVALID_MNEMONIC_GROUP_THRESHOLD; 51 | } 52 | 53 | shard->identifier = mnemonic[0] << 5 | mnemonic[1] >> 5; 54 | shard->iteration_exponent = mnemonic[1] & 31; 55 | shard->group_index = mnemonic[2] >> 6; 56 | shard->group_threshold = group_threshold; 57 | shard->group_count = group_count; 58 | shard->member_index = (mnemonic[3]>>4) & 15; 59 | shard->member_threshold = (mnemonic[3]&15) + 1; 60 | shard->value_length=from_words(mnemonic+4, mnemonic_length - 7, shard->value, 32); 61 | if(shard->value_length < MIN_STRENGTH_BYTES) { 62 | return ERROR_SECRET_TOO_SHORT; 63 | } 64 | if(shard->value_length % 2) { 65 | return ERROR_INVALID_SECRET_LENGTH; 66 | } 67 | return shard->value_length; 68 | } 69 | 70 | 71 | void print_hex( 72 | const uint8_t *buffer, 73 | uint32_t length 74 | ) { 75 | printf("0x"); 76 | for(uint32_t i=0;i 0 && i%32== 0) { 78 | printf("\n "); 79 | } 80 | printf("%02x", buffer[i]); 81 | } 82 | printf("\n"); 83 | } 84 | 85 | 86 | void print_mnemonic( 87 | const uint16_t *mnemonic, 88 | unsigned int mnemonic_length 89 | ) { 90 | slip39_shard shard; 91 | shard.value_length = 32; 92 | 93 | unsigned int secret_length = decode_mnemonic(mnemonic, mnemonic_length, &shard); 94 | shard.value_length = secret_length; 95 | 96 | for(unsigned int i=0;i< mnemonic_length; ++i) { 97 | printf("%s ", slip39_word(mnemonic[i])); 98 | } 99 | 100 | printf("\n"); 101 | printf("identifier: %d exponent: %d\n", shard.identifier, shard.iteration_exponent); 102 | printf("group index: %d threshold: %d count: %d\n", 103 | shard.group_index, shard.group_threshold, shard.group_count); 104 | printf("member index: %d threshold: %d\n", 105 | shard.member_index, shard.member_threshold); 106 | print_hex(shard.value, shard.value_length); 107 | } 108 | 109 | int count_shards(uint8_t group_threshold, const group_descriptor *groups, uint8_t groups_length); 110 | 111 | int count_shards( 112 | uint8_t group_threshold, 113 | const group_descriptor *groups, 114 | uint8_t groups_length 115 | ) { 116 | uint16_t total_shards = 0; 117 | 118 | if(group_threshold > groups_length) { 119 | return ERROR_INVALID_GROUP_THRESHOLD; 120 | } 121 | 122 | for(uint8_t i=0; i groups[i].count ) { 125 | return ERROR_INVALID_MEMBER_THRESHOLD; 126 | } 127 | if( groups[i].threshold == 1 && groups[i].count > 1) { 128 | return ERROR_INVALID_SINGLETON_MEMBER; 129 | } 130 | } 131 | 132 | return total_shards; 133 | } 134 | 135 | ////////////////////////////////////////////////// 136 | // generate shards 137 | // 138 | int generate_shards( 139 | uint8_t group_threshold, 140 | const group_descriptor *groups, 141 | uint8_t groups_length, 142 | const uint8_t *master_secret, 143 | uint32_t master_secret_length, 144 | const char *passphrase, 145 | uint8_t iteration_exponent, 146 | slip39_shard *shards, 147 | uint16_t shards_size 148 | ) { 149 | 150 | if(master_secret_length < MIN_STRENGTH_BYTES) { 151 | return ERROR_SECRET_TOO_SHORT; 152 | } 153 | 154 | if(master_secret_length % 2 == 1) { 155 | return ERROR_INVALID_SECRET_LENGTH; 156 | } 157 | 158 | // Figure out how many shards we are dealing with 159 | int total_shards = count_shards(group_threshold, groups, groups_length); 160 | if(total_shards < 0) { 161 | return total_shards; 162 | } 163 | 164 | // assign a random identifier 165 | uint16_t identifier = 0; 166 | randombytes((uint8_t *)(&identifier), 2); 167 | identifier = identifier & ((1<<15)-1); 168 | 169 | if(shards_size < total_shards) { 170 | return ERROR_INSUFFICIENT_SPACE; 171 | } 172 | 173 | if(master_secret_length % 2 == 1) { 174 | return ERROR_INVALID_SECRET_LENGTH; 175 | } 176 | 177 | for(const uint8_t *p = (const uint8_t *) passphrase; *p; p++) { 178 | if( (*p < 32) || (126 < *p) ) { 179 | return ERROR_INVALID_PASSPHRASE; 180 | } 181 | } 182 | 183 | if(group_threshold > groups_length) { 184 | return ERROR_INVALID_GROUP_THRESHOLD; 185 | } 186 | 187 | uint8_t encrypted_master_secret[master_secret_length]; 188 | 189 | slip39_encrypt(master_secret,master_secret_length,passphrase,iteration_exponent,identifier, encrypted_master_secret); 190 | 191 | uint8_t group_shares[master_secret_length * groups_length]; 192 | 193 | split_secret(group_threshold, groups_length, encrypted_master_secret, master_secret_length, group_shares); 194 | 195 | uint8_t *group_share = group_shares; 196 | 197 | unsigned int shard_count = 0; 198 | slip39_shard *shard = &shards[shard_count]; 199 | 200 | for(uint8_t i=0; iidentifier = identifier; 209 | shard->iteration_exponent = iteration_exponent; 210 | shard->group_threshold = group_threshold; 211 | shard->group_count = groups_length; 212 | shard->value_length = master_secret_length; 213 | shard->group_index = i; 214 | shard->member_threshold = groups[i].threshold; 215 | shard->member_index = j; 216 | memset(shard->value, 0, 32); 217 | memcpy(shard->value, value, master_secret_length); 218 | 219 | if(groups[i].passwords && groups[i].passwords[j]) { 220 | encrypt_shard(shard, groups[i].passwords[j]); 221 | } 222 | 223 | shard_count++; 224 | } 225 | 226 | // clean up 227 | memset(member_shares, 0, sizeof(member_shares)); 228 | } 229 | 230 | // clean up stack 231 | memset(encrypted_master_secret, 0, sizeof(encrypted_master_secret)); 232 | memset(group_shares, 0, sizeof(group_shares)); 233 | 234 | // return the number of shards generated 235 | return shard_count; 236 | } 237 | 238 | ////////////////////////////////////////////////// 239 | // generate mnemonics 240 | // 241 | int generate_mnemonics( 242 | uint8_t group_threshold, 243 | const group_descriptor *groups, 244 | uint8_t groups_length, 245 | const uint8_t *master_secret, 246 | uint32_t master_secret_length, 247 | const char *passphrase, 248 | uint8_t iteration_exponent, 249 | uint32_t *mnemonic_length, 250 | uint16_t *mnemonics, 251 | uint32_t buffer_size 252 | ) { 253 | if(master_secret_length < MIN_STRENGTH_BYTES) { 254 | return ERROR_SECRET_TOO_SHORT; 255 | } 256 | 257 | // Figure out how many shards we are dealing with 258 | int total_shards = count_shards(group_threshold, groups, groups_length); 259 | if(total_shards < 0) { 260 | return total_shards; 261 | } 262 | 263 | // figure out how much space we need to store all of the mnemonics 264 | // and make sure that we were provided with sufficient resources 265 | uint32_t shard_length = METADATA_LENGTH_WORDS + bytes_to_words(master_secret_length); 266 | if(buffer_size < shard_length * total_shards) { 267 | return ERROR_INSUFFICIENT_SPACE; 268 | } 269 | 270 | int error = 0; 271 | 272 | // allocate space for shard representations 273 | slip39_shard shards[total_shards]; 274 | 275 | // generate shards 276 | total_shards = generate_shards(group_threshold, groups, groups_length, master_secret, master_secret_length, 277 | passphrase, iteration_exponent, shards, total_shards); 278 | 279 | if(total_shards < 0) { 280 | error = total_shards; 281 | } 282 | 283 | uint16_t *mnemonic = mnemonics; 284 | unsigned int remaining_buffer = buffer_size; 285 | unsigned int word_count = 0; 286 | 287 | for(uint16_t i =0; !error && iidentifier; 376 | iteration_exponent = shard->iteration_exponent; 377 | group_count = shard->group_count; 378 | group_threshold = shard->group_threshold; 379 | secret_length = shard->value_length; 380 | } else { 381 | // on subsequent shards, check that common metadata matches 382 | if( shard->identifier != identifier || 383 | shard->iteration_exponent != iteration_exponent || 384 | shard->group_threshold != group_threshold || 385 | shard->group_count != group_count || 386 | shard->value_length != secret_length 387 | ) { 388 | return ERROR_INVALID_SHARD_SET; 389 | } 390 | } 391 | 392 | // sort shards into member groups 393 | uint8_t group_found = 0; 394 | for(uint8_t j=0; jgroup_index == groups[j].group_index) { 396 | group_found = 1; 397 | if(shard->member_threshold != groups[j].member_threshold) { 398 | return ERROR_INVALID_MEMBER_THRESHOLD; 399 | } 400 | for(uint8_t k=0; kmember_index == groups[j].member_index[k]) { 402 | return ERROR_DUPLICATE_MEMBER_INDEX; 403 | } 404 | } 405 | groups[j].member_index[groups[j].count] = shard->member_index; 406 | groups[j].value[groups[j].count] = shard->value; 407 | groups[j].count++; 408 | } 409 | } 410 | 411 | if(!group_found) { 412 | groups[next_group].group_index = shard->group_index; 413 | groups[next_group].member_threshold = shard->member_threshold; 414 | groups[next_group].count = 1; 415 | groups[next_group].member_index[0] = shard->member_index; 416 | groups[next_group].value[0] = shard->value; 417 | next_group++; 418 | } 419 | } 420 | 421 | if(buffer_length < secret_length) { 422 | error = ERROR_INSUFFICIENT_SPACE; 423 | } else if(next_group < group_threshold) { 424 | error = ERROR_NOT_ENOUGH_GROUPS; 425 | } 426 | 427 | // here, all of the shards are unpacked into member groups. Now we go through each 428 | // group and recover the group secret, and then use the result to recover the 429 | // master secret 430 | uint8_t gx[16]; 431 | const uint8_t *gy[16]; 432 | 433 | // allocate enough space for the group shards and the encrypted master secret 434 | uint8_t group_shares[secret_length * (group_threshold + 1)]; 435 | uint8_t *group_share = group_shares; 436 | 437 | for(uint8_t i=0; !error && ivalue_length]; 532 | slip39_encrypt(shard->value, shard->value_length, passphrase, shard->iteration_exponent, shard->identifier, temp); 533 | memcpy(shard->value, temp, shard->value_length); 534 | } 535 | 536 | void decrypt_shard( 537 | slip39_shard *shard, 538 | const char *passphrase 539 | ) { 540 | uint8_t temp[shard->value_length]; 541 | slip39_decrypt(shard->value, shard->value_length, passphrase, shard->iteration_exponent, shard->identifier, temp); 542 | memcpy(shard->value, temp, shard->value_length); 543 | } 544 | -------------------------------------------------------------------------------- /slip39.h: -------------------------------------------------------------------------------- 1 | #ifndef SLIP39_H 2 | #define SLIP39_H 3 | 4 | #define RADIX_BITS 10 5 | #define RADIX (1< 53 | #include 54 | #include 55 | #include 56 | 57 | 58 | typedef struct group_descriptor_struct { 59 | uint8_t threshold; 60 | uint8_t count; 61 | const char **passwords; 62 | } group_descriptor; 63 | 64 | typedef struct slip39_shard_struct { 65 | uint16_t identifier; 66 | uint8_t iteration_exponent; 67 | uint8_t group_index; 68 | uint8_t group_threshold; 69 | uint8_t group_count; 70 | uint8_t member_index; 71 | uint8_t member_threshold; 72 | uint8_t value_length; 73 | uint8_t value[32]; 74 | } slip39_shard; 75 | 76 | typedef struct group_struct { 77 | uint8_t group_index; 78 | uint8_t member_threshold; 79 | uint8_t count; 80 | uint8_t member_index[16]; 81 | const uint8_t *value[16]; 82 | } slip39_group; 83 | 84 | uint32_t rs1024_polymod( 85 | const uint16_t *values, // values - 10 bit words 86 | uint32_t values_length // number of entries in the values array 87 | ); 88 | 89 | void rs1024_create_checksum( 90 | uint16_t *values, // data words (10 bit) 91 | uint32_t n // length of the data array, including three checksum word 92 | ); 93 | 94 | uint8_t rs1024_verify_checksum( 95 | const uint16_t *values, // data words 96 | uint32_t n // length of the data array 97 | ); 98 | 99 | 100 | // returns the 10-bit integer that a string represents, or -1 101 | // if the string is not a code word. 102 | int16_t lookup(const char *word); 103 | 104 | const char *slip39_word(int16_t word); 105 | 106 | /** 107 | * converts a string of whitespace delimited mnemonic words 108 | * to an array of 10-bit integers. Returns the number of integers 109 | * written to the buffer. 110 | * 111 | * returns: number of ints written to the words buffer 112 | * 113 | * inputs: word_string: space delimited group of mnemonic words 114 | * words: space to return results 115 | * words_length: maximum size of the words buffer 116 | */ 117 | 118 | uint32_t parse_words( 119 | const char *words_string, 120 | uint16_t *words, 121 | uint32_t words_length 122 | ); 123 | 124 | /** 125 | * convert a buffer of bytes into 10-bit mnemonic words 126 | * 127 | * returns: the number of words written or -1 if there was an error 128 | * 129 | * inputs: buffer: byte buffer to encode into 10-bit words 130 | * size: size of the buffer 131 | * words: destination for the words 132 | * max: maximum number of words to write 133 | */ 134 | 135 | int32_t to_words( 136 | const uint8_t *buffer, // byte buffer to encode into 10-bit words 137 | uint32_t size, // buffer size 138 | uint16_t *words, // destination for words 139 | uint32_t max // maximum number of words to write 140 | ); 141 | 142 | /** 143 | * convert a buffer of words into bytes 144 | * 145 | * returns: the number of bytes written or a negative number if there was an error 146 | * 147 | * inputs: words: array of words to decode 148 | * wordsise: number of elements in the words array 149 | * buffer: memory location to write results to 150 | * size: maximum number of bytes in the buffer. 151 | */ 152 | int32_t from_words( 153 | const uint16_t *words, // words to decode 154 | uint32_t wordsize, // number of words to decode 155 | uint8_t *buffer, // space for result 156 | size_t size // total space available 157 | ); 158 | 159 | 160 | /** 161 | * fills the destination buffer with count random bytes 162 | * 163 | * inputs: dest: location to write random bytes to 164 | * count: number of bytes to write 165 | */ 166 | int randombytes(void *buf, size_t n); 167 | 168 | /** 169 | * creates a digest used to help valididate secret reconstruction (see slip-39 docs) 170 | * 171 | * returns: a pointer to the resulting 4-byte digest 172 | * inputs: random_data: array of data to create a digest for 173 | * rdlen: length of random_data array 174 | * shared_secret: bytes to use as the key for the hmac when generating digest 175 | * sslen: length of the shared secret array 176 | * result: a pointer to a block of 4 bytes to store the resulting digest 177 | */ 178 | uint8_t* create_digest( 179 | const uint8_t *random_data, 180 | uint32_t rdlen, 181 | const uint8_t *shared_secret, 182 | uint32_t sslen, 183 | uint8_t *result 184 | ); 185 | 186 | ////////////////////////////////////////////////// 187 | // slip39 shamir sharing 188 | 189 | /** 190 | * used slip39's version of shamir sharing to split a secret up into 191 | * shard_count shares such that threshold of them must be presented 192 | * to recover the secret. 193 | * 194 | * returns: the number of shards created 195 | * 196 | * inputs: threshold: number of shards required to recover secret 197 | * shard_count: number of shards to generate 198 | * secret: array of bytes representing the secret 199 | * secret_length: length of the secret array. must be >= 16, <= 32 and even. 200 | * result: place to store the resulting shares. Must be able to hold 201 | * share_count * secret_length bytes. 202 | */ 203 | int32_t split_secret( 204 | uint8_t threshold, 205 | uint8_t shard_count, 206 | const uint8_t *secret, 207 | uint32_t secret_length, 208 | uint8_t *result 209 | ); 210 | 211 | /** 212 | * recover a secret from shards 213 | * 214 | * returns: the number of bytes written to the secret array, or a negative value if there was an error 215 | * 216 | * inputs: threshold: number of shards required 217 | * x: array of x values (length threshold) 218 | * shards: array (length threshold) of pointers to y value arrays 219 | * shard_length: number of bytes in each y value array 220 | * secret: array for writing results (must be at least shard_length long) 221 | */ 222 | int32_t recover_secret( 223 | uint8_t threshold, 224 | const uint8_t *x, 225 | const uint8_t **shards, 226 | uint32_t shard_length, 227 | uint8_t *secret 228 | ); 229 | 230 | /** 231 | * this is the round function described in the slip39 spec for the Fiestel network 232 | * it uses to encrypt/decrypt secrets with a passphrase 233 | * 234 | * inputs: i: round number 235 | * passphrase: ascii encoded passphrase 236 | * exp: exponent for the number of iterations of pbkd to run 237 | * salt: array of bytes to use a salt for the encryption 238 | * salt_lentgh: length of the salt array 239 | * r: array of bytes to encrypt 240 | * r_length: lenght of the r array 241 | * dest: location to store encrypted value 242 | * dest_length: maximum number of bytes to write to dest 243 | */ 244 | void round_function( 245 | uint8_t i, 246 | const char *passphrase, 247 | uint8_t exp, 248 | const uint8_t *salt, 249 | uint32_t salt_length, 250 | const uint8_t *r, 251 | uint32_t r_length, 252 | uint8_t *dest, 253 | uint32_t dest_length 254 | ); 255 | 256 | /** 257 | * encrypts input using passphrase with the Fiestel network described in the slip39 spec 258 | * 259 | * inputs: input: array of bytes to encrypt 260 | * input_length: length of input array 261 | * passphrase: null terminated ascii string 262 | * iteration_exponent: exponent for the number of pbkd rounds to use 263 | * identifier: identifier for the shard set (used as part of the salt) 264 | * output: memory location to write output to (same length as the input) 265 | */ 266 | void slip39_encrypt( 267 | const uint8_t *input, 268 | uint32_t input_length, 269 | const char *passphrase, 270 | uint8_t iteration_exponent, 271 | uint16_t identifier, 272 | uint8_t *output 273 | ); 274 | 275 | /** 276 | * decrypts input using passphrase with the Fiestel network described in the slip39 spec 277 | * 278 | * inputs: input: array of bytes to decrypt 279 | * input_length: length of input array 280 | * passphrase: null terminated ascii string 281 | * iteration_exponent: exponent for the number of pbkd rounds to use 282 | * identifier: identifier for the shard set (used as part of the salt) 283 | * output: memory location to write output to (same length as the input) 284 | */ 285 | void slip39_decrypt( 286 | const uint8_t *input, 287 | uint32_t input_length, 288 | const char *passphrase, 289 | uint8_t iteration_exponent, 290 | uint16_t identifier, 291 | uint8_t *output 292 | ); 293 | 294 | /** 295 | * encodes a shard as a mnemonic 296 | * 297 | * returns: number of mnemonic words generated on success, or a negative error code on failure. 298 | * 299 | * inputs: shard: pointer to a slip39_shard structure 300 | * destination: array of 16bit integers to write resulting mnemonic codes to 301 | * destination_length: maximum number of integers to write 302 | */ 303 | int encode_mnemonic( 304 | const slip39_shard *shard, 305 | uint16_t *destination, 306 | uint32_t destination_length 307 | ); 308 | 309 | /** 310 | * decodes set of mnemonic codes as a slip39_shard structure 311 | * 312 | * returns: the length of the shard's secret on success or a negative error code on failure. 313 | * 314 | * inputs: mnemonic: array of 16-bit integers representing mnemonic codes 315 | * mnemonic_lentgh: lenght of mnemonic array 316 | * share: pointer to a shard structure to write results 317 | */ 318 | int decode_mnemonic( 319 | const uint16_t *mnemonic, 320 | uint32_t mnemonic_length, 321 | slip39_shard *shard 322 | ); 323 | 324 | /** 325 | * diagnostic function for writing out hexidecimal encoded byte buffer. 326 | * 327 | * inputs: buffer: the buffer to display 328 | * length: number of bytes to display 329 | */ 330 | void print_hex( 331 | const uint8_t *buffer, 332 | uint32_t length 333 | ); 334 | 335 | /** 336 | * prints out string representation of a mnemonic code 337 | * 338 | * inputs: mnemonic: array of integers 339 | * mnemonic_length: length of mnemonic array 340 | */ 341 | void print_mnemonic( 342 | const uint16_t *mnemonic, 343 | unsigned int mnemonic_length 344 | ); 345 | 346 | /** 347 | * generate a set of shards that can be used to reconstuct a secret 348 | * using the given group policy 349 | * 350 | * returns: the number of shards generated if successful, 351 | * or a negative number indicating an error code when unsuccessful 352 | * 353 | * inputs: group_threshold: the number of groups that need to be satisfied in order 354 | * to reconstruct the secret 355 | * groups: an array of group descriptors 356 | * groups_length: the length of the groups array 357 | * master_secret: pointer to the secret to split up 358 | * master_secret_length: length of the master secret in bytes. 359 | * must be >= 16, <= 32, and even. 360 | * passphrase: string to use to encrypt the master secret 361 | * iteration_exponent: exponent to use when calculating the number of rounds of encryption 362 | * to go through when encrypting the master secret. 363 | * shards: array of shard structures to store the resulting shards 364 | * shards_size: length of the shards array 365 | */ 366 | 367 | int generate_shards( 368 | uint8_t group_threshold, 369 | const group_descriptor *groups, 370 | uint8_t groups_length, 371 | const uint8_t *master_secret, 372 | uint32_t master_secret_length, 373 | const char *passphrase, 374 | uint8_t iteration_exponent, 375 | slip39_shard *shards, 376 | uint16_t shards_size 377 | ); 378 | 379 | /** 380 | * combine a set of shards to reconstuct a secret 381 | * 382 | * returns: the length of the reconstructed secret if successful 383 | * or a negative number indicating an error code when unsuccessful 384 | * 385 | * inputs: shards: an array of shards to combine 386 | * shards_count: length of the shards array 387 | * passphrase: passphrase to use encrypt the resulting secret 388 | * passwords: array of strings to use to decrypt shard data 389 | * passing NULL disables password decrypt for all shards 390 | * passing NULL for the ith password will disable decrypt for the ith shard 391 | * passing a pointer to a string for the ith shard will cause the ith shard 392 | * to be decrypted with the string before recombination 393 | * buffer: location to store the result 394 | * buffer_length: maximum space available in buffer 395 | */ 396 | 397 | int combine_shards( 398 | const slip39_shard *shards, // array of shard structures 399 | uint16_t shards_count, // number of shards in array 400 | const char *passphrase, // passphrase to unlock master secret 401 | const char **passwords, // passwords for the shards 402 | uint8_t *buffer, // working space, and place to return secret 403 | uint32_t buffer_length // total amount of working space 404 | ); 405 | 406 | 407 | /** 408 | * generate a set of shards that can be used to reconstuct a secret 409 | * using the given group policy, but encode them as mnemonic codes 410 | * 411 | * returns: the number of shards generated if successful, 412 | * or a negative number indicating an error code when unsuccessful 413 | * 414 | * inputs: group_threshold: the number of groups that need to be satisfied in order 415 | * to reconstruct the secret 416 | * groups: an array of group descriptors 417 | * groups_length: the length of the groups array 418 | * master_secret: pointer to the secret to split up 419 | * master_secret_length: length of the master secret in bytes. 420 | * must be >= 16, <= 32, and even. 421 | * passphrase: string to use to encrypt the master secret 422 | * iteration_exponent: exponent to use when calculating the number of rounds of encryption 423 | * to go through when encrypting the master secret. 424 | * mnemonic_length: pointer to an integer that will be filled with the number of 425 | * mnemonic words in each shard 426 | * mnemonics: array of shard structures to store the resulting mnemonics. 427 | * the ith shard will be represented by 428 | * mnemonics[i*mnemonic_length]..mnemonics[(i+1)*mnemonic_length -1] 429 | * buffer_size: maximum number of mnemonics code to write to the mnemonics array 430 | */ 431 | int generate_mnemonics( 432 | uint8_t group_threshold, 433 | const group_descriptor *groups, 434 | uint8_t groups_length, 435 | const uint8_t *master_secret, 436 | uint32_t master_secret_length, 437 | const char *passphrase, 438 | uint8_t iteration_exponent, 439 | uint32_t *mnemonic_length, 440 | uint16_t *mnemonics, 441 | uint32_t buffer_size 442 | ); 443 | 444 | 445 | /** 446 | * combine a set of mnemonic encoded shards to reconstuct a secret 447 | * 448 | * returns: the length of the reconstructed secret if successful 449 | * or a negative number indicating an error code when unsuccessful 450 | * 451 | * inputs: mnemonics: an array of pointers to arrays of mnemonic codes 452 | * mnemonics_words: length of each array of mnemonic codes\ 453 | * mnemonics_shards: length of the mnemonics array 454 | * passphrase: passphrase to use encrypt the resulting secret 455 | * passwords: array of strings to use to decrypt shard data 456 | * passing NULL disables password decrypt for all shards 457 | * passing NULL for the ith password will disable decrypt for the ith shard 458 | * passing a pointer to a string for the ith shard will cause the ith shard 459 | * to be decrypted with the string before recombination 460 | * buffer: location to store the result 461 | * buffer_length: maximum space available in buffer 462 | */ 463 | int combine_mnemonics( 464 | const uint16_t **mnemonics, // array of pointers to 10-bit words 465 | uint32_t mnemonics_words, // number of words in each shard 466 | uint32_t mnemonics_shards, // total number of shards 467 | const char *passphrase, // passphrase to unlock master secret 468 | const char **passwords, // passwords protecting shards 469 | uint8_t *buffer, // working space, and place to return secret 470 | uint32_t buffer_length // total amount of working space 471 | ); 472 | 473 | /** 474 | * encrypt the share value of a shard 475 | * 476 | * inputs: shard: the shard to encrypt. The shard value is modified in place. 477 | * passphrase: a NULL terminated ascii string to use to encrypt the shard 478 | */ 479 | void encrypt_shard( 480 | slip39_shard *shard, 481 | const char *passphrase 482 | ); 483 | 484 | /** 485 | * decrypt the share value of a shard 486 | * 487 | * inputs: shard: the shard to decrypt. The shard value is modified in place. 488 | * passphrase: a NULL terminated ascii string to use to decrypt the shard 489 | */ 490 | void decrypt_shard( 491 | slip39_shard *shard, 492 | const char *passphrase 493 | ); 494 | 495 | 496 | /** 497 | * decode a slip39 shard encoded in a binary buffer 498 | * 499 | * returns: if nothing went wrong, the number of bytes read from the buffer 500 | * if an error ocurred, a negative number indicating one of the following 501 | * error conditions: 502 | * ERROR_INVALID_SHARD_BUFFER 503 | * ERROR_SECRET_TOO_SHORT 504 | * ERROR_SECRET_TOO_LONG 505 | * 506 | * inputs: shard: a pointer so a slip39_shard which will be populated upon success. 507 | * buffer: a byte buffer containing a binary encoded shard 508 | * buffer_length: the length of the buffer 509 | */ 510 | 511 | int decode_binary_shard( 512 | slip39_shard *shard, 513 | const uint8_t *buffer, 514 | uint32_t buffer_length 515 | ); 516 | 517 | /** 518 | * encode a slip39 shard into a binary buffer 519 | * 520 | * returns: if nothing went wrong, the number of bytes read from the buffer 521 | * if an error ocurred, a negative number indicating one of the following 522 | * error conditions: 523 | * ERROR_INVALID_SHARD_BUFFER 524 | * 525 | * inputs: shard: a pointer so a slip39_shard which will be populated upon success. 526 | * buffer: a byte buffer containing a binary encoded shard 527 | * buffer_length: the length of the buffer 528 | */ 529 | int encode_binary_shard( 530 | uint8_t *buffer, 531 | uint32_t buffer_length, 532 | const slip39_shard *shard 533 | ); 534 | 535 | #endif 536 | -------------------------------------------------------------------------------- /tweetnacl.c: -------------------------------------------------------------------------------- 1 | #include "tweetnacl.h" 2 | #define FOR(i,n) for (i = 0;i < n;++i) 3 | #define sv static void 4 | 5 | typedef unsigned char u8; 6 | typedef unsigned long u32; 7 | typedef unsigned long long u64; 8 | typedef long long i64; 9 | typedef i64 gf[16]; 10 | extern void randombytes(u8 *,u64); 11 | 12 | static const u8 13 | _0[16], 14 | _9[32] = {9}; 15 | static const gf 16 | gf0, 17 | gf1 = {1}, 18 | _121665 = {0xDB41,1}, 19 | D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203}, 20 | D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406}, 21 | X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169}, 22 | Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666}, 23 | I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83}; 24 | 25 | static u32 L32(u32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); } 26 | 27 | static u32 ld32(const u8 *x) 28 | { 29 | u32 u = x[3]; 30 | u = (u<<8)|x[2]; 31 | u = (u<<8)|x[1]; 32 | return (u<<8)|x[0]; 33 | } 34 | 35 | static u64 dl64(const u8 *x) 36 | { 37 | u64 i,u=0; 38 | FOR(i,8) u=(u<<8)|x[i]; 39 | return u; 40 | } 41 | 42 | sv st32(u8 *x,u32 u) 43 | { 44 | int i; 45 | FOR(i,4) { x[i] = u; u >>= 8; } 46 | } 47 | 48 | sv ts64(u8 *x,u64 u) 49 | { 50 | int i; 51 | for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; } 52 | } 53 | 54 | static int vn(const u8 *x,const u8 *y,int n) 55 | { 56 | u32 i,d = 0; 57 | FOR(i,n) d |= x[i]^y[i]; 58 | return (1 & ((d - 1) >> 8)) - 1; 59 | } 60 | 61 | int crypto_verify_16(const u8 *x,const u8 *y) 62 | { 63 | return vn(x,y,16); 64 | } 65 | 66 | int crypto_verify_32(const u8 *x,const u8 *y) 67 | { 68 | return vn(x,y,32); 69 | } 70 | 71 | sv core(u8 *out,const u8 *in,const u8 *k,const u8 *c,int h) 72 | { 73 | u32 w[16],x[16],y[16],t[4]; 74 | int i,j,m; 75 | 76 | FOR(i,4) { 77 | x[5*i] = ld32(c+4*i); 78 | x[1+i] = ld32(k+4*i); 79 | x[6+i] = ld32(in+4*i); 80 | x[11+i] = ld32(k+16+4*i); 81 | } 82 | 83 | FOR(i,16) y[i] = x[i]; 84 | 85 | FOR(i,20) { 86 | FOR(j,4) { 87 | FOR(m,4) t[m] = x[(5*j+4*m)%16]; 88 | t[1] ^= L32(t[0]+t[3], 7); 89 | t[2] ^= L32(t[1]+t[0], 9); 90 | t[3] ^= L32(t[2]+t[1],13); 91 | t[0] ^= L32(t[3]+t[2],18); 92 | FOR(m,4) w[4*j+(j+m)%4] = t[m]; 93 | } 94 | FOR(m,16) x[m] = w[m]; 95 | } 96 | 97 | if (h) { 98 | FOR(i,16) x[i] += y[i]; 99 | FOR(i,4) { 100 | x[5*i] -= ld32(c+4*i); 101 | x[6+i] -= ld32(in+4*i); 102 | } 103 | FOR(i,4) { 104 | st32(out+4*i,x[5*i]); 105 | st32(out+16+4*i,x[6+i]); 106 | } 107 | } else 108 | FOR(i,16) st32(out + 4 * i,x[i] + y[i]); 109 | } 110 | 111 | int crypto_core_salsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c) 112 | { 113 | core(out,in,k,c,0); 114 | return 0; 115 | } 116 | 117 | int crypto_core_hsalsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c) 118 | { 119 | core(out,in,k,c,1); 120 | return 0; 121 | } 122 | 123 | static const u8 sigma[16] = "expand 32-byte k"; 124 | 125 | int crypto_stream_salsa20_xor(u8 *c,const u8 *m,u64 b,const u8 *n,const u8 *k) 126 | { 127 | u8 z[16],x[64]; 128 | u32 u,i; 129 | if (!b) return 0; 130 | FOR(i,16) z[i] = 0; 131 | FOR(i,8) z[i] = n[i]; 132 | while (b >= 64) { 133 | crypto_core_salsa20(x,z,k,sigma); 134 | FOR(i,64) c[i] = (m?m[i]:0) ^ x[i]; 135 | u = 1; 136 | for (i = 8;i < 16;++i) { 137 | u += (u32) z[i]; 138 | z[i] = u; 139 | u >>= 8; 140 | } 141 | b -= 64; 142 | c += 64; 143 | if (m) m += 64; 144 | } 145 | if (b) { 146 | crypto_core_salsa20(x,z,k,sigma); 147 | FOR(i,b) c[i] = (m?m[i]:0) ^ x[i]; 148 | } 149 | return 0; 150 | } 151 | 152 | int crypto_stream_salsa20(u8 *c,u64 d,const u8 *n,const u8 *k) 153 | { 154 | return crypto_stream_salsa20_xor(c,0,d,n,k); 155 | } 156 | 157 | int crypto_stream(u8 *c,u64 d,const u8 *n,const u8 *k) 158 | { 159 | u8 s[32]; 160 | crypto_core_hsalsa20(s,n,k,sigma); 161 | return crypto_stream_salsa20(c,d,n+16,s); 162 | } 163 | 164 | int crypto_stream_xor(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) 165 | { 166 | u8 s[32]; 167 | crypto_core_hsalsa20(s,n,k,sigma); 168 | return crypto_stream_salsa20_xor(c,m,d,n+16,s); 169 | } 170 | 171 | sv add1305(u32 *h,const u32 *c) 172 | { 173 | u32 j,u = 0; 174 | FOR(j,17) { 175 | u += h[j] + c[j]; 176 | h[j] = u & 255; 177 | u >>= 8; 178 | } 179 | } 180 | 181 | static const u32 minusp[17] = { 182 | 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 183 | } ; 184 | 185 | int crypto_onetimeauth(u8 *out,const u8 *m,u64 n,const u8 *k) 186 | { 187 | u32 s,i,j,u,x[17],r[17],h[17],c[17],g[17]; 188 | 189 | FOR(j,17) r[j]=h[j]=0; 190 | FOR(j,16) r[j]=k[j]; 191 | r[3]&=15; 192 | r[4]&=252; 193 | r[7]&=15; 194 | r[8]&=252; 195 | r[11]&=15; 196 | r[12]&=252; 197 | r[15]&=15; 198 | 199 | while (n > 0) { 200 | FOR(j,17) c[j] = 0; 201 | for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j]; 202 | c[j] = 1; 203 | m += j; n -= j; 204 | add1305(h,c); 205 | FOR(i,17) { 206 | x[i] = 0; 207 | FOR(j,17) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]); 208 | } 209 | FOR(i,17) h[i] = x[i]; 210 | u = 0; 211 | FOR(j,16) { 212 | u += h[j]; 213 | h[j] = u & 255; 214 | u >>= 8; 215 | } 216 | u += h[16]; h[16] = u & 3; 217 | u = 5 * (u >> 2); 218 | FOR(j,16) { 219 | u += h[j]; 220 | h[j] = u & 255; 221 | u >>= 8; 222 | } 223 | u += h[16]; h[16] = u; 224 | } 225 | 226 | FOR(j,17) g[j] = h[j]; 227 | add1305(h,minusp); 228 | s = -(h[16] >> 7); 229 | FOR(j,17) h[j] ^= s & (g[j] ^ h[j]); 230 | 231 | FOR(j,16) c[j] = k[j + 16]; 232 | c[16] = 0; 233 | add1305(h,c); 234 | FOR(j,16) out[j] = h[j]; 235 | return 0; 236 | } 237 | 238 | int crypto_onetimeauth_verify(const u8 *h,const u8 *m,u64 n,const u8 *k) 239 | { 240 | u8 x[16]; 241 | crypto_onetimeauth(x,m,n,k); 242 | return crypto_verify_16(h,x); 243 | } 244 | 245 | int crypto_secretbox(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) 246 | { 247 | int i; 248 | if (d < 32) return -1; 249 | crypto_stream_xor(c,m,d,n,k); 250 | crypto_onetimeauth(c + 16,c + 32,d - 32,c); 251 | FOR(i,16) c[i] = 0; 252 | return 0; 253 | } 254 | 255 | int crypto_secretbox_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k) 256 | { 257 | int i; 258 | u8 x[32]; 259 | if (d < 32) return -1; 260 | crypto_stream(x,32,n,k); 261 | if (crypto_onetimeauth_verify(c + 16,c + 32,d - 32,x) != 0) return -1; 262 | crypto_stream_xor(m,c,d,n,k); 263 | FOR(i,32) m[i] = 0; 264 | return 0; 265 | } 266 | 267 | sv set25519(gf r, const gf a) 268 | { 269 | int i; 270 | FOR(i,16) r[i]=a[i]; 271 | } 272 | 273 | sv car25519(gf o) 274 | { 275 | int i; 276 | i64 c; 277 | FOR(i,16) { 278 | o[i]+=(1LL<<16); 279 | c=o[i]>>16; 280 | o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15); 281 | o[i]-=c<<16; 282 | } 283 | } 284 | 285 | sv sel25519(gf p,gf q,int b) 286 | { 287 | i64 t,i,c=~(b-1); 288 | FOR(i,16) { 289 | t= c&(p[i]^q[i]); 290 | p[i]^=t; 291 | q[i]^=t; 292 | } 293 | } 294 | 295 | sv pack25519(u8 *o,const gf n) 296 | { 297 | int i,j,b; 298 | gf m,t; 299 | FOR(i,16) t[i]=n[i]; 300 | car25519(t); 301 | car25519(t); 302 | car25519(t); 303 | FOR(j,2) { 304 | m[0]=t[0]-0xffed; 305 | for(i=1;i<15;i++) { 306 | m[i]=t[i]-0xffff-((m[i-1]>>16)&1); 307 | m[i-1]&=0xffff; 308 | } 309 | m[15]=t[15]-0x7fff-((m[14]>>16)&1); 310 | b=(m[15]>>16)&1; 311 | m[14]&=0xffff; 312 | sel25519(t,m,1-b); 313 | } 314 | FOR(i,16) { 315 | o[2*i]=t[i]&0xff; 316 | o[2*i+1]=t[i]>>8; 317 | } 318 | } 319 | 320 | static int neq25519(const gf a, const gf b) 321 | { 322 | u8 c[32],d[32]; 323 | pack25519(c,a); 324 | pack25519(d,b); 325 | return crypto_verify_32(c,d); 326 | } 327 | 328 | static u8 par25519(const gf a) 329 | { 330 | u8 d[32]; 331 | pack25519(d,a); 332 | return d[0]&1; 333 | } 334 | 335 | sv unpack25519(gf o, const u8 *n) 336 | { 337 | int i; 338 | FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8); 339 | o[15]&=0x7fff; 340 | } 341 | 342 | sv A(gf o,const gf a,const gf b) 343 | { 344 | int i; 345 | FOR(i,16) o[i]=a[i]+b[i]; 346 | } 347 | 348 | sv Z(gf o,const gf a,const gf b) 349 | { 350 | int i; 351 | FOR(i,16) o[i]=a[i]-b[i]; 352 | } 353 | 354 | sv M(gf o,const gf a,const gf b) 355 | { 356 | i64 i,j,t[31]; 357 | FOR(i,31) t[i]=0; 358 | FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j]; 359 | FOR(i,15) t[i]+=38*t[i+16]; 360 | FOR(i,16) o[i]=t[i]; 361 | car25519(o); 362 | car25519(o); 363 | } 364 | 365 | sv S(gf o,const gf a) 366 | { 367 | M(o,a,a); 368 | } 369 | 370 | sv inv25519(gf o,const gf i) 371 | { 372 | gf c; 373 | int a; 374 | FOR(a,16) c[a]=i[a]; 375 | for(a=253;a>=0;a--) { 376 | S(c,c); 377 | if(a!=2&&a!=4) M(c,c,i); 378 | } 379 | FOR(a,16) o[a]=c[a]; 380 | } 381 | 382 | sv pow2523(gf o,const gf i) 383 | { 384 | gf c; 385 | int a; 386 | FOR(a,16) c[a]=i[a]; 387 | for(a=250;a>=0;a--) { 388 | S(c,c); 389 | if(a!=1) M(c,c,i); 390 | } 391 | FOR(a,16) o[a]=c[a]; 392 | } 393 | 394 | int crypto_scalarmult(u8 *q,const u8 *n,const u8 *p) 395 | { 396 | u8 z[32]; 397 | i64 x[80],r,i; 398 | gf a,b,c,d,e,f; 399 | FOR(i,31) z[i]=n[i]; 400 | z[31]=(n[31]&127)|64; 401 | z[0]&=248; 402 | unpack25519(x,p); 403 | FOR(i,16) { 404 | b[i]=x[i]; 405 | d[i]=a[i]=c[i]=0; 406 | } 407 | a[0]=d[0]=1; 408 | for(i=254;i>=0;--i) { 409 | r=(z[i>>3]>>(i&7))&1; 410 | sel25519(a,b,r); 411 | sel25519(c,d,r); 412 | A(e,a,c); 413 | Z(a,a,c); 414 | A(c,b,d); 415 | Z(b,b,d); 416 | S(d,e); 417 | S(f,a); 418 | M(a,c,a); 419 | M(c,b,e); 420 | A(e,a,c); 421 | Z(a,a,c); 422 | S(b,a); 423 | Z(c,d,f); 424 | M(a,c,_121665); 425 | A(a,a,d); 426 | M(c,c,a); 427 | M(a,d,f); 428 | M(d,b,x); 429 | S(b,e); 430 | sel25519(a,b,r); 431 | sel25519(c,d,r); 432 | } 433 | FOR(i,16) { 434 | x[i+16]=a[i]; 435 | x[i+32]=c[i]; 436 | x[i+48]=b[i]; 437 | x[i+64]=d[i]; 438 | } 439 | inv25519(x+32,x+32); 440 | M(x+16,x+16,x+32); 441 | pack25519(q,x+16); 442 | return 0; 443 | } 444 | 445 | int crypto_scalarmult_base(u8 *q,const u8 *n) 446 | { 447 | return crypto_scalarmult(q,n,_9); 448 | } 449 | 450 | int crypto_box_keypair(u8 *y,u8 *x) 451 | { 452 | randombytes(x,32); 453 | return crypto_scalarmult_base(y,x); 454 | } 455 | 456 | int crypto_box_beforenm(u8 *k,const u8 *y,const u8 *x) 457 | { 458 | u8 s[32]; 459 | crypto_scalarmult(s,x,y); 460 | return crypto_core_hsalsa20(k,_0,s,sigma); 461 | } 462 | 463 | int crypto_box_afternm(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) 464 | { 465 | return crypto_secretbox(c,m,d,n,k); 466 | } 467 | 468 | int crypto_box_open_afternm(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k) 469 | { 470 | return crypto_secretbox_open(m,c,d,n,k); 471 | } 472 | 473 | int crypto_box(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *y,const u8 *x) 474 | { 475 | u8 k[32]; 476 | crypto_box_beforenm(k,y,x); 477 | return crypto_box_afternm(c,m,d,n,k); 478 | } 479 | 480 | int crypto_box_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *y,const u8 *x) 481 | { 482 | u8 k[32]; 483 | crypto_box_beforenm(k,y,x); 484 | return crypto_box_open_afternm(m,c,d,n,k); 485 | } 486 | 487 | static u64 R(u64 x,int c) { return (x >> c) | (x << (64 - c)); } 488 | static u64 Ch(u64 x,u64 y,u64 z) { return (x & y) ^ (~x & z); } 489 | static u64 Maj(u64 x,u64 y,u64 z) { return (x & y) ^ (x & z) ^ (y & z); } 490 | static u64 Sigma0(u64 x) { return R(x,28) ^ R(x,34) ^ R(x,39); } 491 | static u64 Sigma1(u64 x) { return R(x,14) ^ R(x,18) ^ R(x,41); } 492 | static u64 sigma0(u64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); } 493 | static u64 sigma1(u64 x) { return R(x,19) ^ R(x,61) ^ (x >> 6); } 494 | 495 | static const u64 K[80] = 496 | { 497 | 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 498 | 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 499 | 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 500 | 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 501 | 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 502 | 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 503 | 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 504 | 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 505 | 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 506 | 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 507 | 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 508 | 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 509 | 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 510 | 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 511 | 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 512 | 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 513 | 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 514 | 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 515 | 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 516 | 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL 517 | }; 518 | 519 | int crypto_hashblocks(u8 *x,const u8 *m,u64 n) 520 | { 521 | u64 z[8],b[8],a[8],w[16],t; 522 | int i,j; 523 | 524 | FOR(i,8) z[i] = a[i] = dl64(x + 8 * i); 525 | 526 | while (n >= 128) { 527 | FOR(i,16) w[i] = dl64(m + 8 * i); 528 | 529 | FOR(i,80) { 530 | FOR(j,8) b[j] = a[j]; 531 | t = a[7] + Sigma1(a[4]) + Ch(a[4],a[5],a[6]) + K[i] + w[i%16]; 532 | b[7] = t + Sigma0(a[0]) + Maj(a[0],a[1],a[2]); 533 | b[3] += t; 534 | FOR(j,8) a[(j+1)%8] = b[j]; 535 | if (i%16 == 15) 536 | FOR(j,16) 537 | w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]); 538 | } 539 | 540 | FOR(i,8) { a[i] += z[i]; z[i] = a[i]; } 541 | 542 | m += 128; 543 | n -= 128; 544 | } 545 | 546 | FOR(i,8) ts64(x+8*i,z[i]); 547 | 548 | return n; 549 | } 550 | 551 | static const u8 iv[64] = { 552 | 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, 553 | 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, 554 | 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, 555 | 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, 556 | 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, 557 | 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, 558 | 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, 559 | 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 560 | } ; 561 | 562 | int crypto_hash(u8 *out,const u8 *m,u64 n) 563 | { 564 | u8 h[64],x[256]; 565 | u64 i,b = n; 566 | 567 | FOR(i,64) h[i] = iv[i]; 568 | 569 | crypto_hashblocks(h,m,n); 570 | m += n; 571 | n &= 127; 572 | m -= n; 573 | 574 | FOR(i,256) x[i] = 0; 575 | FOR(i,n) x[i] = m[i]; 576 | x[n] = 128; 577 | 578 | n = 256-128*(n<112); 579 | x[n-9] = b >> 61; 580 | ts64(x+n-8,b<<3); 581 | crypto_hashblocks(h,x,n); 582 | 583 | FOR(i,64) out[i] = h[i]; 584 | 585 | return 0; 586 | } 587 | 588 | sv add(gf p[4],gf q[4]) 589 | { 590 | gf a,b,c,d,t,e,f,g,h; 591 | 592 | Z(a, p[1], p[0]); 593 | Z(t, q[1], q[0]); 594 | M(a, a, t); 595 | A(b, p[0], p[1]); 596 | A(t, q[0], q[1]); 597 | M(b, b, t); 598 | M(c, p[3], q[3]); 599 | M(c, c, D2); 600 | M(d, p[2], q[2]); 601 | A(d, d, d); 602 | Z(e, b, a); 603 | Z(f, d, c); 604 | A(g, d, c); 605 | A(h, b, a); 606 | 607 | M(p[0], e, f); 608 | M(p[1], h, g); 609 | M(p[2], g, f); 610 | M(p[3], e, h); 611 | } 612 | 613 | sv cswap(gf p[4],gf q[4],u8 b) 614 | { 615 | int i; 616 | FOR(i,4) 617 | sel25519(p[i],q[i],b); 618 | } 619 | 620 | sv pack(u8 *r,gf p[4]) 621 | { 622 | gf tx, ty, zi; 623 | inv25519(zi, p[2]); 624 | M(tx, p[0], zi); 625 | M(ty, p[1], zi); 626 | pack25519(r, ty); 627 | r[31] ^= par25519(tx) << 7; 628 | } 629 | 630 | sv scalarmult(gf p[4],gf q[4],const u8 *s) 631 | { 632 | int i; 633 | set25519(p[0],gf0); 634 | set25519(p[1],gf1); 635 | set25519(p[2],gf1); 636 | set25519(p[3],gf0); 637 | for (i = 255;i >= 0;--i) { 638 | u8 b = (s[i/8]>>(i&7))&1; 639 | cswap(p,q,b); 640 | add(q,p); 641 | add(p,p); 642 | cswap(p,q,b); 643 | } 644 | } 645 | 646 | sv scalarbase(gf p[4],const u8 *s) 647 | { 648 | gf q[4]; 649 | set25519(q[0],X); 650 | set25519(q[1],Y); 651 | set25519(q[2],gf1); 652 | M(q[3],X,Y); 653 | scalarmult(p,q,s); 654 | } 655 | 656 | int crypto_sign_keypair(u8 *pk, u8 *sk) 657 | { 658 | u8 d[64]; 659 | gf p[4]; 660 | int i; 661 | 662 | randombytes(sk, 32); 663 | crypto_hash(d, sk, 32); 664 | d[0] &= 248; 665 | d[31] &= 127; 666 | d[31] |= 64; 667 | 668 | scalarbase(p,d); 669 | pack(pk,p); 670 | 671 | FOR(i,32) sk[32 + i] = pk[i]; 672 | return 0; 673 | } 674 | 675 | static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10}; 676 | 677 | sv modL(u8 *r,i64 x[64]) 678 | { 679 | i64 carry,i,j; 680 | for (i = 63;i >= 32;--i) { 681 | carry = 0; 682 | for (j = i - 32;j < i - 12;++j) { 683 | x[j] += carry - 16 * x[i] * L[j - (i - 32)]; 684 | carry = (x[j] + 128) >> 8; 685 | x[j] -= carry << 8; 686 | } 687 | x[j] += carry; 688 | x[i] = 0; 689 | } 690 | carry = 0; 691 | FOR(j,32) { 692 | x[j] += carry - (x[31] >> 4) * L[j]; 693 | carry = x[j] >> 8; 694 | x[j] &= 255; 695 | } 696 | FOR(j,32) x[j] -= carry * L[j]; 697 | FOR(i,32) { 698 | x[i+1] += x[i] >> 8; 699 | r[i] = x[i] & 255; 700 | } 701 | } 702 | 703 | sv reduce(u8 *r) 704 | { 705 | i64 x[64],i; 706 | FOR(i,64) x[i] = (u64) r[i]; 707 | FOR(i,64) r[i] = 0; 708 | modL(r,x); 709 | } 710 | 711 | int crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 n,const u8 *sk) 712 | { 713 | u8 d[64],h[64],r[64]; 714 | i64 i,j,x[64]; 715 | gf p[4]; 716 | 717 | crypto_hash(d, sk, 32); 718 | d[0] &= 248; 719 | d[31] &= 127; 720 | d[31] |= 64; 721 | 722 | *smlen = n+64; 723 | FOR(i,n) sm[64 + i] = m[i]; 724 | FOR(i,32) sm[32 + i] = d[32 + i]; 725 | 726 | crypto_hash(r, sm+32, n+32); 727 | reduce(r); 728 | scalarbase(p,r); 729 | pack(sm,p); 730 | 731 | FOR(i,32) sm[i+32] = sk[i+32]; 732 | crypto_hash(h,sm,n + 64); 733 | reduce(h); 734 | 735 | FOR(i,64) x[i] = 0; 736 | FOR(i,32) x[i] = (u64) r[i]; 737 | FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j]; 738 | modL(sm + 32,x); 739 | 740 | return 0; 741 | } 742 | 743 | static int unpackneg(gf r[4],const u8 p[32]) 744 | { 745 | gf t, chk, num, den, den2, den4, den6; 746 | set25519(r[2],gf1); 747 | unpack25519(r[1],p); 748 | S(num,r[1]); 749 | M(den,num,D); 750 | Z(num,num,r[2]); 751 | A(den,r[2],den); 752 | 753 | S(den2,den); 754 | S(den4,den2); 755 | M(den6,den4,den2); 756 | M(t,den6,num); 757 | M(t,t,den); 758 | 759 | pow2523(t,t); 760 | M(t,t,num); 761 | M(t,t,den); 762 | M(t,t,den); 763 | M(r[0],t,den); 764 | 765 | S(chk,r[0]); 766 | M(chk,chk,den); 767 | if (neq25519(chk, num)) M(r[0],r[0],I); 768 | 769 | S(chk,r[0]); 770 | M(chk,chk,den); 771 | if (neq25519(chk, num)) return -1; 772 | 773 | if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]); 774 | 775 | M(r[3],r[0],r[1]); 776 | return 0; 777 | } 778 | 779 | int crypto_sign_open(u8 *m,u64 *mlen,const u8 *sm,u64 n,const u8 *pk) 780 | { 781 | int i; 782 | u8 t[32],h[64]; 783 | gf p[4],q[4]; 784 | 785 | *mlen = -1; 786 | if (n < 64) return -1; 787 | 788 | if (unpackneg(q,pk)) return -1; 789 | 790 | FOR(i,n) m[i] = sm[i]; 791 | FOR(i,32) m[i+32] = pk[i]; 792 | crypto_hash(h,m,n); 793 | reduce(h); 794 | scalarmult(p,q,h); 795 | 796 | scalarbase(q,sm + 32); 797 | add(p,q); 798 | pack(t,p); 799 | 800 | n -= 64; 801 | if (crypto_verify_32(sm, t)) { 802 | FOR(i,n) m[i] = 0; 803 | return -1; 804 | } 805 | 806 | FOR(i,n) m[i] = sm[i + 64]; 807 | *mlen = n; 808 | return 0; 809 | } 810 | --------------------------------------------------------------------------------