From d296f40eae77ab6393c0b6499608e745098a2e8c Mon Sep 17 00:00:00 2001
From: Eli Ribble <eli@theribbles.org>
Date: Wed, 6 Dec 2023 21:16:02 -0700
Subject: [PATCH] Add signature validation.

I also realized I wasn't saving the public and private halves separately so
I'm doing that now too.

God, Rust is great and I'm learning it so slowly.
---
 README.md |  3 ++-
 gongor.rs | 50 +++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index d858cfe..b2ae10c 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,9 @@ Anagram of "Gorgon".
 
 ## Actions
 
- * `cargo run -- create eli.key`: makes a new key.
+ * `cargo run -- create eli.key eli.publickey`: makes a new key.
  * `cargo run -- sign eli.key message.txt [message.sig]`: signs a message, optionally writes the signature to a file.
+ * `cargo run -- validate eli.publickey message.txt message.signed`: validates a signature.
 
 ## TODO
 
diff --git a/gongor.rs b/gongor.rs
index 0e34fdd..b26625f 100644
--- a/gongor.rs
+++ b/gongor.rs
@@ -6,6 +6,10 @@ use rand::rngs::OsRng;
 use ed25519_dalek::SigningKey;
 use ed25519_dalek::Signature;
 use ed25519_dalek::Signer;
+use ed25519_dalek::Verifier;
+use ed25519_dalek::VerifyingKey;
+use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
+
 
 fn main() ->  std::io::Result<()>{
     let action = std::env::args().nth(1).expect("no command given");
@@ -16,7 +20,7 @@ fn main() ->  std::io::Result<()>{
 
 
         let mut keyfile = File::open(&keyfilepath).expect("no file found");
-        let mut keybuffer: [u8; 32] = [0; 32];
+        let mut keybuffer: [u8; 32] = [0; SECRET_KEY_LENGTH];
         keyfile.read(&mut keybuffer).expect("buffer overflow");
         let signing_key: SigningKey = SigningKey::from_bytes(&keybuffer);
 
@@ -38,18 +42,50 @@ fn main() ->  std::io::Result<()>{
         } else {
             println!("Signture: {signature}");
         }
-        return Ok(())
+    } else if action == "validate" {
+        let public_key_filepath = std::env::args().nth(2).expect("no key filepath given");
+        let message_filepath = std::env::args().nth(3).expect("no message filepath given");
+        let signature_filepath = std::env::args().nth(4).expect("no signature filepath given");
+
+        let mut public_keyfile = File::open(&public_key_filepath).expect("no file found");
+        let mut public_keybuffer: [u8; PUBLIC_KEY_LENGTH] = [0; PUBLIC_KEY_LENGTH];
+        public_keyfile.read(&mut public_keybuffer).expect("buffer overflow");
+        let public_key: VerifyingKey = VerifyingKey::from_bytes(&public_keybuffer).expect("Faled to make a key");
+
+        let messagefile= File::open(&message_filepath).expect("no file found");
+        let mut messagereader = BufReader::new(messagefile);
+        let mut messagebuf = Vec::new();
+        messagereader.read_to_end(&mut messagebuf)?;
+
+        let signature_file = File::open(&signature_filepath).expect("no file found");
+        let mut signature_reader = BufReader::new(signature_file);
+        let mut signature_buf: [u8; SIGNATURE_LENGTH] = [0; SIGNATURE_LENGTH];
+        signature_reader.read(&mut signature_buf).expect("buffer overflow");
+        let signature: Signature = Signature::try_from(&signature_buf[..]).expect("not a signature");
+
+        if public_key.verify(&messagebuf, &signature).is_ok() {
+            println!("Yep, that checks out.");
+        } else {
+            println!("Invalid signature.");
+        }
     } else if action == "create" {
-        let keyfilepath = std::env::args().nth(2).expect("no keyfilepath given");
+        let signing_key_filepath = std::env::args().nth(2).expect("no signing key file path given");
+        let verifying_key_filepath = std::env::args().nth(3).expect("no verifying key file path given");
+
         let mut csprng = OsRng;
         let signing_key: SigningKey = SigningKey::generate(&mut csprng);
 
-        println!("Writing new key to {keyfilepath}");
-        let mut file = File::create(keyfilepath)?;
+        println!("Writing new private key to {signing_key_filepath}");
+        let mut file = File::create(signing_key_filepath)?;
         file.write_all(&signing_key.to_bytes())?;
-        return Ok(());
+
+        println!("Writing new public key to {verifying_key_filepath}");
+        let verifying_key: VerifyingKey = signing_key.verifying_key();
+        file = File::create(verifying_key_filepath)?;
+        file.write_all(&verifying_key.to_bytes())?;
+
     } else {
         println!("Unrecognized command {action}");
-        return Ok(());
     }
+    return Ok(());
 }