Skip to content

Commit

Permalink
Merge pull request vault713#88 from jaspervdm/tx_proof
Browse files Browse the repository at this point in the history
[WIP] Transaction proof
  • Loading branch information
jaspervdm authored Jan 25, 2019
2 parents 107e664 + f5585aa commit a6e120f
Show file tree
Hide file tree
Showing 19 changed files with 521 additions and 151 deletions.
151 changes: 57 additions & 94 deletions src/broker/grinbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use std::sync::{Arc, Mutex};
use std::thread;
use ws::{connect, Sender, Handler, Handshake, Message, CloseCode, Result as WsResult, ErrorKind as WsErrorKind, Error as WsError};
use ws::util::Token;
use colored::*;

use grin_core::libtx::slate::Slate;

use crate::wallet::types::{TxProofErrorKind, TxProof};
use common::{ErrorKind, Result};
use common::crypto::{SecretKey, Signature, verify_signature, sign_challenge, Hex, EncryptedMessage};
use common::crypto::{SecretKey, sign_challenge, Hex, EncryptedMessage};
use contacts::{Address, GrinboxAddress, DEFAULT_GRINBOX_PORT};

use super::types::{Publisher, Subscriber, SubscriptionHandler, CloseReason};
Expand All @@ -21,23 +21,21 @@ pub struct GrinboxPublisher {
address: GrinboxAddress,
secret_key: SecretKey,
protocol_unsecure: bool,
use_encryption: bool,
}

impl GrinboxPublisher {
pub fn new(address: &GrinboxAddress, secert_key: &SecretKey, protocol_unsecure: bool, use_encryption: bool) -> Result<Self> {
pub fn new(address: &GrinboxAddress, secert_key: &SecretKey, protocol_unsecure: bool) -> Result<Self> {
Ok(Self {
address: address.clone(),
secret_key: secert_key.clone(),
protocol_unsecure,
use_encryption
})
}
}

impl Publisher for GrinboxPublisher {
fn post_slate(&self, slate: &Slate, to: &Address) -> Result<()> {
let broker = GrinboxBroker::new(self.protocol_unsecure, self.use_encryption)?;
let broker = GrinboxBroker::new(self.protocol_unsecure)?;
let to = GrinboxAddress::from_str(&to.to_string())?;
broker.post_slate(slate, &to, &self.address, &self.secret_key)?;
Ok(())
Expand All @@ -52,10 +50,10 @@ pub struct GrinboxSubscriber {
}

impl GrinboxSubscriber {
pub fn new(address: &GrinboxAddress, secret_key: &SecretKey, protocol_unsecure: bool, use_encryption: bool) -> Result<Self> {
pub fn new(address: &GrinboxAddress, secret_key: &SecretKey, protocol_unsecure: bool) -> Result<Self> {
Ok(Self {
address: address.clone(),
broker: GrinboxBroker::new(protocol_unsecure, use_encryption)?,
broker: GrinboxBroker::new(protocol_unsecure)?,
secret_key: secret_key.clone(),
})
}
Expand All @@ -80,7 +78,6 @@ impl Subscriber for GrinboxSubscriber {
struct GrinboxBroker {
inner: Arc<Mutex<Option<Sender>>>,
protocol_unsecure: bool,
use_encryption: bool,
}

struct ConnectionMetadata {
Expand All @@ -98,11 +95,10 @@ impl ConnectionMetadata {
}

impl GrinboxBroker {
fn new(protocol_unsecure: bool, use_encryption: bool) -> Result<Self> {
fn new(protocol_unsecure: bool) -> Result<Self> {
Ok(Self {
inner: Arc::new(Mutex::new(None)),
protocol_unsecure,
use_encryption
protocol_unsecure
})
}

Expand All @@ -121,15 +117,10 @@ impl GrinboxBroker {
let response = serde_json::from_str::<ProtocolResponse>(&msg.to_string()).expect("could not parse response!");
match response {
ProtocolResponse::Challenge { str } => {
let slate_str = match self.use_encryption {
true => {
let message = EncryptedMessage::new(serde_json::to_string(&slate).unwrap(), &pkey, &skey).map_err(|_|
WsError::new(WsErrorKind::Protocol, "could not encrypt slate!")
)?;
serde_json::to_string(&message).unwrap()
},
false => serde_json::to_string(&slate).unwrap(),
};
let message = EncryptedMessage::new(serde_json::to_string(&slate).unwrap(), &pkey, &skey).map_err(|_|
WsError::new(WsErrorKind::Protocol, "could not encrypt slate!")
)?;
let slate_str = serde_json::to_string(&message).unwrap();

let mut challenge = String::new();
challenge.push_str(&slate_str);
Expand Down Expand Up @@ -165,7 +156,6 @@ impl GrinboxBroker {
let cloned_address = address.clone();
let cloned_inner = self.inner.clone();
let cloned_handler = handler.clone();
let use_encryption = self.use_encryption;
thread::spawn(move || {
let connection_meta_data = Arc::new(Mutex::new(ConnectionMetadata::new()));
loop {
Expand All @@ -184,7 +174,6 @@ impl GrinboxBroker {
challenge: None,
address: cloned_address.clone(),
secret_key,
use_encryption,
connection_meta_data: cloned_connection_meta_data.clone(),
};
client
Expand Down Expand Up @@ -235,7 +224,6 @@ struct GrinboxClient {
challenge: Option<String>,
address: GrinboxAddress,
secret_key: SecretKey,
use_encryption: bool,
connection_meta_data: Arc<Mutex<ConnectionMetadata>>,
}

Expand All @@ -252,17 +240,6 @@ impl GrinboxClient {
Ok(())
}

fn verify_slate_signature(&self, from: &str, str: &str, challenge: &str, signature: &str) -> Result<()> {
let from = GrinboxAddress::from_str(from)?;
let public_key = from.public_key()?;
let signature = Signature::from_hex(signature)?;
let mut challenge_builder = String::new();
challenge_builder.push_str(str);
challenge_builder.push_str(challenge);
verify_signature(&challenge_builder, &signature, &public_key)?;
Ok(())
}

fn send(&self, request: &ProtocolRequest) -> Result<()> {
let request = serde_json::to_string(&request).unwrap();
self.sender.send(request)?;
Expand Down Expand Up @@ -298,9 +275,14 @@ impl Handler for GrinboxClient {
}

fn on_message(&mut self, msg: Message) -> WsResult<()> {
let response = serde_json::from_str::<ProtocolResponse>(&msg.to_string()).map_err(|_| {
WsError::new(WsErrorKind::Protocol, "could not parse response!")
})?;
let response = match serde_json::from_str::<ProtocolResponse>(&msg.to_string()) {
Ok(x) => x,
Err(_) => {
cli_message!("could not parse response");
return Ok(());
},
};

match response {
ProtocolResponse::Challenge { str } => {
self.challenge = Some(str.clone());
Expand All @@ -309,63 +291,44 @@ impl Handler for GrinboxClient {
})?;
},
ProtocolResponse::Slate { from, str, challenge, signature } => {
if let Ok(_) = self.verify_slate_signature(&from, &str, &challenge, &signature) {
let from = match GrinboxAddress::from_str(&from) {
Ok(x) => x,
Err(_) => {
cli_message!("could not parse address!");
return Ok(());
},
};

let mut slate: Slate = match self.use_encryption {
true => {
let encrypted_message: EncryptedMessage = match serde_json::from_str(&str) {
Ok(x) => x,
Err(_) => {
cli_message!("could not parse encrypted message!");
return Ok(());
},
};
let pkey = match from.public_key() {
Ok(x) => x,
Err(_) => {
cli_message!("could not parse public key!");
return Ok(());
},
};

let decrypted_message = match encrypted_message.decrypt(&pkey, &self.secret_key) {
Ok(x) => x,
Err(_) => {
cli_message!("could not decrypt message!");
return Ok(());
},
};

let slate: Slate = match serde_json::from_str(&decrypted_message) {
Ok(x) => x,
Err(_) => {
cli_message!("could not parse slate!");
return Ok(());
},
};

slate
},
false => match serde_json::from_str(&str) {
Ok(x) => x,
Err(_) => {
cli_message!("could not parse slate!");
return Ok(());
},
},
};
let (mut slate, mut tx_proof) = match TxProof::from_response(from, str, challenge, signature, &self.secret_key) {
Ok(x) => x,
Err(TxProofErrorKind::ParseAddress) => {
cli_message!("could not parse address!");
return Ok(());
},
Err(TxProofErrorKind::ParsePublicKey) => {
cli_message!("could not parse public key!");
return Ok(());
},
Err(TxProofErrorKind::ParseSignature) => {
cli_message!("could not parse signature!");
return Ok(());
},
Err(TxProofErrorKind::VerifySignature) => {
cli_message!("invalid slate signature!");
return Ok(());
},
Err(TxProofErrorKind::ParseEncryptedMessage) => {
cli_message!("could not parse encrypted slate!");
return Ok(());
},
Err(TxProofErrorKind::DecryptionKey) => {
cli_message!("could not determine decryption key!");
return Ok(());
},
Err(TxProofErrorKind::DecryptMessage) => {
cli_message!("could not decrypt slate!");
return Ok(());
},
Err(TxProofErrorKind::ParseSlate) => {
cli_message!("could not parse decrypted slate!");
return Ok(());
},
};

self.handler.lock().unwrap().on_slate(&from, &mut slate);
} else {
cli_message!("{}: received slate with invalid signature!", "ERROR".bright_red());
}
let address = tx_proof.address.clone();
self.handler.lock().unwrap().on_slate(&address, &mut slate, Some(&mut tx_proof));
},
ProtocolResponse::Error { kind: _, description: _ } => {
cli_message!("{}", response);
Expand Down
2 changes: 1 addition & 1 deletion src/broker/keybase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl Subscriber for KeybaseSubscriber {
username: sender.to_string(),
topic: Some(reply_topic),
};
handler.on_slate(address.borrow(), &mut slate);
handler.on_slate(address.borrow(), &mut slate, None);
}
} else {
if !dropped {
Expand Down
4 changes: 3 additions & 1 deletion src/broker/types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use grin_core::libtx::slate::Slate;

use crate::wallet::types::TxProof;

use common::Error;
use contacts::Address;

Expand All @@ -20,7 +22,7 @@ pub trait Subscriber {

pub trait SubscriptionHandler: Send {
fn on_open(&self);
fn on_slate(&self, from: &Address, slate: &mut Slate);
fn on_slate(&self, from: &Address, slate: &mut Slate, proof: Option<&mut TxProof>);
fn on_close(&self, result: CloseReason);
fn on_dropped(&self);
fn on_reestablished(&self);
Expand Down
17 changes: 17 additions & 0 deletions src/cli/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,5 +240,22 @@ impl<'a, 'b> Parser {
SubCommand::with_name("check")
.about("checks a wallet's outputs against a live node, repairing and restoring missing outputs if required")
)
.subcommand(
SubCommand::with_name("export-proof")
.about("exports a transaction proof to a file")
.arg(
Arg::from_usage("-i, --id=<id> 'the transaction id'")
)
.arg(
Arg::from_usage("-f, --file=<file> 'the file to write to'")
)
)
.subcommand(
SubCommand::with_name("verify-proof")
.about("verifies a transaction proof")
.arg(
Arg::from_usage("-f, --file=<file> 'the file to read from'")
)
)
}
}
7 changes: 1 addition & 6 deletions src/common/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fs::File;
use std::fmt;

use grin_wallet::WalletConfig;
use grin_core::global::{ChainTypes, is_mainnet};
use grin_core::global::ChainTypes;

use common::{Result, ErrorKind};
use common::crypto::{SecretKey, PublicKey, public_key_from_secret_key};
Expand All @@ -25,7 +25,6 @@ pub struct Wallet713Config {
pub wallet713_data_path: String,
pub grinbox_domain: String,
pub grinbox_port: Option<u16>,
pub grinbox_e2e_encryption: Option<bool>,
pub grinbox_protocol_unsecure: Option<bool>,
pub grinbox_address_index: Option<u32>,
pub grin_node_uri: Option<String>,
Expand Down Expand Up @@ -108,10 +107,6 @@ impl Wallet713Config {
Ok(wallet_config)
}

pub fn grinbox_e2e_encryption(&self) -> bool {
self.grinbox_e2e_encryption.unwrap_or(is_mainnet())
}

pub fn grinbox_protocol_unsecure(&self) -> bool {
self.grinbox_protocol_unsecure.unwrap_or(false)
}
Expand Down
14 changes: 10 additions & 4 deletions src/common/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,8 @@ impl EncryptedMessage {
})
}

pub fn decrypt(&self, sender_public_key: &PublicKey, secret_key: &SecretKey) -> Result<String> {
let mut encrypted_message = from_hex(self.encrypted_message.clone()).map_err(|_| ErrorKind::Decryption)?;
pub fn key(&self, sender_public_key: &PublicKey, secret_key: &SecretKey) -> Result<[u8; 32]> {
let salt = from_hex(self.salt.clone()).map_err(|_| ErrorKind::Decryption)?;
let nonce = from_hex(self.nonce.clone()).map_err(|_| ErrorKind::Decryption)?;

let secp = Secp256k1::new();
let mut common_secret = sender_public_key.clone();
Expand All @@ -166,7 +164,15 @@ impl EncryptedMessage {

let mut key = [0; 32];
pbkdf2::derive(&digest::SHA512, 100, &salt, common_secret_slice, &mut key);
let opening_key = aead::OpeningKey::new(&aead::CHACHA20_POLY1305, &key)

Ok(key)
}

pub fn decrypt_with_key(&self, key: &[u8; 32]) -> Result<String> {
let mut encrypted_message = from_hex(self.encrypted_message.clone()).map_err(|_| ErrorKind::Decryption)?;
let nonce = from_hex(self.nonce.clone()).map_err(|_| ErrorKind::Decryption)?;

let opening_key = aead::OpeningKey::new(&aead::CHACHA20_POLY1305, key)
.map_err(|_| ErrorKind::Decryption)?;
let decrypted_data = aead::open_in_place(&opening_key, &nonce, &[], 0, &mut encrypted_message)
.map_err(|_| ErrorKind::Decryption)?;
Expand Down
8 changes: 7 additions & 1 deletion src/common/error_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub enum ErrorKind {
TransactionNotCancellable(String),
#[fail(display = "\x1b[31;1merror:\x1b[0m transaction cancellation error: {}", _0)]
TransactionCancellationError(&'static str),
#[fail(display = "\x1b[31;1merror:\x1b[0m transaction doesn't have a proof!")]
TransactionHasNoProof,
#[fail(display = "\x1b[31;1merror:\x1b[0m internal transaction error!")]
LibTX(libtx::ErrorKind),
#[fail(display = "\x1b[31;1merror:\x1b[0m Not enough funds. Required: {}, Available: {}", needed_disp, available_disp)]
Expand Down Expand Up @@ -100,5 +102,9 @@ pub enum ErrorKind {
#[fail(display = "\x1b[31;1merror:\x1b[0m unknown account: {}", 0)]
UnknownAccountLabel(String),
#[fail(display = "\x1b[31;1merror:\x1b[0m http request error")]
HttpRequest
HttpRequest,
#[fail(display = "\x1b[31;1merror:\x1b[0m unable to verify proof")]
VerifyProof,
#[fail(display = "\x1b[31;1merror:\x1b[0m file '{}' not found", 0)]
FileNotFound(String),
}
Loading

0 comments on commit a6e120f

Please sign in to comment.