Skip to content

Commit 20b97a6

Browse files
committed
Rust: Add API for calculating digests (SHA-256, etc.).
1 parent 6b4b2ed commit 20b97a6

File tree

10 files changed

+603
-18
lines changed

10 files changed

+603
-18
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ doc/doc.css
1717
*.userosscache
1818
*.vsp
1919
*.vspx
20+
21+
# Cargo Junk
22+
Cargo.lock
23+
target/

BUILDING.md

+19-4
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,23 @@ affect building:
1313

1414

1515

16-
Building on Linux and Similar Platforms
17-
=======================================
16+
Building the Rust Library
17+
=========================
18+
19+
*ring*'s Rust crate is named ```rust_ring```. You can build it
20+
using ```cargo build --release``` and you can run the tests
21+
with ```cargo test --release```. When you use ```cargo build```, you don't need
22+
to follow the instructions below to build the C code separately, because
23+
[build.rs](build.rs) does that automatically. Unlike a lot of Rust wrappers
24+
around C libraries, the build script for ```ring``` is implemented using the
25+
msbuild projects (on Windows) or the Makefile (on other platforms). Because
26+
this is a little unusual, I would be particularly grateful if you could report
27+
any problems building (or using) *ring*'s Rust crate.
28+
29+
30+
31+
Building the C Library on Linux and Similar Platforms
32+
=====================================================
1833

1934
There is no ./configure step.
2035

@@ -62,8 +77,8 @@ be in ```$PATH```. Example:
6277

6378

6479

65-
Building on Windows
66-
===================
80+
Building the C Library on Windows
81+
=================================
6782

6883
Note that currently the assembly language optimizations are NOT built on
6984
Windows yet, only because the additions to the project files to support doing

Cargo.toml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
authors = ["Brian Smith <[email protected]>"]
3+
build = "build.rs"
4+
description = "A Rust interface for a simplification of BoringSSL's libcrypto."
5+
license-file = "LICENSE"
6+
name = "rust-ring"
7+
readme = "README.md"
8+
repository = "https://github.com/briansmith/ring"
9+
version = "0.1.0"
10+
11+
[lib]
12+
name = "rust_ring"
13+
crate-type = ["rlib"]
14+
15+
[dependencies]
16+
libc = "0.1"
17+
18+
# TODO: [dev-dependencies]
19+
rustc-serialize = "0.3.15"
20+
21+
[profile.release]
22+
opt-level = 3
23+
debug = false
24+
rpath = false
25+
lto = true
26+
debug-assertions = false
27+
codegen-units = 1

README.md

+27-14
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1111
What is *ring*?
1212
===============
1313

14-
*ring* is a simplified version of BoringSSL that has the following features
15-
removed:
16-
17-
* TLS (libssl)
18-
* X.509 (crypto/pem, crypto/x509, crypto/x509v3)
19-
* ASN.1 (crypto/asn1 and crypto/obj)
14+
*ring* is a simplified version of BoringSSL with C and Rust APIs.
2015

2116
*ring* makes OpenSSL's high-quality, high-performance crypto primitives
2217
conveniently available to new crypto libraries written in safer (than C)
@@ -36,6 +31,32 @@ were developed for *ring* have already been integrated upstream in BoringSSL.
3631

3732

3833

34+
The Rust API
35+
============
36+
The first part of the ```rust_ring``` Rust crate is now available.
37+
38+
Currently only support for cryptographic digests is available. See the
39+
documentation at
40+
https://briansmith.github.io/ring/rust_ring/. Also take a look at the example
41+
program [checkdigest.rs](examples/checkdigest.rs).
42+
43+
See [Building the Rust Library](BUILDING.md#building-the-rust-library) for
44+
instructions on how to build it (hint: it's just ```cargo build```).
45+
46+
47+
48+
The C API
49+
=========
50+
The C API is the same as BoringSSL's, except that its SSL/TLS, X.509, and
51+
ASN.1 APIs have been removed. See
52+
[this](https://github.com/briansmith/ring/blob/wip/BUILDING.md#building-the-c-library-on-windows)
53+
(for Windows) and
54+
[this](https://github.com/briansmith/ring/blob/wip/BUILDING.md#building-the-c-library-on-linux-and-similar-platforms)
55+
(for other platforms) for instructions on how to build *ring* and incorporate
56+
it into your project.
57+
58+
59+
3960
Warning: The ```wip``` Branch Gets Rebased Frequently
4061
=====================================================
4162

@@ -46,14 +67,6 @@ I intend to never rebase, and then I will delete the ```wip``` branch.
4667

4768

4869

49-
Building
50-
========
51-
52-
See [BUILDING.md](BUILDING.md) for instructions on how to build *ring* and
53-
incorporate it into your project.
54-
55-
56-
5770
Contributing
5871
============
5972

build.rs

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2015 Brian Smith.
2+
//
3+
// Permission to use, copy, modify, and/or distribute this software for any
4+
// purpose with or without fee is hereby granted, provided that the above
5+
// copyright notice and this permission notice appear in all copies.
6+
//
7+
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8+
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9+
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10+
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11+
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12+
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13+
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14+
15+
use std::env;
16+
use std::path::Path;
17+
18+
fn main() {
19+
let host_str = env::var("HOST").unwrap();
20+
let host_triple = host_str.split('-').collect::<Vec<&str>>();
21+
22+
let target_str = env::var("TARGET").unwrap();
23+
let target_triple = target_str.split('-').collect::<Vec<&str>>();
24+
25+
let out_dir = env::var("OUT_DIR").unwrap();
26+
27+
let use_msbuild = host_triple.contains(&"msvc") &&
28+
target_triple.contains(&"msvc");
29+
30+
let debug_var = env::var("DEBUG").unwrap();
31+
let is_debug = match debug_var.as_ref() {
32+
"true" => true,
33+
"false" => false,
34+
_ => panic!("$DEBUG is not 'true' or 'false': {}", debug_var)
35+
};
36+
37+
// TODO: deal with link-time-optimization flag.
38+
39+
let command_name;
40+
let args;
41+
let lib_path;
42+
if !use_msbuild {
43+
command_name = "make";
44+
// Environment variables |CC|, |CXX|, etc. will be inherited from this
45+
// process.
46+
let cmake_build_type = "RELWITHDEBINFO"; // TODO: support DEBUG mode.
47+
args = vec![
48+
format!("-j{}", env::var("NUM_JOBS").unwrap()),
49+
format!("TARGET={}", target_str),
50+
format!("CMAKE_BUILD_TYPE={}", cmake_build_type),
51+
format!("BUILD_PREFIX={}/", out_dir),
52+
];
53+
lib_path = Path::new(&out_dir).join("lib");
54+
} else {
55+
// TODO: This assumes that the package is being built under a
56+
// {VS2013,VS2015} {x86,x64} Native Tools Command Prompt. It would be
57+
// nice if we didn't require that to be the case. At least it should be
58+
// documented.
59+
command_name = "msbuild";
60+
let platform = match target_triple[0] {
61+
"i686" => "Win32",
62+
"x86_64" => "x64",
63+
_ => panic!("unexpected ARCH: {}", target_triple[0])
64+
};
65+
let configuration = if is_debug { "Debug" } else { "Release" };
66+
args = vec![
67+
format!("ring.sln"),
68+
format!("/m:{}", env::var("NUM_JOBS").unwrap()),
69+
format!("/p:Platform={}", platform),
70+
format!("/p:Configuration={}", configuration),
71+
format!("/p:OutRootDir={}/", out_dir),
72+
];
73+
lib_path = Path::new(&out_dir).join("lib");
74+
}
75+
76+
if !std::process::Command::new(command_name)
77+
.args(&args)
78+
.status()
79+
.unwrap_or_else(|e| { panic!("failed to execute {}: {}",
80+
command_name, e); })
81+
.success() {
82+
panic!("{} execution failed", command_name);
83+
}
84+
85+
println!("cargo:rustc-link-search=native={}", lib_path.to_str().unwrap());
86+
println!("cargo:rustc-link-lib=static=ring");
87+
}

examples/checkdigest.rs

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright 2015 Brian Smith.
2+
//
3+
// Permission to use, copy, modify, and/or distribute this software for any
4+
// purpose with or without fee is hereby granted, provided that the above
5+
// copyright notice and this permission notice appear in all copies.
6+
//
7+
// THE SOFTWARE IS PROVIDED "AS IS" AND AND THE AUTHORS DISCLAIM ALL WARRANTIES
8+
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9+
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10+
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11+
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12+
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13+
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14+
15+
extern crate rust_ring;
16+
extern crate rustc_serialize;
17+
18+
use rust_ring::{Digest, SHA256, SHA384, SHA512};
19+
use rustc_serialize::hex::FromHex;
20+
use std::error::Error;
21+
use std::io::{Read, Write};
22+
23+
24+
fn print_usage(program_name: &str) {
25+
let program_file_name = std::path::Path::new(program_name)
26+
.file_name().unwrap().to_str().unwrap();
27+
28+
println!(
29+
"Usage: {} sha256|sha384|sha512 <digest value in hex> <filename>\n\
30+
\n\
31+
On success nothing is output, and 0 is returned.\n\
32+
On failure, an error message is printed, and a non-zero value is returned\n\
33+
\n\
34+
Example:\n\
35+
{} sha256 \
36+
def7352915ac84bea5e2ed16f6fff712d35de519799777bf927e2a567ab53b7e \
37+
LICENSE",
38+
program_file_name, program_file_name);
39+
}
40+
41+
fn run(digest_name: &str, expected_digest_hex: &str,
42+
file_path: &std::path::Path) -> Result<(), &'static str> {
43+
enum D {
44+
SHA256(SHA256),
45+
SHA384(SHA384),
46+
SHA512(SHA512),
47+
}
48+
49+
let mut digest = try!(match digest_name {
50+
"sha256" => Ok(D::SHA256(SHA256::new())),
51+
"sha384" => Ok(D::SHA384(SHA384::new())),
52+
"sha512" => Ok(D::SHA512(SHA512::new())),
53+
_ => Err("unsupported digest algorithm")
54+
});
55+
56+
{
57+
let mut file = match std::fs::File::open(file_path) {
58+
Ok(file) => file,
59+
// TODO: don't use panic here.
60+
Err(why) => panic!("couldn't open {}: {}", file_path.display(),
61+
why.description())
62+
};
63+
64+
let mut chunk = vec![0u8; 128 * 1024];
65+
loop {
66+
match file.read(&mut chunk[..]) {
67+
Ok(0) => break,
68+
Ok(bytes_read) => match digest {
69+
D::SHA256(ref mut ctx) => ctx.update(&chunk[0..bytes_read]),
70+
D::SHA384(ref mut ctx) => ctx.update(&chunk[0..bytes_read]),
71+
D::SHA512(ref mut ctx) => ctx.update(&chunk[0..bytes_read]),
72+
},
73+
// TODO: don't use panic here
74+
Err(why) => panic!("couldn't open {}: {}", file_path.display(),
75+
why.description())
76+
}
77+
}
78+
}
79+
80+
let matched = match expected_digest_hex.from_hex() {
81+
Ok(expected) => match digest {
82+
D::SHA256(ref mut ctx) => &expected[..] == &ctx.finish()[..],
83+
D::SHA384(ref mut ctx) => &expected[..] == &ctx.finish()[..],
84+
D::SHA512(ref mut ctx) => &expected[..] == &ctx.finish()[..],
85+
},
86+
Err(_) => panic!("syntactically invalid digest")
87+
};
88+
89+
match matched {
90+
true => Ok(()),
91+
false => Err("digest mismatch") // TODO: calculated digest.
92+
}
93+
}
94+
95+
fn main() {
96+
let args: Vec<String> = std::env::args().collect();
97+
98+
if args.iter().any(|arg| arg == "-h") {
99+
print_usage(&args[0]);
100+
return
101+
} else if args.len() < 4 {
102+
print_usage(&args[0]);
103+
std::process::exit(1);
104+
}
105+
106+
match run(&args[1], &args[2], std::path::Path::new(&args[3])) {
107+
Ok(x) => x,
108+
Err(s) => {
109+
let _ = writeln!(&mut std::io::stderr(), "{}", s);
110+
std::process::exit(1)
111+
}
112+
}
113+
}

include/openssl/md5.h

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ OPENSSL_EXPORT uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out);
9292
* transformation using the state from |md5| and 64 bytes from |block|. */
9393
OPENSSL_EXPORT void MD5_Transform(MD5_CTX *md5, const uint8_t *block);
9494

95+
/* ring: Keep this in sync with |md5_state_st| in digest.rs. */
9596
struct md5_state_st {
9697
uint32_t A, B, C, D;
9798
uint32_t Nl, Nh;

include/openssl/sha.h

+3
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ OPENSSL_EXPORT int SHA1_Final(uint8_t *md, SHA_CTX *sha);
9292
* transformation using the state from |sha| and 64 bytes from |block|. */
9393
OPENSSL_EXPORT void SHA1_Transform(SHA_CTX *sha, const uint8_t *block);
9494

95+
/* ring: Keep this in sync with |sha_state_st| in digest.rs. */
9596
struct sha_state_st {
9697
uint32_t h0, h1, h2, h3, h4;
9798
uint32_t Nl, Nh;
@@ -143,6 +144,7 @@ OPENSSL_EXPORT int SHA256_Final(uint8_t *md, SHA256_CTX *sha);
143144
* transformation using the state from |sha| and 64 bytes from |block|. */
144145
OPENSSL_EXPORT void SHA256_Transform(SHA256_CTX *sha, const uint8_t *data);
145146

147+
/* ring: Keep this in sync with |sha256_state_st| in digest.rs. */
146148
struct sha256_state_st {
147149
uint32_t h[8];
148150
uint32_t Nl, Nh;
@@ -198,6 +200,7 @@ OPENSSL_EXPORT int SHA512_Final(uint8_t *md, SHA512_CTX *sha);
198200
* transformation using the state from |sha| and 64 bytes from |block|. */
199201
OPENSSL_EXPORT void SHA512_Transform(SHA512_CTX *sha, const uint8_t *data);
200202

203+
/* ring: Keep this in sync with |sha512_state_st| in digest.rs. */
201204
struct sha512_state_st {
202205
uint64_t h[8];
203206
uint64_t Nl, Nh;

0 commit comments

Comments
 (0)