`cargo test -p ring` will build and run the tests, but apparently without installing *ring*'s dev-dependencies. Thus, we need to eliminate the dev-dependencies to make that work.
130 lines
4.2 KiB
Rust
130 lines
4.2 KiB
Rust
// Copyright 2015 Brian Smith.
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
|
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
extern crate ring;
|
|
|
|
use ring::*;
|
|
use std::error::Error;
|
|
use std::io::{Read, Write};
|
|
|
|
|
|
fn print_usage(program_name: &str) {
|
|
let program_file_name = std::path::Path::new(program_name)
|
|
.file_name().unwrap().to_str().unwrap();
|
|
|
|
println!(
|
|
"Usage: {} sha256|sha384|sha512 <digest value in hex> <filename>\n\
|
|
\n\
|
|
On success nothing is output, and 0 is returned.\n\
|
|
On failure, an error message is printed, and a non-zero value is returned\n\
|
|
\n\
|
|
Example:\n\
|
|
{} sha256 \
|
|
def7352915ac84bea5e2ed16f6fff712d35de519799777bf927e2a567ab53b7e \
|
|
LICENSE",
|
|
program_file_name, program_file_name);
|
|
}
|
|
|
|
fn run(digest_name: &str, expected_digest_hex: &str,
|
|
file_path: &std::path::Path) -> Result<(), &'static str> {
|
|
let digest_alg = match digest_name {
|
|
"sha256" => &digest::SHA256,
|
|
"sha384" => &digest::SHA384,
|
|
"sha512" => &digest::SHA512,
|
|
_ => { return Err("unsupported digest algorithm"); }
|
|
};
|
|
|
|
let mut ctx = digest::Context::new(digest_alg);
|
|
|
|
{
|
|
let mut file = match std::fs::File::open(file_path) {
|
|
Ok(file) => file,
|
|
// TODO: don't use panic here.
|
|
Err(why) => panic!("couldn't open {}: {}", file_path.display(),
|
|
why.description())
|
|
};
|
|
|
|
let mut chunk = vec![0u8; 128 * 1024];
|
|
loop {
|
|
match file.read(&mut chunk[..]) {
|
|
Ok(0) => break,
|
|
Ok(bytes_read) => ctx.update(&chunk[0..bytes_read]),
|
|
// TODO: don't use panic here
|
|
Err(why) => panic!("couldn't open {}: {}", file_path.display(),
|
|
why.description())
|
|
}
|
|
}
|
|
}
|
|
|
|
let actual_digest = ctx.finish();
|
|
|
|
let matched = match from_hex(&expected_digest_hex) {
|
|
Ok(expected) => actual_digest.as_ref() == &expected[..],
|
|
Err(msg) => panic!("syntactically invalid digest: {} in {}", msg,
|
|
&expected_digest_hex),
|
|
};
|
|
|
|
match matched {
|
|
true => Ok(()),
|
|
false => Err("digest mismatch") // TODO: calculated digest.
|
|
}
|
|
}
|
|
|
|
pub fn from_hex(hex_str: &str) -> Result<Vec<u8>, String> {
|
|
if hex_str.len() % 2 != 0 {
|
|
return Err(
|
|
String::from("Hex string does not have an even number of digits"));
|
|
}
|
|
|
|
fn from_hex_digit(d: u8) -> Result<u8, String> {
|
|
if d >= b'0' && d <= b'9' {
|
|
Ok(d - b'0')
|
|
} else if d >= b'a' && d <= b'f' {
|
|
Ok(d - b'a' + 10u8)
|
|
} else if d >= b'A' && d <= b'F' {
|
|
Ok(d - b'A' + 10u8)
|
|
} else {
|
|
Err(format!("Invalid hex digit '{}'", d as char))
|
|
}
|
|
}
|
|
|
|
let mut result = Vec::with_capacity(hex_str.len() / 2);
|
|
for digits in hex_str.as_bytes().chunks(2) {
|
|
let hi = try!(from_hex_digit(digits[0]));
|
|
let lo = try!(from_hex_digit(digits[1]));
|
|
result.push((hi * 0x10) | lo);
|
|
}
|
|
Ok(result)
|
|
}
|
|
|
|
fn main() {
|
|
let args: Vec<String> = std::env::args().collect();
|
|
|
|
if args.iter().any(|arg| arg == "-h") {
|
|
print_usage(&args[0]);
|
|
return
|
|
} else if args.len() < 4 {
|
|
print_usage(&args[0]);
|
|
std::process::exit(1);
|
|
}
|
|
|
|
match run(&args[1], &args[2], std::path::Path::new(&args[3])) {
|
|
Ok(x) => x,
|
|
Err(s) => {
|
|
let _ = writeln!(&mut std::io::stderr(), "{}", s);
|
|
std::process::exit(1)
|
|
}
|
|
}
|
|
}
|