static char * wallet_encrypt_string(struct wallet *wallet, const char *plaintext, struct crypt_key *ckey) { struct secure_area *sec; char cipherStr[1024]; uint8 *cipher; char *hmac; char *res; size_t clen; size_t len; bool s; ASSERT(plaintext); len = strlen(plaintext) + 1; sec = secure_alloc(len); memcpy(sec->buf, plaintext, len); s = crypt_encrypt(ckey, sec, &cipher, &clen); ASSERT(s); str_snprintf_bytes(cipherStr, sizeof cipherStr, NULL, cipher, clen); hmac = wallet_hmac_string(cipher, clen, wallet->pass); res = safe_asprintf("%s-%s", cipherStr, hmac); free(hmac); free(cipher); secure_free(sec); return res; }
static int wallet_save_keys(struct wallet *wallet) { struct config *cfg; int res; int n; n = hashtable_getnumentries(wallet->hash_keys); Log(LGPFX" saving %u key%s in %sencrypted wallet %s.\n", n, n > 1 ? "s" : "", wallet->pass ? "encrypted" : "NON-", wallet->filename); cfg = config_create(); config_setint64(cfg, n, "numKeys"); if (wallet->pass) { char saltStr[80]; int64 count = 0; bool s; res = RAND_bytes(wallet->ckey->salt, sizeof wallet->ckey->salt); if (res != 1) { res = ERR_get_error(); Log(LGPFX" RAND_bytes failed: %d\n", res); goto exit; } str_snprintf_bytes(saltStr, sizeof saltStr, NULL, wallet->ckey->salt, sizeof wallet->ckey->salt); config_setstring(cfg, saltStr, "encryption.salt"); s = crypt_set_key_from_passphrase(wallet->pass, wallet->ckey, &count); ASSERT(s); ASSERT(count >= CRYPT_NUM_ITERATIONS_OLD); config_setint64(cfg, count, "encryption.numIterations"); } hashtable_for_each(wallet->hash_keys, wallet_save_key_cb, cfg); file_rotate(wallet->filename, 1); res = file_create(wallet->filename); if (res) { Log(LGPFX" failed to create file '%s': %s\n", wallet->filename, strerror(res)); goto exit; } res = file_chmod(wallet->filename, 0600); if (res) { Log(LGPFX" failed to chmod 0600 wallet.dat: %s\n", strerror(res)); goto exit; } res = config_write(cfg, wallet->filename); exit: config_free(cfg); return res; }
void Log_Bytes(const char *pfx, const void *data, size_t len) { char str[16384]; str_snprintf_bytes(str, sizeof str, pfx, data, len); Log("%s\n", str); }
static char * wallet_hmac_string(const uint8 *privkey, size_t privlen, const struct secure_area *passphrase) { char result[128]; uint256 hmac; ASSERT(privkey); crypt_hmac_sha256(privkey, privlen, passphrase->buf, passphrase->len, &hmac); str_snprintf_bytes(result, sizeof result, NULL, hmac.data, sizeof hmac); return safe_strdup(result); }
static void wallet_save_key_cb(const void *key, size_t klen, void *clientData, void *keyData) { struct wallet_key *wkey = (struct wallet_key *)keyData; struct config *wcfg = (struct config *)clientData; uint8 *privkey; uint8 *pubkey; size_t privlen; size_t publen; char *privStr; char pubStr[256]; key_get_privkey(wkey->key, &privkey, &privlen); key_get_pubkey(wkey->key, &pubkey, &publen); privStr = b58_bytes_to_privkey(privkey, privlen); str_snprintf_bytes(pubStr, sizeof pubStr, NULL, pubkey, publen); config_setint64(wcfg, wkey->birth, "key%u.birth", wkey->cfg_idx); config_setstring(wcfg, wkey->desc, "key%u.desc", wkey->cfg_idx); config_setstring(wcfg, pubStr, "key%u.pubkey", wkey->cfg_idx); config_setbool(wcfg, wkey->spendable, "key%u.spendable", wkey->cfg_idx); if (btc->wallet->pass) { char *enc = wallet_encrypt_string(btc->wallet, privStr, btc->wallet->ckey); free(privStr); privStr = enc; } config_setstring(wcfg, privStr, "key%u.privkey", wkey->cfg_idx); free(pubkey); free(privkey); free(privStr); }