parent
a439d8674d
commit
42da580ce8
@ -0,0 +1,155 @@
|
||||
#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;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#ifndef __BIP39_H__
|
||||
#define __BIP39_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
const char *mnemonic_encode(uint8_t *data, int len, char *passphrase);
|
||||
|
||||
int mnemonic_decode(const char *mnemonic, uint8_t *data, char *passphrase);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue