pub struct KeyManager;Expand description
Main interface for key management operations
This is the recommended API for library integration. It provides simple, safe methods for common key operations.
Implementations§
Source§impl KeyManager
impl KeyManager
Sourcepub fn generate_keypair() -> Keypair
pub fn generate_keypair() -> Keypair
Generate a new Solana keypair
§Example
use fnzero_safe::KeyManager;
use solana_sdk::signature::Signer;
let keypair = KeyManager::generate_keypair();
println!("Public key: {}", keypair.pubkey());Sourcepub fn encrypt_with_password(
private_key: &str,
password: &str,
) -> EncryptionResult<String>
pub fn encrypt_with_password( private_key: &str, password: &str, ) -> EncryptionResult<String>
Encrypt a private key with a password
§Arguments
private_key- The private key in base58 string formatpassword- The password to use for encryption
§Returns
A serialized authenticated v2 keystore envelope
§Example
use fnzero_safe::KeyManager;
let keypair = KeyManager::generate_keypair();
let private_key = keypair.to_base58_string();
let encrypted = KeyManager::encrypt_with_password(
&private_key,
"my_password"
).unwrap();Sourcepub fn encrypt_secret_with_password(
secret: &str,
password: &str,
) -> EncryptionResult<String>
pub fn encrypt_secret_with_password( secret: &str, password: &str, ) -> EncryptionResult<String>
Encrypt arbitrary UTF-8 secret material in an authenticated, password-derived envelope.
Sourcepub fn decrypt_secret_with_password(
encrypted_data: &str,
password: &str,
) -> EncryptionResult<String>
pub fn decrypt_secret_with_password( encrypted_data: &str, password: &str, ) -> EncryptionResult<String>
Decrypt an authenticated UTF-8 secret envelope.
Sourcepub fn decrypt_with_password(
encrypted_data: &str,
password: &str,
) -> EncryptionResult<String>
pub fn decrypt_with_password( encrypted_data: &str, password: &str, ) -> EncryptionResult<String>
Decrypt a private key with a password
§Arguments
encrypted_data- A v2 envelope or legacy v1 ciphertextpassword- The password used for encryption
§Returns
The original private key in base58 string format
§Example
use fnzero_safe::KeyManager;
let keypair = KeyManager::generate_keypair();
let private_key = keypair.to_base58_string();
let encrypted = KeyManager::encrypt_with_password(
&private_key,
"my_password"
).unwrap();
let decrypted = KeyManager::decrypt_with_password(
&encrypted,
"my_password"
).unwrap();
assert_eq!(decrypted, private_key);Sourcepub fn get_public_key(private_key: &str) -> EncryptionResult<String>
pub fn get_public_key(private_key: &str) -> EncryptionResult<String>
Sourcepub fn keypair_to_encrypted_json(
keypair: &Keypair,
password: &str,
) -> EncryptionResult<String>
pub fn keypair_to_encrypted_json( keypair: &Keypair, password: &str, ) -> EncryptionResult<String>
Sourcepub fn mnemonic_to_encrypted_json(
mnemonic: &str,
derivation_path: &str,
password: &str,
) -> EncryptionResult<String>
pub fn mnemonic_to_encrypted_json( mnemonic: &str, derivation_path: &str, password: &str, ) -> EncryptionResult<String>
Encrypt a BIP-39 mnemonic as the primary keystore secret.
Sourcepub fn keypair_from_mnemonic(
mnemonic: &str,
derivation_path: &str,
) -> EncryptionResult<Keypair>
pub fn keypair_from_mnemonic( mnemonic: &str, derivation_path: &str, ) -> EncryptionResult<Keypair>
Derive a Solana keypair from a BIP-39 mnemonic and absolute path.
Sourcepub fn mnemonic_from_encrypted_json(
json_data: &str,
password: &str,
) -> EncryptionResult<Zeroizing<String>>
pub fn mnemonic_from_encrypted_json( json_data: &str, password: &str, ) -> EncryptionResult<Zeroizing<String>>
Decrypt the mnemonic from a v3 mnemonic keystore.
Sourcepub fn keystore_version(json_data: &str) -> EncryptionResult<KeystoreVersion>
pub fn keystore_version(json_data: &str) -> EncryptionResult<KeystoreVersion>
Detect the supported password-keystore format without decrypting it.
Sourcepub fn keypair_from_encrypted_json_v2(
json_data: &str,
password: &str,
) -> EncryptionResult<Keypair>
pub fn keypair_from_encrypted_json_v2( json_data: &str, password: &str, ) -> EncryptionResult<Keypair>
Decrypt a supported v2 keystore, rejecting legacy unauthenticated formats.
Sourcepub fn keypair_from_encrypted_json(
json_data: &str,
password: &str,
) -> EncryptionResult<Keypair>
pub fn keypair_from_encrypted_json( json_data: &str, password: &str, ) -> EncryptionResult<Keypair>
Decrypt a password keystore. Legacy v1 support is read-only.
Examples found in repository?
7fn main() {
8 let args: Vec<String> = std::env::args().collect();
9 let password = if args.len() >= 2 {
10 args[1].clone()
11 } else {
12 eprintln!("Usage: cargo run -p fnzero-safe-core --example test_decrypt <password>");
13 std::process::exit(1);
14 };
15
16 let keystore_path = if args.len() >= 3 {
17 args[2].clone()
18 } else {
19 "config/dev/keystore.json".to_string()
20 };
21
22 let content = std::fs::read_to_string(&keystore_path).unwrap_or_else(|e| {
23 eprintln!("Failed to read {}: {}", keystore_path, e);
24 std::process::exit(1);
25 });
26
27 let data: serde_json::Value = serde_json::from_str(&content).unwrap();
28 let encrypted = data["encrypted_private_key"].as_str().unwrap();
29 let pubkey = data["public_key"].as_str().unwrap();
30
31 eprintln!("Keystore: {}", keystore_path);
32 eprintln!("Public key: {}", pubkey);
33 eprintln!("Password len: {}", password.len());
34
35 let key = generate_encryption_key_simple(&password);
36 eprintln!(
37 "Encryption key: {:02x}{:02x}{:02x}{:02x}...",
38 key[0], key[1], key[2], key[3]
39 );
40
41 match decrypt_key_to_bytes(encrypted, &key) {
42 Ok(bytes) => {
43 let preview: Vec<String> = bytes
44 .iter()
45 .take(16)
46 .map(|b| format!("{:02x}", b))
47 .collect();
48 eprintln!(
49 "Decrypted {} bytes, first 16: {}",
50 bytes.len(),
51 preview.join(" ")
52 );
53 eprintln!("is_ascii: {}", bytes.iter().all(|b| b.is_ascii()));
54 eprintln!("is_utf8: {}", String::from_utf8(bytes.clone()).is_ok());
55
56 // Check if it looks like base58
57 let all_base58 = bytes.iter().all(|b| {
58 let c = *b as char;
59 c.is_ascii()
60 && (('1'..='9').contains(&c)
61 || ('A'..='H').contains(&c)
62 || ('J'..='N').contains(&c)
63 || ('P'..='Z').contains(&c)
64 || c.is_ascii_lowercase())
65 });
66 eprintln!("all_base58_chars: {}", all_base58);
67 }
68 Err(e) => eprintln!("decrypt_key_to_bytes failed: {}", e),
69 }
70
71 // Also try with trimmed password
72 let trimmed = password.trim();
73 if trimmed != password {
74 eprintln!("\n--- Trying trimmed password (len={}) ---", trimmed.len());
75 let key2 = generate_encryption_key_simple(trimmed);
76 eprintln!(
77 "Encryption key: {:02x}{:02x}{:02x}{:02x}...",
78 key2[0], key2[1], key2[2], key2[3]
79 );
80
81 match decrypt_key_to_bytes(encrypted, &key2) {
82 Ok(bytes) => {
83 let preview: Vec<String> = bytes
84 .iter()
85 .take(16)
86 .map(|b| format!("{:02x}", b))
87 .collect();
88 eprintln!(
89 "Decrypted {} bytes, first 16: {}",
90 bytes.len(),
91 preview.join(" ")
92 );
93 eprintln!("is_ascii: {}", bytes.iter().all(|b| b.is_ascii()));
94 eprintln!("is_utf8: {}", String::from_utf8(bytes.clone()).is_ok());
95 }
96 Err(e) => eprintln!("decrypt failed: {}", e),
97 }
98
99 match KeyManager::keypair_from_encrypted_json(&content, trimmed) {
100 Ok(kp) => {
101 println!("SUCCESS with trimmed! keypair: {}", kp.pubkey());
102 if kp.pubkey().to_string() == pubkey {
103 println!("Public key MATCHES!");
104 }
105 }
106 Err(e) => eprintln!("keypair_from_encrypted_json (trimmed) failed: {}", e),
107 }
108 }
109
110 match KeyManager::keypair_from_encrypted_json(&content, &password) {
111 Ok(kp) => {
112 println!("SUCCESS! keypair: {}", kp.pubkey());
113 if kp.pubkey().to_string() == pubkey {
114 println!("Public key MATCHES!");
115 } else {
116 println!("WARNING: mismatch! expected {}", pubkey);
117 }
118 }
119 Err(e) => eprintln!("keypair_from_encrypted_json failed: {}", e),
120 }
121}Sourcepub fn migrate_encrypted_json_to_v2(
json_data: &str,
legacy_password: &str,
new_password: &str,
) -> EncryptionResult<String>
pub fn migrate_encrypted_json_to_v2( json_data: &str, legacy_password: &str, new_password: &str, ) -> EncryptionResult<String>
Explicitly decrypt a legacy v1 keystore and re-encrypt it as v2.
Sourcepub fn migrate_encrypted_json_to_v2_with_public_key(
json_data: &str,
legacy_password: &str,
new_password: &str,
) -> EncryptionResult<(String, String)>
pub fn migrate_encrypted_json_to_v2_with_public_key( json_data: &str, legacy_password: &str, new_password: &str, ) -> EncryptionResult<(String, String)>
Explicitly migrate legacy v1 and return the public key verified from plaintext.