Skip to main content

KeyManager

Struct KeyManager 

Source
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

Source

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());
Source

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 format
  • password - 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();
Source

pub fn encrypt_secret_with_password( secret: &str, password: &str, ) -> EncryptionResult<String>

Encrypt arbitrary UTF-8 secret material in an authenticated, password-derived envelope.

Source

pub fn decrypt_secret_with_password( encrypted_data: &str, password: &str, ) -> EncryptionResult<String>

Decrypt an authenticated UTF-8 secret envelope.

Source

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 ciphertext
  • password - 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);
Source

pub fn get_public_key(private_key: &str) -> EncryptionResult<String>

Get public key from a private key

§Arguments
  • private_key - Private key in base58 string format
§Returns

Public key as a base58 string

Source

pub fn keypair_to_encrypted_json( keypair: &Keypair, password: &str, ) -> EncryptionResult<String>

Encrypt a keypair to a JSON keystore format

This creates a fnzero-safe v2 password keystore.

§Arguments
  • keypair - The Solana keypair to encrypt
  • password - The password for encryption
§Returns

JSON string containing the encrypted keystore

Source

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.

Source

pub fn keypair_from_mnemonic( mnemonic: &str, derivation_path: &str, ) -> EncryptionResult<Keypair>

Derive a Solana keypair from a BIP-39 mnemonic and absolute path.

Source

pub fn mnemonic_from_encrypted_json( json_data: &str, password: &str, ) -> EncryptionResult<Zeroizing<String>>

Decrypt the mnemonic from a v3 mnemonic keystore.

Source

pub fn keystore_version(json_data: &str) -> EncryptionResult<KeystoreVersion>

Detect the supported password-keystore format without decrypting it.

Source

pub fn keypair_from_encrypted_json_v2( json_data: &str, password: &str, ) -> EncryptionResult<Keypair>

Decrypt a supported v2 keystore, rejecting legacy unauthenticated formats.

Source

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?
examples/test_decrypt.rs (line 99)
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}
Source

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.

Source

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.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V