Skip to content

Commit

Permalink
Sign entire file, support multiple keys
Browse files Browse the repository at this point in the history
  • Loading branch information
Kijewski committed Sep 12, 2023
1 parent 183a840 commit 0f77cae
Show file tree
Hide file tree
Showing 9 changed files with 358 additions and 907 deletions.
353 changes: 12 additions & 341 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 2 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,9 @@ authors = ["René Kijewski <[email protected]>"]
license = "MIT OR Apache-2.0 WITH LLVM-exception"

[dependencies]
bzip2 = "0.4.4"
clap = { version = "4.4.2", features = ["derive"] }
ed25519-dalek = { version = "2.0.0", features = ["rand_core"] }
flate2 = "1.0.27"
is_executable = "1.0.1"
memmap2 = "0.7.1"
num-traits = "0.2.16"
parse_int = { version = "0.6.0", features = ["implicit-octal"] }
ed25519-dalek = { version = "2.0.0", features = ["digest", "rand_core", "zeroize"] }
pretty-error-debug = "0.3.0"
rand_core = { version = "0.6.4", features = ["getrandom"] }
strum = { version = "0.25.0", features = ["derive"] }
thiserror = "1.0.48"
xz2 = { version = "0.1.7", features = ["static"] }
zip = { version = "0.6.6", features = ["bzip2", "deflate", "zstd"] }
zip = { version = "0.6.6", default-features = false }
58 changes: 37 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
## zipsign: Sign a file with an ed25519 signing key
## zipsign: Sign a file with an ed25519ph signing key

### Install

```text
cargo install --git https://github.com/Kijewski/zipsign
```

### Verify a signature
### Example

Usage: `zipsign verify <VERIFYING_KEY> <FILE> <SIGNATURE>`
```sh
# Generate key pair:
$ zipsign gen-key priv.key pub.key

Arguments:
# ZIP a file and list the content of the ZIP file:
$ 7z a Cargo.lock.zip Cargo.lock
$ 7z l Cargo.lock.zip
Cargo.lock

* `VERIFYING_KEY`: Verifying key
* `FILE`: Signed file
* `SIGNATURE`: Signature file or .zip file generated with "zip" command
# Sign the ZIP file:
$ zipsign sign -k priv.key -i Cargo.lock.zip -o Cargo.lock.tmp -c Cargo.lock --zip
$ mv Cargo.lock.tmp Cargo.lock.zip
$ 7z l Cargo.lock.zip
Cargo.lock

# Verify that the ZIP that the generated signature is valid:
$ zipsign verify -k pub.key -i Cargo.lock.zip -c Cargo.lock
OK

# Verify the signed ZIP file:
$ zipsign verify -k pub.key -i Cargo.lock.zip -c Cargo.lock
```

### Generate key

Expand All @@ -25,28 +40,29 @@ Arguments:
* `PRIVATE_KEY`: Private key file to create
* `VERIFYING_KEY`: Verifying key (public key) file to create

### Zip a file and store its signature in the .zip
### Generate signatures

Usage: `zipsign zip [OPTIONS] <PRIVATE_KEY> <FILE> <ZIP>`
Usage: `zipsign sign -k <PRIVATE_KEY> -i <INPUT> -o <SIGNATURE> [OPTIONS]`

Arguments:

* `PRIVATE_KEY`: Private key
* `FILE`: File to sign
* `ZIP`: ZIP file to (over)write

Options:

* `--method <METHOD>`: Compression method (stored | \*deflated | bzip2 | zstd, \*=default)
* `--level <LEVEL>`: Compression level
* `--permissions <PERMISSIONS>`: Unix-style permissions, default: 0o755 if "FILE" is executable, otherwise 0o644
* `-i`, `--input <INPUT>`: File to verify
* `-o`, `--signature <SIGNATURE>`: Signature to (over)write
* `-k`, `--private-key <PRIVATE_KEY>…`: One or more files containing private keys
* `-c`, `--context <CONTEXT>`: Context (an arbitrary string used to salt the input, e.g. the basename of `<INPUT>`)
* `-z`, `--zip`: `<INPUT>` is a ZIP file. Copy its data into the output
* `-e`, `--end-of-file`: Signatures at end of file (.tar files)

### Generate signature in new file
### Verify a signature

Usage: `zipsign sign <PRIVATE_KEY> <FILE> <SIGNATURE>`
Usage: `zipsign verify -k <VERIFYING_KEY> -i <INPUT> [-o <SIGNATURE>] [OPTIONS]`

Arguments:

* `PRIVATE_KEY`: Private key
* `FILE`: File to sign
* `SIGNATURE`: Signature to (over)write
* `-i`, `--input <INPUT>`: File to verify
* `-o`, `--signature <SIGNATURE>`: Signature file. If absent the signature it is read from `<INPUT>`
* `-k`, `--verifying-key <VERIFYING_KEY>…`: One or more files containing verifying keys
* `-z`, `--zip`: `<INPUT>` is a ZIP file. Copy its data into the output
* `-e`, `--end-of-file`: Signatures at end of file (.tar files)
14 changes: 14 additions & 0 deletions src/generate.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
use std::fs::OpenOptions;
use std::io::Write;
#[cfg(unix)]
use std::os::unix::prelude::OpenOptionsExt;
use std::path::PathBuf;

use clap::Parser;
use ed25519_dalek::SigningKey;
use rand_core::OsRng;

trait NotUnixOpenOptionsExt {
#[inline(always)]
fn mode(&mut self, _mode: u32) -> &mut Self {
self
}
}

#[cfg(not(unix))]
impl NotUnixOpenOptionsExt for OpenOptions {}

pub fn main(args: Cli) -> Result<(), Error> {
let key: SigningKey = SigningKey::generate(&mut OsRng);

let result = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.mode(0o400)
.open(&args.private_key);
let mut f = match result {
Ok(f) => f,
Expand All @@ -26,6 +39,7 @@ pub fn main(args: Cli) -> Result<(), Error> {
.write(true)
.create(true)
.truncate(true)
.mode(0o444)
.open(&args.verifying_key);
let mut f = match result {
Ok(f) => f,
Expand Down
18 changes: 7 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
mod generate;
mod sign;
mod tar;
mod verify;
mod zip;

use clap::{Parser, Subcommand};

// "\x0c\x04\x01" -- form feed, end of text, start of header
// "ed25519ph" -- used algorithm
// "\x00\x00" -- version number in network byte order
const MAGIC_HEADER: &[u8; 14] = b"\x0c\x04\x01ed25519ph\x00\x00";
const HEADER_SIZE: usize = 16;
type SignatureCountLeInt = u16;

fn main() -> Result<(), MainError> {
let args = Cli::parse();
match args.subcommand {
CliSubcommand::GenKey(args) => generate::main(args)?,
CliSubcommand::Verify(args) => verify::main(args)?,
CliSubcommand::Sign(args) => sign::main(args)?,
CliSubcommand::Tar(args) => tar::main(args)?,
CliSubcommand::Zip(args) => zip::main(args)?,
}
Ok(())
}
Expand All @@ -32,9 +35,6 @@ enum CliSubcommand {
GenKey(generate::Cli),
Verify(verify::Cli),
Sign(sign::Cli),
Tar(tar::Cli),
Zip(zip::Cli),
// TODO: verify .tar file
}

#[derive(pretty_error_debug::Debug, thiserror::Error)]
Expand All @@ -45,8 +45,4 @@ enum MainError {
Verify(#[from] verify::Error),
#[error("could not sign file")]
Sign(#[from] sign::Error),
#[error("could not create signed .tar file")]
Tar(#[from] tar::Error),
#[error("could not create signed .zip file")]
Zip(#[from] zip::Error),
}
Loading

0 comments on commit 0f77cae

Please sign in to comment.