1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use crate::coinconfig::CoinConfig;
use crate::db::AccountBackup;
use bech32::{FromBase32, ToBase32, Variant};
use chacha20poly1305::aead::{Aead, NewAead};
use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce};
use rand::RngCore;
use rand::rngs::OsRng;
const NONCE: &[u8; 12] = b"unique nonce";
pub fn get_full_backup(coin: u8) -> anyhow::Result<Vec<AccountBackup>> {
let c = CoinConfig::get(coin);
let db = c.db()?;
db.get_full_backup(coin)
}
pub fn restore_full_backup(coin: u8, accounts: &[AccountBackup]) -> anyhow::Result<()> {
let c = CoinConfig::get(coin);
let db = c.db()?;
db.restore_full_backup(accounts)
}
pub fn encrypt_backup(accounts: &[AccountBackup], key: &str) -> anyhow::Result<String> {
let accounts_bin = bincode::serialize(&accounts)?;
let backup = if !key.is_empty() {
let (hrp, key, _) = bech32::decode(key)?;
if hrp != "zwk" {
anyhow::bail!("Invalid backup key")
}
let key = Vec::<u8>::from_base32(&key)?;
let key = Key::from_slice(&key);
let cipher = ChaCha20Poly1305::new(key);
let cipher_text = cipher
.encrypt(Nonce::from_slice(NONCE), &*accounts_bin)
.map_err(|_e| anyhow::anyhow!("Failed to encrypt backup"))?;
base64::encode(cipher_text)
} else {
base64::encode(accounts_bin)
};
Ok(backup)
}
pub fn decrypt_backup(key: &str, backup: &str) -> anyhow::Result<Vec<AccountBackup>> {
let backup = if !key.is_empty() {
let (hrp, key, _) = bech32::decode(key)?;
if hrp != "zwk" {
anyhow::bail!("Not a valid decryption key");
}
let key = Vec::<u8>::from_base32(&key)?;
let key = Key::from_slice(&key);
let cipher = ChaCha20Poly1305::new(key);
let backup = base64::decode(backup)?;
cipher
.decrypt(Nonce::from_slice(NONCE), &*backup)
.map_err(|_e| anyhow::anyhow!("Failed to decrypt backup"))?
} else {
base64::decode(backup)?
};
let accounts: Vec<AccountBackup> = bincode::deserialize(&backup)?;
Ok(accounts)
}
pub fn generate_random_enc_key() -> anyhow::Result<String> {
let mut key = [0u8; 32];
OsRng.fill_bytes(&mut key);
let key = bech32::encode("zwk", key.to_base32(), Variant::Bech32)?;
Ok(key)
}