diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-06-24 09:39:18 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-06-24 09:39:18 +0100 |
| commit | 173ab188b326fbe78cfba4ab455a74619f4556bb (patch) | |
| tree | 743a2413c241f7babd4efb336718c510eb743847 /src/key_handling/encryption.rs | |
| parent | 681fdd7683363c62251ecd8dabcc1931a18f4840 (diff) | |
feat(login): store in git config and use cache
replace ngit yaml file config with:
* nsec / ncryptsec / npub in git config in nostr.* namespace
* sql database cache for metadata and relay events
allow different logins to be used for different git repositories by
storing login in local git config
Diffstat (limited to 'src/key_handling/encryption.rs')
| -rw-r--r-- | src/key_handling/encryption.rs | 77 |
1 files changed, 29 insertions, 48 deletions
diff --git a/src/key_handling/encryption.rs b/src/key_handling/encryption.rs index 3f4ee41..3841d50 100644 --- a/src/key_handling/encryption.rs +++ b/src/key_handling/encryption.rs | |||
| @@ -1,46 +1,31 @@ | |||
| 1 | use anyhow::Result; | 1 | use anyhow::Result; |
| 2 | #[cfg(test)] | ||
| 3 | use mockall::*; | ||
| 4 | use nostr::{prelude::*, Keys}; | 2 | use nostr::{prelude::*, Keys}; |
| 5 | 3 | ||
| 6 | #[derive(Default)] | 4 | pub fn encrypt_key(keys: &Keys, password: &str) -> Result<String> { |
| 7 | pub struct Encryptor; | 5 | let log2_rounds: u8 = if password.len() > 20 { |
| 8 | 6 | // we have enough of entropy - no need to spend CPU time adding much more | |
| 9 | #[cfg_attr(test, automock)] | 7 | 1 |
| 10 | pub trait EncryptDecrypt { | 8 | } else { |
| 11 | /// requires less CPU time if the password is long | 9 | println!("this may take a few seconds..."); |
| 12 | fn encrypt_key(&self, keys: &Keys, password: &str) -> Result<String>; | 10 | // default (scrypt::Params::RECOMMENDED_LOG_N) is 17 but 30s is too long to wait |
| 13 | fn decrypt_key(&self, encrypted_key: &str, password: &str) -> Result<Keys>; | 11 | 15 |
| 12 | }; | ||
| 13 | Ok(nostr::nips::nip49::EncryptedSecretKey::new( | ||
| 14 | keys.secret_key()?, | ||
| 15 | password, | ||
| 16 | log2_rounds, | ||
| 17 | KeySecurity::Medium, | ||
| 18 | )? | ||
| 19 | .to_bech32()?) | ||
| 14 | } | 20 | } |
| 15 | 21 | ||
| 16 | /// approach and code adapted from nostr gossip client | 22 | pub fn decrypt_key(encrypted_key: &str, password: &str) -> Result<nostr::Keys> { |
| 17 | impl EncryptDecrypt for Encryptor { | 23 | let encrypted_key = nostr::nips::nip49::EncryptedSecretKey::from_bech32(encrypted_key)?; |
| 18 | fn encrypt_key(&self, keys: &Keys, password: &str) -> Result<String> { | 24 | // to request that log_n gets exposed |
| 19 | let log2_rounds: u8 = if password.len() > 20 { | 25 | if encrypted_key.log_n() > 14 { |
| 20 | // we have enough of entropy - no need to spend CPU time adding much more | 26 | println!("this may take a few seconds..."); |
| 21 | 1 | ||
| 22 | } else { | ||
| 23 | println!("this may take a few seconds..."); | ||
| 24 | // default (scrypt::Params::RECOMMENDED_LOG_N) is 17 but 30s is too long to wait | ||
| 25 | 15 | ||
| 26 | }; | ||
| 27 | Ok(nostr::nips::nip49::EncryptedSecretKey::new( | ||
| 28 | keys.secret_key()?, | ||
| 29 | password, | ||
| 30 | log2_rounds, | ||
| 31 | KeySecurity::Medium, | ||
| 32 | )? | ||
| 33 | .to_bech32()?) | ||
| 34 | } | ||
| 35 | |||
| 36 | fn decrypt_key(&self, encrypted_key: &str, password: &str) -> Result<nostr::Keys> { | ||
| 37 | let encrypted_key = nostr::nips::nip49::EncryptedSecretKey::from_bech32(encrypted_key)?; | ||
| 38 | // to request that log_n gets exposed | ||
| 39 | if encrypted_key.log_n() > 14 { | ||
| 40 | println!("this may take a few seconds..."); | ||
| 41 | } | ||
| 42 | Ok(nostr::Keys::new(encrypted_key.to_secret_key(password)?)) | ||
| 43 | } | 27 | } |
| 28 | Ok(nostr::Keys::new(encrypted_key.to_secret_key(password)?)) | ||
| 44 | } | 29 | } |
| 45 | 30 | ||
| 46 | #[cfg(test)] | 31 | #[cfg(test)] |
| @@ -51,7 +36,7 @@ mod tests { | |||
| 51 | 36 | ||
| 52 | #[test] | 37 | #[test] |
| 53 | fn encrypt_key_produces_string_prefixed_with() -> Result<()> { | 38 | fn encrypt_key_produces_string_prefixed_with() -> Result<()> { |
| 54 | let s = Encryptor.encrypt_key(&nostr::Keys::generate(), TEST_PASSWORD)?; | 39 | let s = encrypt_key(&nostr::Keys::generate(), TEST_PASSWORD)?; |
| 55 | assert!(s.starts_with("ncryptsec")); | 40 | assert!(s.starts_with("ncryptsec")); |
| 56 | Ok(()) | 41 | Ok(()) |
| 57 | } | 42 | } |
| @@ -59,8 +44,7 @@ mod tests { | |||
| 59 | #[test] | 44 | #[test] |
| 60 | // ensures password encryption hasn't changed | 45 | // ensures password encryption hasn't changed |
| 61 | fn decrypts_with_strong_password_from_reference_string() -> Result<()> { | 46 | fn decrypts_with_strong_password_from_reference_string() -> Result<()> { |
| 62 | let encryptor = Encryptor; | 47 | let decrypted_key = decrypt_key(TEST_KEY_1_ENCRYPTED, TEST_PASSWORD)?; |
| 63 | let decrypted_key = encryptor.decrypt_key(TEST_KEY_1_ENCRYPTED, TEST_PASSWORD)?; | ||
| 64 | 48 | ||
| 65 | assert_eq!( | 49 | assert_eq!( |
| 66 | format!( | 50 | format!( |
| @@ -78,8 +62,7 @@ mod tests { | |||
| 78 | #[test] | 62 | #[test] |
| 79 | // ensures password encryption hasn't changed | 63 | // ensures password encryption hasn't changed |
| 80 | fn decrypts_with_weak_password_from_reference_string() -> Result<()> { | 64 | fn decrypts_with_weak_password_from_reference_string() -> Result<()> { |
| 81 | let encryptor = Encryptor; | 65 | let decrypted_key = decrypt_key(TEST_KEY_1_ENCRYPTED_WEAK, TEST_WEAK_PASSWORD)?; |
| 82 | let decrypted_key = encryptor.decrypt_key(TEST_KEY_1_ENCRYPTED_WEAK, TEST_WEAK_PASSWORD)?; | ||
| 83 | 66 | ||
| 84 | assert_eq!( | 67 | assert_eq!( |
| 85 | format!( | 68 | format!( |
| @@ -96,10 +79,9 @@ mod tests { | |||
| 96 | 79 | ||
| 97 | #[test] | 80 | #[test] |
| 98 | fn decrypts_key_encrypted_using_encrypt_key() -> Result<()> { | 81 | fn decrypts_key_encrypted_using_encrypt_key() -> Result<()> { |
| 99 | let encryptor = Encryptor; | ||
| 100 | let key = nostr::Keys::generate(); | 82 | let key = nostr::Keys::generate(); |
| 101 | let s = encryptor.encrypt_key(&key, TEST_PASSWORD)?; | 83 | let s = encrypt_key(&key, TEST_PASSWORD)?; |
| 102 | let newkey = encryptor.decrypt_key(s.as_str(), TEST_PASSWORD)?; | 84 | let newkey = decrypt_key(s.as_str(), TEST_PASSWORD)?; |
| 103 | 85 | ||
| 104 | assert_eq!( | 86 | assert_eq!( |
| 105 | format!("{}", key.secret_key().unwrap().to_bech32().unwrap()), | 87 | format!("{}", key.secret_key().unwrap().to_bech32().unwrap()), |
| @@ -110,10 +92,9 @@ mod tests { | |||
| 110 | 92 | ||
| 111 | #[test] | 93 | #[test] |
| 112 | fn decrypt_key_successfully_decrypts_key_encrypted_using_encrypt_key() -> Result<()> { | 94 | fn decrypt_key_successfully_decrypts_key_encrypted_using_encrypt_key() -> Result<()> { |
| 113 | let encryptor = Encryptor; | ||
| 114 | let key = nostr::Keys::generate(); | 95 | let key = nostr::Keys::generate(); |
| 115 | let s = encryptor.encrypt_key(&key, TEST_PASSWORD)?; | 96 | let s = encrypt_key(&key, TEST_PASSWORD)?; |
| 116 | let newkey = encryptor.decrypt_key(s.as_str(), TEST_PASSWORD)?; | 97 | let newkey = decrypt_key(s.as_str(), TEST_PASSWORD)?; |
| 117 | 98 | ||
| 118 | assert_eq!( | 99 | assert_eq!( |
| 119 | format!("{}", key.secret_key().unwrap().to_bech32().unwrap()), | 100 | format!("{}", key.secret_key().unwrap().to_bech32().unwrap()), |