From 8a363a6c0add542888edb584306117e3cc329a4b Mon Sep 17 00:00:00 2001 From: "Dr. Maxim Orlovsky" Date: Sun, 20 Nov 2022 17:49:32 +0100 Subject: [PATCH] Signature verification in command line tool --- Cargo.lock | 7 +++++ Cargo.toml | 9 +++--- identity/Cargo.toml | 2 +- src/bin/lnpbp.rs | 69 ++++++++++++++++++++++++++++++++++++--------- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6c0c63a..5ad39a3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,6 +265,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colorize" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc17e449bc7854c50b943d113a98bc0e01dc6585d2c66eaa09ca645ebd8a7e62" + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -550,6 +556,7 @@ dependencies = [ "base58", "base64-compat", "clap", + "colorize", "lnpbp_bech32", "lnpbp_chain", "lnpbp_elgamal", diff --git a/Cargo.toml b/Cargo.toml index e127b060..e0004b48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,16 +32,17 @@ lnpbp_identity = { version = "0.9.0-beta.1", path = "identity", optional = true serde_crate = { package = "serde", version = "1", features = ["derive"], optional = true } serde_with = { version = "1.8", features = ["hex"], optional = true } # serde_with_macros = { version = "~1.2.0", optional = true } # Fix for the problem in 1.3.0 -clap = { version = "~3.1.18", features = ["derive"], optional = true } -serde_yaml = { version = "0.9", optional = true } -serde_json = { version = "1", optional = true } +clap = { version = "~3.1.18", features = ["derive"], optional = true } # Used by cli only +serde_yaml = { version = "0.9", optional = true } # Used by cli only +serde_json = { version = "1", optional = true } # Used by cli only base64-compat = { version = "1", optional = true } # Used by cli only base58 = { version = "0.2", optional = true } # Used by cli only +colorize = { version = "0.1.0", optional = true } # Used by cli only [features] default = ["zip"] all = ["serde", "elgamal", "identity", "zip", "cli"] -cli = ["clap", "serde", "identity", "base64-compat", "base58", "serde_yaml", "serde_json", "amplify/hex"] +cli = ["clap", "serde", "identity", "base64-compat", "base58", "serde_yaml", "serde_json", "amplify/hex", "colorize"] serde = ["serde_crate", "serde_with", "amplify/serde", "lnpbp_bech32/serde", "lnpbp_chain/serde"] identity = ["lnpbp_identity"] diff --git a/identity/Cargo.toml b/identity/Cargo.toml index b4635205..4fe0dbb7 100644 --- a/identity/Cargo.toml +++ b/identity/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] amplify = "4.0.0-alpha.1" -secp256k1 = "0.24.1" +secp256k1 = { version = "0.24.1", features = ["global-context", "rand-std"] } strict_encoding = "2.0.0-alpha.2" bech32 = "0.9.1" crc32fast = "1.3.2" diff --git a/src/bin/lnpbp.rs b/src/bin/lnpbp.rs index c4979af7..624206b7 100644 --- a/src/bin/lnpbp.rs +++ b/src/bin/lnpbp.rs @@ -18,18 +18,22 @@ extern crate amplify; extern crate serde_crate as serde; use amplify::hex; -use std::fmt::{Debug, Display}; -use std::fs; +use std::fmt::{Debug, Display, Formatter}; use std::io::{self, Read, Write}; +use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; use std::str::FromStr; use std::string::FromUtf8Error; +use std::{fmt, fs}; use amplify::hex::{FromHex, ToHex}; use base58::{FromBase58, FromBase58Error, ToBase58}; use clap::Parser; +use colorize::AnsiColor; use lnpbp::{bech32, bech32::Blob, id}; -use lnpbp_identity::{EcAlgo, IdentityCert, IdentitySigner, SigCert}; +use lnpbp_identity::{ + EcAlgo, IdentityCert, IdentitySigner, SigCert, VerifyError, +}; use serde::Serialize; use strict_encoding::{StrictDecode, StrictEncode}; @@ -83,7 +87,7 @@ pub enum IdentityCommand { /// Generate a new identity, saving it to the file Create { /// Curve algorithm to use foe the new identity - #[clap(short, long, default_value = "secp256k1-bip340-xonly")] + #[clap(short, long, default_value = "bip340")] algo: id::EcAlgo, /// File to store the identity in @@ -92,7 +96,7 @@ pub enum IdentityCommand { }, /// Read info about the identity from the file - Read { + Info { /// File containing identity information #[clap()] file: PathBuf, @@ -105,11 +109,11 @@ pub enum IdentityCommand { identity_file: PathBuf, /// Message to sign - #[clap(short, long, conflicts_with = "file")] + #[clap(short, long)] message: Option, /// File to sign - #[clap()] + #[clap(conflicts_with = "message")] message_file: Option, }, @@ -122,15 +126,15 @@ pub enum IdentityCommand { /// A signature to verify #[clap()] - sig: Option, + sig: SigCert, /// Message to verify the signature - #[clap(short, long = "msg", conflicts_with = "file")] + #[clap(short, long = "msg")] message: Option, /// File to verify the signature - #[clap()] - file: Option, + #[clap(conflicts_with = "message")] + message_file: Option, }, /// Encrypt a message @@ -248,7 +252,7 @@ impl FromStr for Format { } } -#[derive(Debug, Display, Error, From)] +#[derive(Display, Error, From)] #[display(inner)] pub enum Error { #[from] @@ -287,6 +291,15 @@ pub enum Error { #[display("can't read data from {0} format")] UnsupportedFormat(Format), + + #[from] + Signature(VerifyError), +} + +impl Debug for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } } fn input_read(data: Vec, format: Format) -> Result @@ -378,13 +391,43 @@ fn main() -> Result<(), Error> { } let id = IdentitySigner::new_bip340(); let fd = fs::File::create(file)?; + let mut perms = fd.metadata()?.permissions(); + perms.set_mode(0o600); + fd.set_permissions(perms)?; id.strict_encode(fd)?; println!("{}", id.cert); + println!("{:?}", id.cert); } - Command::Identity(IdentityCommand::Read { file }) => { + Command::Identity(IdentityCommand::Info { file }) => { let fd = fs::File::open(file)?; let id = IdentitySigner::strict_decode(fd)?; println!("{}", id.cert); + println!("{:?}", id.cert); + } + Command::Identity(IdentityCommand::Sign { + identity_file, + message, + message_file, + }) => { + let fd = fs::File::open(identity_file)?; + let id = IdentitySigner::strict_decode(fd)?; + let mut input = file_str_or_stdin(message_file, message)?; + let mut data = vec![]; + input.read_to_end(&mut data)?; + let sig = id.sign(data); + println!("{}", sig); + } + Command::Identity(IdentityCommand::Verify { + cert, + sig, + message, + message_file, + }) => { + let mut input = file_str_or_stdin(message_file, message)?; + let mut data = vec![]; + input.read_to_end(&mut data)?; + sig.verify(&cert, data)?; + println!("{}", "Signature is valid".green()); } Command::Identity(_) => todo!(), Command::Convert {