You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
3.4 KiB
156 lines
3.4 KiB
11 years ago
|
#include <string.h>
|
||
|
|
||
|
#include "bip39.h"
|
||
|
#include "sha2.h"
|
||
|
#include "aes.h"
|
||
|
#include "bip39_english.h"
|
||
|
|
||
|
#define RIJNDAEL_ITERATIONS 10000
|
||
|
|
||
|
void mnemonic_rijndael(uint8_t *data, int len, char *passphrase, bool encrypt)
|
||
|
{
|
||
|
if (len != 16 && len != 24 && len != 32) return;
|
||
|
|
||
|
SHA256_CTX sha_ctx;
|
||
|
aes_ctx ctx;
|
||
|
uint8_t key[32];
|
||
|
int i;
|
||
|
|
||
|
SHA256_Init(&sha_ctx);
|
||
|
SHA256_Update(&sha_ctx, (uint8_t *)"mnemonic", 8);
|
||
|
if (passphrase) {
|
||
|
SHA256_Update(&sha_ctx, (uint8_t *)passphrase, strlen(passphrase));
|
||
|
}
|
||
|
SHA256_Final(key, &sha_ctx);
|
||
|
|
||
|
aes_blk_len(len, &ctx);
|
||
|
|
||
|
if (encrypt) {
|
||
|
aes_enc_key(key, 32, &ctx);
|
||
|
for (i = 0; i < RIJNDAEL_ITERATIONS; i++) {
|
||
|
aes_enc_blk(data, data, &ctx);
|
||
|
}
|
||
|
} else {
|
||
|
aes_dec_key(key, 32, &ctx);
|
||
|
for (i = 0; i < RIJNDAEL_ITERATIONS; i++) {
|
||
|
aes_dec_blk(data, data, &ctx);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define mnemonic_stretch(D, L, P) mnemonic_rijndael((D), (L), (P), true)
|
||
|
#define mnemonic_unstretch(D, L, P) mnemonic_rijndael((D), (L), (P), false)
|
||
|
|
||
|
static char mnemo[24 * 10];
|
||
|
static char bits[256 + 8];
|
||
|
|
||
|
char mnemonic_checksum(uint8_t *data, int len)
|
||
|
{
|
||
|
char r = 0;
|
||
|
int i;
|
||
|
switch (len) {
|
||
|
case 16: // checksum = 4 bits
|
||
|
for (i = 0; i < 16; i++) {
|
||
|
r ^= (data[i] & 0xF0) >> 4;
|
||
|
r ^= (data[i] & 0x0F);
|
||
|
}
|
||
|
break;
|
||
|
case 24: // checksum = 6 bits
|
||
|
for (i = 0; i < 8; i++) {
|
||
|
r ^= (data[3 * i] & 0xFC) >> 2; // xxxxxx__ ________ ________
|
||
|
r ^= ((data[3 * i] & 0x03) << 4) | ((data[3 * i + 1] & 0xF0) >> 4); // ______xx xxxx____ ________
|
||
|
r ^= ((data[3 * i + 1] & 0x0F) << 2) | ((data[3 * i + 2] & 0xC0) >> 6); // ________ ____xxxx xx______
|
||
|
r ^= data[3 * i + 2] & 0x3F; // ________ ________ __xxxxxx
|
||
|
}
|
||
|
break;
|
||
|
case 32: // checksum = 8 bits
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
r ^= data[i];
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
const char *mnemonic_encode(uint8_t *data, int len, char *passphrase)
|
||
|
{
|
||
|
if (len != 16 && len != 24 && len != 32) return 0;
|
||
|
|
||
|
mnemonic_stretch(data, len, passphrase);
|
||
|
|
||
|
int i, j;
|
||
|
for (i = 0; i < len; i++) {
|
||
|
for (j = 0; j < 8; j++) {
|
||
|
bits[8 * i + j] = (data[i] & (1 << (7 - j))) > 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char checksum = mnemonic_checksum(data, len);
|
||
|
for (j = 0; j < (len/4); j++) {
|
||
|
bits[8 * len + j] = (checksum & (1 << ((len / 4 - 1) - j))) > 0;
|
||
|
}
|
||
|
|
||
|
len = len * 3 / 4;
|
||
|
char *p = mnemo;
|
||
|
for (i = 0; i < len; i++) {
|
||
|
int idx = 0;
|
||
|
for (j = 0; j < 11; j++) {
|
||
|
idx += bits[i * 11 + j] << (10 - j);
|
||
|
}
|
||
|
strcpy(p, wordlist[idx]);
|
||
|
p += strlen(wordlist[idx]);
|
||
|
*p = (i < len - 1) ? ' ' : 0;
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
return mnemo;
|
||
|
}
|
||
|
|
||
|
int wordlist_index(const char *word)
|
||
|
{
|
||
|
int i = 0;
|
||
|
while (wordlist[i]) {
|
||
|
if (strcmp(word, wordlist[i]) == 0) return i;
|
||
|
i++;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int mnemonic_decode(const char *mnemonic, uint8_t *data, char *passphrase)
|
||
|
{
|
||
|
strcpy(mnemo, mnemonic);
|
||
|
|
||
|
int i, j, b = 0, len;
|
||
|
char *p = strtok(mnemo, " ");
|
||
|
while (p) {
|
||
|
int idx = wordlist_index(p);
|
||
|
if (idx < 0 || idx > 2047) return 0;
|
||
|
for (j = 0; j < 11; j++) {
|
||
|
bits[b] = (idx & (1 << (10 - j))) > 0;
|
||
|
b++;
|
||
|
}
|
||
|
p = strtok(NULL, " ");
|
||
|
}
|
||
|
if (b != 128 + 4 && b != 192 + 6 && b != 256 + 8) return 0;
|
||
|
|
||
|
len = b / 33 * 4;
|
||
|
|
||
|
for (i = 0; i < len; i++) {
|
||
|
data[i] = 0;
|
||
|
for (j = 0; j < 8; j++) {
|
||
|
data[i] |= bits[8 * i + j] << (7 - j);
|
||
|
}
|
||
|
}
|
||
|
char checksum = 0;
|
||
|
for (j = 0; j < (len/4); j++) {
|
||
|
checksum |= bits[8 * len + j] << ((len / 4 - 1) - j);
|
||
|
}
|
||
|
if (checksum != mnemonic_checksum(data, len)) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
mnemonic_unstretch(data, len, passphrase);
|
||
|
|
||
|
return len;
|
||
|
}
|