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
//! Mnemonic utility CLI commands (camouflage encrypt/decrypt).
use clap::{Args, Subcommand};
use crate::output::{self, CamouflageOutput};
/// Mnemonic utility operations.
#[derive(Args)]
pub(crate) struct MnemonicCommand {
/// The subcommand to execute.
#[command(subcommand)]
command: MnemonicSubcommand,
}
/// Mnemonic utility subcommands.
#[derive(Subcommand)]
enum MnemonicSubcommand {
/// Encrypt a mnemonic into a camouflaged (but valid) BIP-39 mnemonic.
///
/// The output looks like a normal mnemonic and can even generate a
/// real (empty) wallet. Only someone with the password can recover
/// the original mnemonic.
Encrypt {
/// BIP39 mnemonic phrase to camouflage.
#[arg(short, long)]
mnemonic: String,
/// Password used to derive the encryption key.
#[arg(short, long)]
password: String,
},
/// Decrypt a camouflaged mnemonic back to the original.
///
/// Requires the same password that was used during encryption.
Decrypt {
/// Camouflaged BIP-39 mnemonic phrase.
#[arg(short = 'c', long)]
camouflaged: String,
/// Password used during encryption.
#[arg(short, long)]
password: String,
},
}
impl MnemonicCommand {
/// Execute the mnemonic command.
pub(crate) fn execute(self, json: bool) -> Result<(), Box<dyn std::error::Error>> {
match self.command {
MnemonicSubcommand::Encrypt { mnemonic, password } => {
let expanded = kobe::mnemonic::expand(&mnemonic)?;
let camouflaged = kobe::camouflage::encrypt(&expanded, &password)?;
let out = CamouflageOutput {
mode: "encrypt",
words: expanded.split_whitespace().count(),
input: expanded,
output: camouflaged.to_string(),
};
output::render_camouflage(&out, json)?;
}
MnemonicSubcommand::Decrypt {
camouflaged,
password,
} => {
let expanded = kobe::mnemonic::expand(&camouflaged)?;
let original = kobe::camouflage::decrypt(&expanded, &password)?;
let out = CamouflageOutput {
mode: "decrypt",
words: expanded.split_whitespace().count(),
input: expanded.clone(),
output: original.to_string(),
};
output::render_camouflage(&out, json)?;
}
}
Ok(())
}
}