Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VSS client #645

Merged
merged 10 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions mutiny-core/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ struct CustomClaims {
sub: String,
}

pub(crate) struct MutinyAuthClient {
auth: AuthManager,
pub struct MutinyAuthClient {
pub auth: AuthManager,
lnurl_client: Arc<LnUrlClient>,
url: String,
http_client: Client,
Expand Down Expand Up @@ -75,7 +75,11 @@ impl MutinyAuthClient {
self.retrieve_new_jwt().await?;
self.authenticated_request(method, url, body).await
}
_ => Ok(res),
StatusCode::OK | StatusCode::ACCEPTED | StatusCode::CREATED => Ok(res),
code => {
log_error!(self.logger, "Received unexpected status code: {code}");
Err(MutinyError::ConnectionFailed)
}
}
}

Expand Down
59 changes: 55 additions & 4 deletions mutiny-core/src/encrypt.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
use crate::error::MutinyError;
use aes::cipher::block_padding::Pkcs7;
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
use aes::Aes256;
use aes_gcm::Aes256Gcm;
use aes_gcm::{
aead::{generic_array::GenericArray, Aead},
KeyInit,
};
use argon2::Argon2;
use base64;
use bitcoin::secp256k1;
use bitcoin::secp256k1::SecretKey;
use cbc::{Decryptor, Encryptor};
use getrandom::getrandom;
use std::sync::Arc;

type Aes256CbcEnc = Encryptor<Aes256>;
type Aes256CbcDec = Decryptor<Aes256>;

#[derive(Clone)]
pub struct Cipher {
key: Arc<Aes256Gcm>,
Expand Down Expand Up @@ -47,8 +56,8 @@ pub fn encrypt(content: &str, c: Cipher) -> Result<String, MutinyError> {
Ok(base64::encode(&result))
}

pub fn decrypt(encrypted: &str, password: &str) -> Result<String, MutinyError> {
let encrypted = base64::decode(encrypted).map_err(|_| MutinyError::IncorrectPassword)?;
pub fn decrypt_with_password(encrypted: &str, password: &str) -> Result<String, MutinyError> {
let encrypted = base64::decode(encrypted)?;
if encrypted.len() < 12 + 16 {
return Err(MutinyError::IncorrectPassword);
}
Expand Down Expand Up @@ -86,9 +95,40 @@ fn argon2() -> Argon2<'static> {
Argon2::from(params.build().expect("valid params"))
}

pub fn encrypt_with_key(encryption_key: &SecretKey, bytes: &[u8]) -> Vec<u8> {
let iv: [u8; 16] = secp256k1::rand::random();

let cipher = Aes256CbcEnc::new(&encryption_key.secret_bytes().into(), &iv.into());
let mut encrypted: Vec<u8> = cipher.encrypt_padded_vec_mut::<Pkcs7>(bytes);
encrypted.extend(iv);

encrypted
}

pub fn decrypt_with_key(
encryption_key: &SecretKey,
bytes: Vec<u8>,
) -> Result<Vec<u8>, MutinyError> {
if bytes.len() < 16 {
return Err(MutinyError::IncorrectPassword);
}
// split last 16 bytes off as iv
let iv = &bytes[bytes.len() - 16..];
let bytes = &bytes[..bytes.len() - 16];

let cipher = Aes256CbcDec::new(&encryption_key.secret_bytes().into(), iv.into());
let decrypted: Vec<u8> = cipher.decrypt_padded_vec_mut::<Pkcs7>(bytes)?;

Ok(decrypted)
}

#[cfg(test)]
mod tests {
use crate::encrypt::{decrypt, encrypt, encryption_key_from_pass};
use crate::encrypt::{
decrypt_with_key, decrypt_with_password, encrypt, encrypt_with_key,
encryption_key_from_pass,
};
use bitcoin::secp256k1::SecretKey;

#[test]
fn test_encryption() {
Expand All @@ -99,8 +139,19 @@ mod tests {
let encrypted = encrypt(content, cipher).unwrap();
println!("{encrypted}");

let decrypted = decrypt(&encrypted, password).unwrap();
let decrypted = decrypt_with_password(&encrypted, password).unwrap();
println!("{decrypted}");
assert_eq!(content, decrypted);
}

#[test]
fn test_encryption_with_key() {
let key = SecretKey::from_slice(&[1u8; 32]).unwrap();
let content = [6u8; 32].to_vec();

let encrypted = encrypt_with_key(&key, &content);

let decrypted = decrypt_with_key(&key, encrypted).unwrap();
assert_eq!(content, decrypted);
}
}
20 changes: 20 additions & 0 deletions mutiny-core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::esplora::TxSyncError;
use aes::cipher::block_padding::UnpadError;
use bitcoin::Network;
use lightning::ln::peer_handler::PeerHandleError;
use lightning_invoice::payment::PaymentError;
use lightning_invoice::ParseOrSemanticError;
use lightning_rapid_gossip_sync::GraphSyncError;
use std::string::FromUtf8Error;
use thiserror::Error;

#[derive(Error, Debug)]
Expand Down Expand Up @@ -155,6 +157,24 @@ impl MutinyError {
}
}

impl From<UnpadError> for MutinyError {
fn from(_e: UnpadError) -> Self {
Self::IncorrectPassword
}
}

impl From<base64::DecodeError> for MutinyError {
fn from(_e: base64::DecodeError) -> Self {
Self::IncorrectPassword
}
}

impl From<FromUtf8Error> for MutinyError {
fn from(_e: FromUtf8Error) -> Self {
Self::IncorrectPassword
}
}

impl From<aes_gcm::Error> for MutinyError {
fn from(_: aes_gcm::Error) -> Self {
Self::IncorrectPassword
Expand Down
12 changes: 6 additions & 6 deletions mutiny-core/src/gossip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ fn write_gossip_data(
network_graph: &NetworkGraph,
) -> Result<(), MutinyError> {
// Save the last sync timestamp
storage.set_data(GOSSIP_SYNC_TIME_KEY, last_sync_timestamp)?;
storage.set_data(GOSSIP_SYNC_TIME_KEY, last_sync_timestamp, None)?;

// Save the network graph
storage.set_data(NETWORK_GRAPH_KEY, network_graph.encode().to_hex())?;
storage.set_data(NETWORK_GRAPH_KEY, network_graph.encode().to_hex(), None)?;

Ok(())
}
Expand Down Expand Up @@ -362,7 +362,7 @@ pub(crate) fn save_peer_connection_info(
},
};

storage.set_data(key, new_info)?;
storage.set_data(key, new_info, None)?;
Ok(())
}

Expand All @@ -388,7 +388,7 @@ pub(crate) fn set_peer_label(
},
};

storage.set_data(key, new_info)?;
storage.set_data(key, new_info, None)?;
Ok(())
}

Expand All @@ -406,7 +406,7 @@ pub(crate) fn delete_peer_info(
if current.nodes.is_empty() {
storage.delete(&[key])?;
} else {
storage.set_data(key, current)?;
storage.set_data(key, current, None)?;
}
}

Expand All @@ -426,7 +426,7 @@ pub(crate) fn save_ln_peer_info(

// if the new info is different than the current info, we should to save it
if !current.is_some_and(|c| c == new_info) {
storage.set_data(key, new_info)?;
storage.set_data(key, new_info, None)?;
}

Ok(())
Expand Down
14 changes: 7 additions & 7 deletions mutiny-core/src/keymanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,12 @@ pub fn generate_seed(num_words: u8) -> Result<Mnemonic, MutinyError> {
// key secret will be derived from `m/0'`.
pub(crate) fn create_keys_manager<S: MutinyStorage>(
wallet: Arc<OnChainWallet<S>>,
mnemonic: &Mnemonic,
xprivkey: ExtendedPrivKey,
child_index: u32,
logger: Arc<MutinyLogger>,
) -> Result<PhantomKeysManager<S>, MutinyError> {
let context = Secp256k1::new();

let seed = mnemonic.to_seed("");
let xprivkey = ExtendedPrivKey::new_master(wallet.network, &seed)?;
let shared_key = xprivkey.derive_priv(
&context,
&DerivationPath::from(vec![ChildNumber::from_hardened_idx(0)?]),
Expand Down Expand Up @@ -250,6 +248,7 @@ mod tests {
use crate::onchain::OnChainWallet;
use crate::storage::MemoryStorage;
use bip39::Mnemonic;
use bitcoin::util::bip32::ExtendedPrivKey;
use bitcoin::Network;
use esplora_client::Builder;
use std::str::FromStr;
Expand Down Expand Up @@ -277,10 +276,11 @@ mod tests {
logger.clone(),
));
let stop = Arc::new(AtomicBool::new(false));
let xpriv = ExtendedPrivKey::new_master(Network::Testnet, &mnemonic.to_seed("")).unwrap();

let wallet = Arc::new(
OnChainWallet::new(
&mnemonic,
xpriv,
db,
Network::Testnet,
esplora,
Expand All @@ -291,21 +291,21 @@ mod tests {
.unwrap(),
);

let km = create_keys_manager(wallet.clone(), &mnemonic, 1, logger.clone()).unwrap();
let km = create_keys_manager(wallet.clone(), xpriv, 1, logger.clone()).unwrap();
let pubkey = pubkey_from_keys_manager(&km);
assert_eq!(
"02cae09cf2c8842ace44068a5bf3117a494ebbf69a99e79712483c36f97cdb7b54",
pubkey.to_string()
);

let km = create_keys_manager(wallet.clone(), &mnemonic, 2, logger.clone()).unwrap();
let km = create_keys_manager(wallet.clone(), xpriv, 2, logger.clone()).unwrap();
let second_pubkey = pubkey_from_keys_manager(&km);
assert_eq!(
"03fcc9eaaf0b84946ea7935e3bc4f2b498893c2f53e5d2994d6877d149601ce553",
second_pubkey.to_string()
);

let km = create_keys_manager(wallet, &mnemonic, 2, logger).unwrap();
let km = create_keys_manager(wallet, xpriv, 2, logger).unwrap();
let second_pubkey_again = pubkey_from_keys_manager(&km);

assert_eq!(second_pubkey, second_pubkey_again);
Expand Down
Loading
Loading