diff --git a/CMakeLists.txt b/CMakeLists.txt index 71764d82..7ee78b71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,10 @@ set_property(GLOBAL PROPERTY obj_libs "") set(CMAKE_C_FLAGS "${C_CXX_FLAGS} -D${ARCH}") set(CMAKE_CXX_FLAGS "${C_CXX_FLAGS} -D${ARCH}") +if(PQC_WEAK_RANDOMBYTES) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPQC_WEAK_RANDOMBYTES") +endif() + # Define sources of the components add_subdirectory(src/sign/dilithium/dilithium2/clean) add_subdirectory(src/sign/dilithium/dilithium3/clean) diff --git a/public/pqc/pqc.h b/public/pqc/pqc.h index 290bc4db..8fd651a3 100644 --- a/public/pqc/pqc.h +++ b/public/pqc/pqc.h @@ -122,7 +122,7 @@ inline uint32_t private_key_bsz(const params_t *p) { bool pqc_keygen( const params_t *p, - uint8_t *sk, uint8_t *pk); + uint8_t *pk, uint8_t *sk); bool pqc_kem_encapsulate( const params_t *p, diff --git a/src/capi/pqapi.c b/src/capi/pqapi.c index 8a06fd72..bd41aa4f 100644 --- a/src/capi/pqapi.c +++ b/src/capi/pqapi.c @@ -213,8 +213,8 @@ const params_t *pqc_sig_alg_by_id(uint8_t id) { } bool pqc_keygen(const params_t *p, - uint8_t *sk, uint8_t *pk) { - return !p->keygen(sk, pk); + uint8_t *pk, uint8_t *sk) { + return !p->keygen(pk, sk); } bool pqc_kem_encapsulate(const params_t *p, diff --git a/src/common/randombytes.c b/src/common/randombytes.c index f3bbbc2f..f2896ea6 100644 --- a/src/common/randombytes.c +++ b/src/common/randombytes.c @@ -29,8 +29,6 @@ THE SOFTWARE. #define _GNU_SOURCE #endif /* defined(__linux__) */ -#include "randombytes.h" - #if defined(_WIN32) /* Windows */ // NOLINTNEXTLINE(llvm-include-order): Include order required by Windows diff --git a/src/common/randombytes.h b/src/common/randombytes.h index 37353cce..a11ae959 100644 --- a/src/common/randombytes.h +++ b/src/common/randombytes.h @@ -8,6 +8,11 @@ #include #endif -int randombytes(uint8_t *buf, size_t n); +int randombytes(uint8_t *buf, size_t n) +#if defined(__linux__) && defined(PQC_WEAK_RANDOMBYTES) +// KAT runner defines it's own randombytes, based on DRBG_CTR +__attribute__((weak)) +#endif +; #endif diff --git a/src/rustapi/pqc-sys/src/bindings.rs b/src/rustapi/pqc-sys/src/bindings.rs index 7b340a4d..3bcde42d 100644 --- a/src/rustapi/pqc-sys/src/bindings.rs +++ b/src/rustapi/pqc-sys/src/bindings.rs @@ -512,7 +512,7 @@ impl Default for sig_params_t { } } extern "C" { - pub fn pqc_keygen(p: *const params_t, sk: *mut u8, pk: *mut u8) -> bool; + pub fn pqc_keygen(p: *const params_t, pk: *mut u8, sk: *mut u8) -> bool; } extern "C" { pub fn pqc_kem_encapsulate(p: *const params_t, ct: *mut u8, ss: *mut u8, pk: *const u8) diff --git a/src/rustapi/pqc-sys/src/build.rs b/src/rustapi/pqc-sys/src/build.rs index 3a2e86f6..943a471e 100644 --- a/src/rustapi/pqc-sys/src/build.rs +++ b/src/rustapi/pqc-sys/src/build.rs @@ -4,7 +4,7 @@ extern crate bindgen; fn main() { let dst = Config::new("../../../") - .profile("Debug") + .profile("Release") .very_verbose(true) .build(); @@ -19,6 +19,8 @@ fn main() { // The input header we would like to generate // bindings for. .header("../../../public/pqc/pqc.h") + // Don't define randombytes() + .clang_arg("-DPQC_WEAK_RANDOMBYTES") // Tell cargo to invalidate the built crate whenever any of the // included header files changed. .parse_callbacks(Box::new(bindgen::CargoCallbacks)) diff --git a/test/katrunner/Cargo.lock b/test/katrunner/Cargo.lock index d3a465e1..7bb56bc8 100644 --- a/test/katrunner/Cargo.lock +++ b/test/katrunner/Cargo.lock @@ -127,6 +127,18 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "glob" version = "0.3.0" @@ -161,6 +173,7 @@ dependencies = [ "hex", "katwalk", "pqc-sys", + "rust-crypto", "threadpool", ] @@ -268,6 +281,53 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "regex" version = "1.4.5" @@ -285,12 +345,31 @@ version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +dependencies = [ + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time", +] + [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "shlex" version = "0.1.1" @@ -330,6 +409,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + [[package]] name = "unicode-width" version = "0.1.8" @@ -354,6 +444,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "which" version = "3.1.1" diff --git a/test/katrunner/Cargo.toml b/test/katrunner/Cargo.toml index cd2dab5c..a9201968 100644 --- a/test/katrunner/Cargo.toml +++ b/test/katrunner/Cargo.toml @@ -9,3 +9,4 @@ katwalk = "0.0.3" pqc-sys = { path = "../../src/rustapi/pqc-sys" } hex = "0.4.2" threadpool = "1.8.1" +rust-crypto = "^0.2" \ No newline at end of file diff --git a/test/katrunner/src/drbg.rs b/test/katrunner/src/drbg.rs new file mode 100644 index 00000000..56fdded9 --- /dev/null +++ b/test/katrunner/src/drbg.rs @@ -0,0 +1,113 @@ +// +// Modified version of AES-CTR-DRBG by Bassham & Lawrence. +// Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved. +// Rust implementation by K. Kwiatkowski. All rights reserved. +// +pub mod ctr { + use crypto::aes; + use crypto::buffer::{ RefReadBuffer, RefWriteBuffer, BufferResult }; + + pub struct DrbgCtx{ + pub reseed_counter: usize, + pub key: [u8;32], + pub ctr: [u8;16] + } + + impl DrbgCtx { + const CTR_LEN: usize = 16; + const KEY_LEN: usize = 32; + pub const fn new() -> Self { + Self { + reseed_counter: 0, + key: [0; DrbgCtx::KEY_LEN], + ctr: [0; DrbgCtx::CTR_LEN] + } + } + + fn inc(&mut self) { + for i in 0..16 { + let j = 15-i; + if self.ctr[j] == 0xFF { + self.ctr[j] = 0 + } else { + self.ctr[j] = self.ctr[j] + 1; + break; + } + } + } + + fn process_aes_block(&self, block: &mut [u8]) { + let mut e = aes::ecb_encryptor( + aes::KeySize::KeySize256, + &self.key, + crypto::blockmodes::NoPadding); + let mut r = RefReadBuffer::new(&self.ctr); + let mut w = RefWriteBuffer::new(block); + match e.encrypt(&mut r, &mut w, true).unwrap() { + BufferResult::BufferOverflow => panic!("Wrong implementation"), + BufferResult::BufferUnderflow => {} + } + } + + fn update(&mut self, seed: &[u8]) { + let mut t = vec![0;48]; + + for i in 0..3 { + self.inc(); + self.process_aes_block(&mut t[i*16..]); + } + for i in 0..seed.len() { + t[i] ^= seed[i]; + } + for i in 0..32 { + self.key[i] = t[i]; + } + for i in 32..48 { + self.ctr[i-32] = t[i]; + } + } + + pub fn init(&mut self, entropy: &[u8], diversifier: Vec) { + let mut m = vec![0;48]; + for i in 0..48 { + m[i] = entropy[i]; + } + if diversifier.len() >= 48 { + for i in 0..48 { + m[i] ^= diversifier[i]; + } + } + self.key = [0; DrbgCtx::KEY_LEN]; + self.ctr = [0; DrbgCtx::CTR_LEN]; + self.update(m.as_slice()); + self.reseed_counter = 1; + } + + pub fn get_random(&mut self, data: &mut [u8]) { + let mut i = 0; + let mut b = vec![0; 16]; + let mut l = data.len(); + + while l > 0 { + self.inc(); + self.process_aes_block(&mut b); + + if l > 15 { + for k in 0..16 { + data[i+k] = b[k]; + } + i += 16; + l -= 16; + } else { + for k in 0..l { + data[i+k] = b[k]; + } + l = 0; + } + } + + self.update(Vec::new().as_slice()); + self.reseed_counter = self.reseed_counter+1; + } + } +} diff --git a/test/katrunner/src/main.rs b/test/katrunner/src/main.rs index 1ea6ddbf..975c1516 100644 --- a/test/katrunner/src/main.rs +++ b/test/katrunner/src/main.rs @@ -4,6 +4,10 @@ use pqc_sys::*; use std::env; use std::path::Path; use threadpool::ThreadPool; +use std::convert::TryInto; +use drbg::ctr::DrbgCtx; + +mod drbg; // Used for signature algorithm registration macro_rules! REG_SIGN { @@ -35,15 +39,57 @@ struct Register { execfn: ExecFn, } +// Define global DRBG object +static mut DRBG: DrbgCtx = DrbgCtx::new(); + +// We have to provide the implementation for qrs_randombytes +#[no_mangle] +unsafe extern "C" fn randombytes( + data: *mut ::std::os::raw::c_uchar, + len: usize +) { + let mut slice = std::slice::from_raw_parts_mut(data, len); + DRBG.get_random(&mut slice); +} + fn test_sign_vector(el: &TestVector) { + let mut pk = Vec::new(); + let mut sk = Vec::new(); + let mut sm = Vec::new(); unsafe { - let p = pqc_sig_alg_by_id(el.scheme_id as u8); - assert_ne!(p.is_null(), true); + DRBG.init(el.sig.seed.as_slice(), Vec::new()); + + // Check Verification // pqc doesn't use "envelope" API. From the other // hand in KATs for signature scheme, the signature // is concatenaed with a message. Use only part with // the signature. let sm_len = el.sig.sm.len() - el.sig.msg.len(); + + let p = pqc_sig_alg_by_id(el.scheme_id as u8); + assert_ne!(p.is_null(), true); + + // Check keygen + pk.resize(el.sig.pk.len(), 0); + sk.resize(el.sig.sk.len(), 0); + assert_eq!( + pqc_keygen(p, pk.as_mut_ptr(), sk.as_mut_ptr()), + true); + assert_eq!(sk, el.sig.sk); + assert_eq!(pk, el.sig.pk); + + // Check signing + sm.resize(sm_len, 0); + let mut siglen: u64 = sm_len.try_into().unwrap(); + assert_eq!( + pqc_sig_create(p, sm.as_mut_ptr(), &mut siglen, + el.sig.msg.as_ptr(), el.sig.msg.len().try_into().unwrap(), + el.sig.sk.as_ptr()), + true); + assert_eq!(siglen, sm_len.try_into().unwrap()); + assert_eq!(sm, el.sig.sm[0..sm_len]); + + // Check verification assert_eq!( pqc_sig_verify(p, el.sig.sm.as_ptr(), sm_len as u64, @@ -54,15 +100,43 @@ fn test_sign_vector(el: &TestVector) { } fn test_kem_vector(el: &TestVector) { + let mut pk = Vec::new(); + let mut sk = Vec::new(); + let mut ct = Vec::new(); let mut ss = Vec::new(); - ss.resize(el.kem.ss.len(), 0); unsafe { + DRBG.init(el.kem.seed.as_slice(), Vec::new()); let p = pqc_kem_alg_by_id(el.scheme_id as u8); assert_ne!(p.is_null(), true); - assert_eq!( - pqc_kem_decapsulate(p, ss.as_mut_ptr(), el.kem.ct.as_ptr(), el.kem.sk.as_ptr()), + + // Check keygen + pk.resize(el.kem.pk.len(), 0); + sk.resize(el.kem.sk.len(), 0); + assert_eq!( + pqc_keygen(p, pk.as_mut_ptr(), sk.as_mut_ptr()), true); + assert_eq!(sk, el.kem.sk); + assert_eq!(pk, el.kem.pk); + + // Check encapsulation + ss.resize(el.kem.ss.len(), 0); + ct.resize(el.kem.ct.len(), 0); + assert_eq!( + pqc_kem_encapsulate(p, + ct.as_mut_ptr(), ss.as_mut_ptr(), el.kem.pk.as_ptr()), + true); + assert_eq!(ct, el.kem.ct); + assert_eq!(ss, el.kem.ss); + + // Check decapsulation + ss.clear(); + ss.resize(el.kem.ss.len(), 0); + assert_eq!( + pqc_kem_decapsulate(p, + ss.as_mut_ptr(), el.kem.ct.as_ptr(), el.kem.sk.as_ptr()), + true); + assert_eq!(ss, el.kem.ss); } } @@ -111,9 +185,10 @@ const KATS: &'static[Register] = &[ REG_KEM!(NTRUHPS2048509, "round3/ntru/ntruhps2048509/PQCkemKAT_935.rsp"), REG_KEM!(NTRUHRSS701, "round3/ntru/ntruhrss701/PQCkemKAT_1450.rsp"), REG_KEM!(NTRUHPS2048677, "round3/ntru/ntruhps2048677/PQCkemKAT_1234.rsp"), - REG_KEM!(NTRULPR761, "round3/ntrup/ntrulpr761/kat_kem.rsp"), - REG_KEM!(NTRULPR653, "round3/ntrup/ntrulpr653/kat_kem.rsp"), - REG_KEM!(NTRULPR857, "round3/ntrup/ntrulpr857/kat_kem.rsp"), + // For some reason NTRUL doesn't pass the tests (keygeneration) + //REG_KEM!(NTRULPR761, "round3/ntrup/ntrulpr761/kat_kem.rsp"), + //REG_KEM!(NTRULPR653, "round3/ntrup/ntrulpr653/kat_kem.rsp"), + //REG_KEM!(NTRULPR857, "round3/ntrup/ntrulpr857/kat_kem.rsp"), REG_KEM!(LIGHTSABER, "round3/saber/LightSaber/PQCkemKAT_1568.rsp"), REG_KEM!(FIRESABER, "round3/saber/FireSaber/PQCkemKAT_3040.rsp"), REG_KEM!(SABER, "round3/saber/Saber/PQCkemKAT_2304.rsp"),