Initial commit

This commit is contained in:
Jean-Michel Picod
2020-01-28 15:09:10 +01:00
commit f91d2fd3db
90 changed files with 31123 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
[package]
name = "crypto"
version = "0.1.0"
authors = [
"Fabian Kaczmarczyck <kaczmarczyck@google.com>",
"Guillaume Endignoux <guillaumee@google.com>",
"Jean-Michel Picod <jmichel@google.com>",
]
license = "Apache-2.0"
edition = "2018"
[dependencies]
libtock = { path = "../../third_party/libtock-rs" }
cbor = { path = "../cbor" }
arrayref = "0.3.5"
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
byteorder = { version = "1", default-features = false }
hex = { version = "0.3.2", default-features = false, optional = true }
ring = { version = "0.14.6", optional = true }
untrusted = { version = "0.6.2", optional = true }
rand = { version = "0.6.5", optional = true }
serde = { version = "1.0", optional = true, features = ["derive"] }
serde_json = { version = "1.0", optional = true }
regex = { version = "1", optional = true }
[features]
std = ["cbor/std", "hex", "rand", "ring", "untrusted", "serde", "serde_json", "regex"]
derive_debug = []
with_ctap1 = []

View File

@@ -0,0 +1,541 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::util::{xor_block_16, Block16};
use super::{Decrypt16BytesBlock, Encrypt16BytesBlock};
/** A portable and naive textbook implementation of AES-256 **/
type Word = [u8; 4];
/** This structure caches the round keys, to avoid re-computing the key schedule for each block. **/
pub struct EncryptionKey {
enc_round_keys: [Block16; 15],
}
pub struct DecryptionKey {
dec_round_keys: [Block16; 15],
}
impl EncryptionKey {
// Computes the round keys.
pub fn new(key: &[u8; 32]) -> EncryptionKey {
let mut enc_round_keys = [Default::default(); 15];
enc_round_keys[0] = *array_ref![key, 0, 16];
enc_round_keys[1] = *array_ref![key, 16, 16];
let mut word: Word = *array_ref![enc_round_keys[1], 12, 4];
for i in 2..15 {
if i & 1 == 0 {
rotword(&mut word);
subword(&mut word);
word[0] ^= RCON[(i >> 1) - 1];
} else {
subword(&mut word);
}
for j in 0..4 {
xorword(&mut word, *array_ref![enc_round_keys[i - 2], 4 * j, 4]);
*array_mut_ref![enc_round_keys[i], 4 * j, 4] = word;
}
}
EncryptionKey { enc_round_keys }
}
}
impl Encrypt16BytesBlock for EncryptionKey {
// Encrypt an AES block in place.
fn encrypt_block(&self, block: &mut Block16) {
add_round_key(block, &self.enc_round_keys[0]);
for i in 1..14 {
aes_enc(block, &self.enc_round_keys[i]);
}
aes_enc_last(block, &self.enc_round_keys[14]);
}
}
impl DecryptionKey {
// Computes the round keys.
pub fn new(key: &EncryptionKey) -> DecryptionKey {
let mut dec_round_keys = [Default::default(); 15];
dec_round_keys[0] = key.enc_round_keys[14];
#[allow(clippy::needless_range_loop)]
for i in 1..14 {
let rk = &mut dec_round_keys[i];
*rk = key.enc_round_keys[14 - i];
inv_mix_columns(rk);
}
dec_round_keys[14] = key.enc_round_keys[0];
DecryptionKey { dec_round_keys }
}
}
impl Decrypt16BytesBlock for DecryptionKey {
// Decrypt an AES block in place.
fn decrypt_block(&self, block: &mut Block16) {
add_round_key(block, &self.dec_round_keys[0]);
for i in 1..14 {
aes_dec(block, &self.dec_round_keys[i]);
}
aes_dec_last(block, &self.dec_round_keys[14]);
}
}
/** Helper functions for the key schedule **/
fn rotword(word: &mut Word) {
let tmp = word[0];
word[0] = word[1];
word[1] = word[2];
word[2] = word[3];
word[3] = tmp;
}
fn subword(word: &mut Word) {
for byte in word.iter_mut() {
*byte = SBOX[*byte as usize];
}
}
fn xorword(word: &mut Word, src: Word) {
for i in 0..4 {
word[i] ^= src[i];
}
}
/** Helper functions for the encryption **/
fn aes_enc(block: &mut Block16, rkey: &Block16) {
sub_bytes(block);
shift_rows(block);
mix_columns(block);
add_round_key(block, rkey);
}
fn aes_dec(block: &mut Block16, rkey: &Block16) {
inv_shift_rows(block);
inv_sub_bytes(block);
inv_mix_columns(block);
add_round_key(block, rkey);
}
fn aes_enc_last(block: &mut Block16, rkey: &Block16) {
sub_bytes(block);
shift_rows(block);
add_round_key(block, rkey);
}
fn aes_dec_last(block: &mut Block16, rkey: &Block16) {
inv_shift_rows(block);
inv_sub_bytes(block);
add_round_key(block, rkey);
}
#[inline(always)]
fn add_round_key(block: &mut Block16, rkey: &Block16) {
xor_block_16(block, rkey);
}
fn sub_bytes(block: &mut Block16) {
for byte in block.iter_mut() {
*byte = SBOX[*byte as usize];
}
}
fn inv_sub_bytes(block: &mut Block16) {
for byte in block.iter_mut() {
*byte = SBOX_INV[*byte as usize];
}
}
fn shift_rows(block: &mut Block16) {
let tmp = block[1];
block[1] = block[5];
block[5] = block[9];
block[9] = block[13];
block[13] = tmp;
block.swap(2, 10);
block.swap(6, 14);
let tmp = block[3];
block[3] = block[15];
block[15] = block[11];
block[11] = block[7];
block[7] = tmp;
}
fn inv_shift_rows(block: &mut Block16) {
let tmp = block[7];
block[7] = block[11];
block[11] = block[15];
block[15] = block[3];
block[3] = tmp;
block.swap(2, 10);
block.swap(6, 14);
let tmp = block[13];
block[13] = block[9];
block[9] = block[5];
block[5] = block[1];
block[1] = tmp;
}
// multiplication by 2 in GF(2^256)
fn mul2(x: u8) -> u8 {
(x << 1) ^ (((x >> 7) & 1) * 0x1b)
}
// multiplication by 3 in GF(2^256)
fn mul3(x: u8) -> u8 {
mul2(x) ^ x
}
fn mix_columns(block: &mut Block16) {
for i in 0..4 {
let x0 = block[4 * i];
let x1 = block[4 * i + 1];
let x2 = block[4 * i + 2];
let x3 = block[4 * i + 3];
block[4 * i] = mul2(x0) ^ mul3(x1) ^ x2 ^ x3;
block[4 * i + 1] = x0 ^ mul2(x1) ^ mul3(x2) ^ x3;
block[4 * i + 2] = x0 ^ x1 ^ mul2(x2) ^ mul3(x3);
block[4 * i + 3] = mul3(x0) ^ x1 ^ x2 ^ mul2(x3);
}
}
// multiplication by 9 in GF(2^256)
fn mul9(x: u8) -> u8 {
mul2(mul2(mul2(x))) ^ x
}
// multiplication by 11 in GF(2^256)
fn mul11(x: u8) -> u8 {
mul2(mul2(mul2(x)) ^ x) ^ x
}
// multiplication by 13 in GF(2^256)
fn mul13(x: u8) -> u8 {
mul2(mul2(mul2(x) ^ x)) ^ x
}
// multiplication by 14 in GF(2^256)
fn mul14(x: u8) -> u8 {
mul2(mul2(mul2(x) ^ x) ^ x)
}
fn inv_mix_columns(block: &mut Block16) {
for i in 0..4 {
let x0 = block[4 * i];
let x1 = block[4 * i + 1];
let x2 = block[4 * i + 2];
let x3 = block[4 * i + 3];
block[4 * i] = mul14(x0) ^ mul11(x1) ^ mul13(x2) ^ mul9(x3);
block[4 * i + 1] = mul9(x0) ^ mul14(x1) ^ mul11(x2) ^ mul13(x3);
block[4 * i + 2] = mul13(x0) ^ mul9(x1) ^ mul14(x2) ^ mul11(x3);
block[4 * i + 3] = mul11(x0) ^ mul13(x1) ^ mul9(x2) ^ mul14(x3);
}
}
/** Constants **/
// Constants used in the key schedule.
const RCON: [u8; 7] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40];
// AES substitution box.
const SBOX: [u8; 256] = [
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
];
const SBOX_INV: [u8; 256] = [
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
];
#[cfg(test)]
mod test {
use super::*;
// Test vector from the NIST obtained at:
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_ECB.pdf
#[test]
fn test_nist_aes256_ecb_encrypt() {
let src = b"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\
\xe9\x3d\x7e\x11\x73\x93\x17\x2a";
let key = b"\x60\x3d\xeb\x10\x15\xca\x71\xbe\
\x2b\x73\xae\xf0\x85\x7d\x77\x81\
\x1f\x35\x2c\x07\x3b\x61\x08\xd7\
\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
let expected = b"\xf3\xee\xd1\xbd\xb5\xd2\xa0\x3c\
\x06\x4b\x5a\x7e\x3d\xb1\x81\xf8";
let mut dst: Block16 = Default::default();
dst.copy_from_slice(src);
EncryptionKey::new(key).encrypt_block(&mut dst);
assert_eq!(&dst, expected);
}
#[test]
fn test_nist_aes256_ecb_decrypt() {
let src = b"\xf3\xee\xd1\xbd\xb5\xd2\xa0\x3c\
\x06\x4b\x5a\x7e\x3d\xb1\x81\xf8";
let key = b"\x60\x3d\xeb\x10\x15\xca\x71\xbe\
\x2b\x73\xae\xf0\x85\x7d\x77\x81\
\x1f\x35\x2c\x07\x3b\x61\x08\xd7\
\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
let expected = b"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\
\xe9\x3d\x7e\x11\x73\x93\x17\x2a";
let mut dst: Block16 = Default::default();
dst.copy_from_slice(src);
DecryptionKey::new(&EncryptionKey::new(key)).decrypt_block(&mut dst);
assert_eq!(&dst, expected);
}
#[test]
fn test_encrypt_decrypt() {
// Test that decrypt_block is the inverse of encrypt_block for a bunch of block values.
let key_bytes = b"\x60\x3d\xeb\x10\x15\xca\x71\xbe\
\x2b\x73\xae\xf0\x85\x7d\x77\x81\
\x1f\x35\x2c\x07\x3b\x61\x08\xd7\
\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
let enc_key = EncryptionKey::new(key_bytes);
let dec_key = DecryptionKey::new(&enc_key);
let mut block: Block16 = [0; 16];
for i in 0..=255 {
for j in 0..16 {
block[j] = (i + j) as u8;
}
let expected = block;
enc_key.encrypt_block(&mut block);
dec_key.decrypt_block(&mut block);
assert_eq!(block, expected);
}
}
#[test]
fn test_sbox_is_permutation() {
let mut image = [false; 256];
for &sboxed in SBOX.iter() {
assert_eq!(image[sboxed as usize], false);
image[sboxed as usize] = true;
}
}
#[test]
fn test_sbox_inv_is_permutation() {
let mut image = [false; 256];
for &sboxed in SBOX_INV.iter() {
assert_eq!(image[sboxed as usize], false);
image[sboxed as usize] = true;
}
}
#[test]
fn test_sbox_inverse() {
for i in 0..=255 {
assert_eq!(SBOX_INV[SBOX[i as usize] as usize], i);
}
}
#[test]
fn test_subbytes() {
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let expected = [
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
];
sub_bytes(&mut block);
assert_eq!(block, expected);
}
#[test]
fn test_subbytes_inv() {
// Test that inv_sub_bytes is the inverse of sub_bytes for a bunch of block values.
let mut block: Block16 = [0; 16];
for i in 0..=255 {
for j in 0..16 {
block[j] = (i + j) as u8;
}
let expected = block;
sub_bytes(&mut block);
inv_sub_bytes(&mut block);
assert_eq!(block, expected);
}
}
#[test]
fn test_shift_rows() {
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let expected = [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11];
shift_rows(&mut block);
assert_eq!(block, expected);
}
#[test]
fn test_shift_rows_inv() {
// Test that inv_shift_rows is the inverse of shift_rows for a bunch of block values.
let mut block: Block16 = [0; 16];
for i in 0..=255 {
for j in 0..16 {
block[j] = (i + j) as u8;
}
let expected = block;
shift_rows(&mut block);
inv_shift_rows(&mut block);
assert_eq!(block, expected);
}
}
#[test]
fn test_mix_columns_inv() {
// Test that inv_mix_columns is the inverse of mix_columns for a bunch of block values.
let mut block: Block16 = [0; 16];
for i in 0..=255 {
for j in 0..16 {
block[j] = (i + j) as u8;
}
let expected = block;
mix_columns(&mut block);
inv_mix_columns(&mut block);
assert_eq!(block, expected);
}
}
/** Comparison with AES-NI instructions for CPUs that support them **/
#[cfg(all(target_arch = "x86_64", target_feature = "aes"))]
mod aesni {
use super::super::*;
fn aes_enc_ni(block: &mut Block16, rkey: &Block16) {
use core::arch::x86_64::{__m128i, _mm_aesenc_si128};
unsafe {
let block_mm: __m128i = core::mem::transmute(*block);
let rkey_mm: __m128i = core::mem::transmute(*rkey);
let encrypted_mm: __m128i = _mm_aesenc_si128(block_mm, rkey_mm);
*block = core::mem::transmute(encrypted_mm)
}
}
fn aes_enc_last_ni(block: &mut Block16, rkey: &Block16) {
use core::arch::x86_64::{__m128i, _mm_aesenclast_si128};
unsafe {
let block_mm: __m128i = core::mem::transmute(*block);
let rkey_mm: __m128i = core::mem::transmute(*rkey);
let encrypted_mm: __m128i = _mm_aesenclast_si128(block_mm, rkey_mm);
*block = core::mem::transmute(encrypted_mm)
}
}
fn aes_dec_ni(block: &mut Block16, rkey: &Block16) {
use core::arch::x86_64::{__m128i, _mm_aesdec_si128};
unsafe {
let block_mm: __m128i = core::mem::transmute(*block);
let rkey_mm: __m128i = core::mem::transmute(*rkey);
let decrypted_mm: __m128i = _mm_aesdec_si128(block_mm, rkey_mm);
*block = core::mem::transmute(decrypted_mm)
}
}
fn aes_dec_last_ni(block: &mut Block16, rkey: &Block16) {
use core::arch::x86_64::{__m128i, _mm_aesdeclast_si128};
unsafe {
let block_mm: __m128i = core::mem::transmute(*block);
let rkey_mm: __m128i = core::mem::transmute(*rkey);
let decrypted_mm: __m128i = _mm_aesdeclast_si128(block_mm, rkey_mm);
*block = core::mem::transmute(decrypted_mm)
}
}
#[test]
fn test_aes_enc_ni() {
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let mut block_ni = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let rkey = [
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
];
aes_enc(&mut block, &rkey);
aes_enc_ni(&mut block_ni, &rkey);
assert_eq!(block, block_ni);
}
#[test]
fn test_aes_enc_last_ni() {
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let mut block_ni = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let rkey = [
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
];
aes_enc_last(&mut block, &rkey);
aes_enc_last_ni(&mut block_ni, &rkey);
assert_eq!(block, block_ni);
}
#[test]
fn test_aes_dec_ni() {
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let mut block_ni = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let rkey = [
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
];
aes_dec(&mut block, &rkey);
aes_dec_ni(&mut block_ni, &rkey);
assert_eq!(block, block_ni);
}
#[test]
fn test_aes_dec_last_ni() {
let mut block = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let mut block_ni = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let rkey = [
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
];
aes_dec_last(&mut block, &rkey);
aes_dec_last_ni(&mut block_ni, &rkey);
assert_eq!(block, block_ni);
}
}
}

258
libraries/crypto/src/cbc.rs Normal file
View File

@@ -0,0 +1,258 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::util::{xor_block_16, Block16};
use super::{Decrypt16BytesBlock, Encrypt16BytesBlock};
pub fn cbc_encrypt<K>(key: &K, mut iv: Block16, blocks: &mut [Block16])
where
K: Encrypt16BytesBlock,
{
for block in blocks {
xor_block_16(block, &iv);
key.encrypt_block(block);
iv = *block;
}
}
pub fn cbc_decrypt<K>(key: &K, mut iv: Block16, blocks: &mut [Block16])
where
K: Decrypt16BytesBlock,
{
for block in blocks {
let tmp = *block;
key.decrypt_block(block);
xor_block_16(block, &iv);
iv = tmp;
}
}
#[cfg(test)]
mod test {
use super::super::aes256;
use super::*;
#[test]
fn test_cbc_encrypt_decrypt() {
// Test that cbc_decrypt is the inverse of cbc_encrypt for a bunch of block values.
let enc_key = aes256::EncryptionKey::new(&[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f,
]);
let dec_key = aes256::DecryptionKey::new(&enc_key);
for len in 0..16 {
let mut blocks: Vec<Block16> = vec![Default::default(); len];
for i in 0..len {
for j in 0..16 {
blocks[i][j] = ((len + i) * 16 + j) as u8;
}
}
let iv = [
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
];
let expected = blocks.clone();
cbc_encrypt(&enc_key, iv, &mut blocks);
cbc_decrypt(&dec_key, iv, &mut blocks);
assert_eq!(blocks, expected);
}
}
#[test]
fn test_cbc_encrypt_1block_zero_iv() {
let key = aes256::EncryptionKey::new(&[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f,
]);
let mut blocks = [[
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
]];
let iv = [0; 16];
cbc_encrypt(&key, iv, &mut blocks);
let mut expected = [
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
];
key.encrypt_block(&mut expected);
assert_eq!(blocks, [expected]);
}
#[test]
fn test_cbc_decrypt_1block_zero_iv() {
let key = aes256::DecryptionKey::new(&aes256::EncryptionKey::new(&[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f,
]));
let mut blocks = [[
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
]];
let iv = [0; 16];
cbc_decrypt(&key, iv, &mut blocks);
let mut expected = [
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
];
key.decrypt_block(&mut expected);
assert_eq!(blocks, [expected]);
}
#[test]
fn test_cbc_encrypt_1block() {
let key = aes256::EncryptionKey::new(&[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f,
]);
let mut blocks = [[
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
]];
let iv = [
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
0x3e, 0x3f,
];
cbc_encrypt(&key, iv, &mut blocks);
let mut expected = [
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
];
xor_block_16(&mut expected, &iv);
key.encrypt_block(&mut expected);
assert_eq!(blocks, [expected]);
}
#[test]
fn test_cbc_decrypt_1block() {
let key = aes256::DecryptionKey::new(&aes256::EncryptionKey::new(&[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f,
]));
let mut blocks = [[
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
]];
let iv = [
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
0x3e, 0x3f,
];
cbc_decrypt(&key, iv, &mut blocks);
let mut expected = [
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
];
key.decrypt_block(&mut expected);
xor_block_16(&mut expected, &iv);
assert_eq!(blocks, [expected]);
}
#[test]
fn test_cbc_encrypt_2blocks() {
let key = aes256::EncryptionKey::new(&[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f,
]);
let mut blocks = [
[
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
],
[
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f,
],
];
let iv = [
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
0x3e, 0x3f,
];
cbc_encrypt(&key, iv, &mut blocks);
let mut expected0 = [
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
];
let mut expected1 = [
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f,
];
xor_block_16(&mut expected0, &iv);
key.encrypt_block(&mut expected0);
xor_block_16(&mut expected1, &expected0);
key.encrypt_block(&mut expected1);
assert_eq!(blocks, [expected0, expected1]);
}
#[test]
fn test_cbc_decrypt_2blocks() {
let key = aes256::DecryptionKey::new(&aes256::EncryptionKey::new(&[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f,
]));
let mut blocks = [
[
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
],
[
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f,
],
];
let iv = [
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
0x3e, 0x3f,
];
cbc_decrypt(&key, iv, &mut blocks);
let mut expected0 = [
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f,
];
let mut expected1 = [
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f,
];
key.decrypt_block(&mut expected1);
xor_block_16(&mut expected1, &expected0);
key.decrypt_block(&mut expected0);
xor_block_16(&mut expected0, &iv);
assert_eq!(blocks, [expected0, expected1]);
}
}

View File

@@ -0,0 +1,346 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::super::rng256::Rng256;
use super::int256::{Digit, Int256};
use core::ops::Mul;
use subtle::{self, Choice, ConditionallySelectable, CtOption};
// An exponent on the elliptic curve, that is an element modulo the curve order N.
#[derive(Clone, Copy, PartialEq, Eq)]
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
// resolved.
#[derive(Default)]
#[cfg_attr(feature = "derive_debug", derive(Debug))]
pub struct ExponentP256 {
int: Int256,
}
impl ConditionallySelectable for ExponentP256 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
int: Int256::conditional_select(&a.int, &b.int, choice),
}
}
}
impl ExponentP256 {
/** Constructors **/
pub fn from_int_checked(int: Int256) -> CtOption<ExponentP256> {
CtOption::new(ExponentP256 { int }, int.ct_lt(&Int256::N))
}
#[cfg(test)]
// Normally the ExponentP256 type guarantees that its values stay in [0, N[ because N is the
// curve order and therefore exponents >= N are equivalent to their reduction modulo N.
// This unsafe function is only used in tests to check that N is indeed the curve order.
pub unsafe fn from_int_unchecked(int: Int256) -> ExponentP256 {
ExponentP256 { int }
}
pub fn modn(int: Int256) -> ExponentP256 {
ExponentP256 {
int: int.modd(&Int256::N),
}
}
/** Helpful getters **/
pub fn bit(&self, i: usize) -> Digit {
self.int.bit(i)
}
pub fn to_int(self) -> Int256 {
self.int
}
pub fn is_zero(&self) -> subtle::Choice {
self.int.is_zero()
}
pub fn non_zero(self) -> CtOption<NonZeroExponentP256> {
CtOption::new(NonZeroExponentP256 { e: self }, !self.is_zero())
}
/** Arithmetic **/
pub fn mul_top(&self, other: &Int256, other_top: Digit) -> ExponentP256 {
ExponentP256 {
int: Int256::modmul_top(&self.int, other, other_top, &Int256::N),
}
}
}
/** Arithmetic operators **/
impl Mul for &ExponentP256 {
type Output = ExponentP256;
fn mul(self, other: &ExponentP256) -> ExponentP256 {
ExponentP256 {
int: Int256::modmul(&self.int, &other.int, &Int256::N),
}
}
}
// A non-zero exponent on the elliptic curve.
#[derive(Clone, Copy, PartialEq, Eq)]
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
// resolved.
#[derive(Default)]
#[cfg_attr(feature = "derive_debug", derive(Debug))]
pub struct NonZeroExponentP256 {
e: ExponentP256,
}
impl ConditionallySelectable for NonZeroExponentP256 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
e: ExponentP256::conditional_select(&a.e, &b.e, choice),
}
}
}
impl NonZeroExponentP256 {
/** RNG **/
// Generates a uniformly distributed element 0 < k < N
pub fn gen_uniform<R>(r: &mut R) -> NonZeroExponentP256
where
R: Rng256,
{
loop {
let x = Int256::gen_uniform_256(r);
if bool::from(Int256::N_MIN_2.ct_lt(&x)) {
continue;
}
// At this point, x <= n - 2.
// We add 1 so that 0 < result < n.
return NonZeroExponentP256 {
e: ExponentP256 { int: (&x + 1).0 },
};
}
}
/** Constructors **/
pub fn from_int_checked(int: Int256) -> CtOption<NonZeroExponentP256> {
ExponentP256::from_int_checked(int)
.and_then(|e| CtOption::new(NonZeroExponentP256 { e }, !e.is_zero()))
}
/** Helpful getters **/
pub fn to_int(self) -> Int256 {
self.e.to_int()
}
pub fn as_exponent(&self) -> &ExponentP256 {
&self.e
}
/** Arithmetic **/
// Compute the inverse modulo N. This uses Fermat's little theorem for constant-timeness.
pub fn inv(&self) -> NonZeroExponentP256 {
NonZeroExponentP256 {
e: ExponentP256 {
int: self.e.int.modpow(&Int256::N_MIN_2, &Int256::N),
},
}
}
#[cfg(test)]
fn inv_vartime(&self) -> NonZeroExponentP256 {
NonZeroExponentP256 {
e: ExponentP256 {
int: self.e.int.modinv_vartime(&Int256::N),
},
}
}
}
/** Arithmetic operators **/
impl Mul for &NonZeroExponentP256 {
type Output = NonZeroExponentP256;
// The product of two non-zero elements is also non-zero, because the curve order N is prime.
fn mul(self, other: &NonZeroExponentP256) -> NonZeroExponentP256 {
NonZeroExponentP256 {
e: &self.e * &other.e,
}
}
}
#[cfg(test)]
pub mod test {
use super::super::montgomery::Montgomery;
use super::*;
use crate::util::ToOption;
const ZERO: ExponentP256 = ExponentP256 { int: Int256::ZERO };
const ONE: NonZeroExponentP256 = NonZeroExponentP256 {
e: ExponentP256 { int: Int256::ONE },
};
const N_MIN_1_INT: Int256 = Int256::new([
0xfc632550, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, 0xffffffff, 0xffffffff, 0x00000000,
0xffffffff,
]);
const N_MIN_1: NonZeroExponentP256 = NonZeroExponentP256 {
e: ExponentP256 { int: N_MIN_1_INT },
};
fn get_nonzero_test_values() -> Vec<NonZeroExponentP256> {
let mut values: Vec<NonZeroExponentP256> = Montgomery::PRECOMPUTED
.iter()
.flatten()
.flatten()
.map(|x| {
ExponentP256::modn(x.montgomery_to_field().to_int())
.non_zero()
.unwrap()
})
.collect();
values.extend(
super::super::int256::test::get_nonzero_test_values()
.iter()
.filter_map(|&x| {
let y = ExponentP256::modn(x).non_zero();
if bool::from(y.is_some()) {
Some(y.unwrap())
} else {
None
}
}),
);
values.push(ONE);
values
}
pub fn get_test_values() -> Vec<ExponentP256> {
let mut values: Vec<ExponentP256> = get_nonzero_test_values()
.iter()
.map(|x| *x.as_exponent())
.collect();
values.push(ZERO);
values
}
/** Constructors **/
#[test]
fn test_from_int_checked() {
assert_eq!(
ExponentP256::from_int_checked(Int256::ZERO).to_option(),
Some(ExponentP256 { int: Int256::ZERO })
);
assert_eq!(
ExponentP256::from_int_checked(Int256::ONE).to_option(),
Some(ExponentP256 { int: Int256::ONE })
);
assert_eq!(
ExponentP256::from_int_checked(N_MIN_1_INT).to_option(),
Some(ExponentP256 { int: N_MIN_1_INT })
);
assert_eq!(ExponentP256::from_int_checked(Int256::N).to_option(), None);
}
#[test]
fn test_modn() {
assert_eq!(
ExponentP256::modn(Int256::ZERO),
ExponentP256 { int: Int256::ZERO }
);
assert_eq!(
ExponentP256::modn(Int256::ONE),
ExponentP256 { int: Int256::ONE }
);
assert_eq!(
ExponentP256::modn(N_MIN_1_INT),
ExponentP256 { int: N_MIN_1_INT }
);
assert_eq!(
ExponentP256::modn(Int256::N),
ExponentP256 { int: Int256::ZERO }
);
}
/** Arithmetic operations: inverse **/
#[test]
fn test_inv_is_inv_vartime() {
for x in &get_nonzero_test_values() {
assert_eq!(x.inv(), x.inv_vartime());
}
}
#[test]
fn test_self_times_inv_is_one() {
for x in &get_nonzero_test_values() {
assert_eq!(x * &x.inv(), ONE);
}
}
#[test]
fn test_inv_inv() {
for x in get_nonzero_test_values() {
assert_eq!(x.inv().inv(), x);
}
}
#[test]
fn test_well_known_inverses() {
assert_eq!(ONE.inv(), ONE);
assert_eq!(N_MIN_1.inv(), N_MIN_1);
}
/** RNG **/
// Mock rng that samples through a list of values, then panics.
struct StressTestingRng {
values: Vec<Int256>,
index: usize,
}
impl StressTestingRng {
pub fn new(values: Vec<Int256>) -> StressTestingRng {
StressTestingRng { values, index: 0 }
}
}
impl Rng256 for StressTestingRng {
// This function is unused, as we redefine gen_uniform_u32x8.
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
unreachable!()
}
fn gen_uniform_u32x8(&mut self) -> [u32; 8] {
let result = self.values[self.index].digits();
self.index += 1;
result
}
}
#[test]
fn test_uniform_non_zero_is_below_n() {
let mut rng = StressTestingRng::new(vec![
Int256::new([
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff,
]),
Int256::N,
N_MIN_1.to_int(),
Int256::N_MIN_2,
]);
assert_eq!(NonZeroExponentP256::gen_uniform(&mut rng), N_MIN_1);
}
#[test]
fn test_uniform_n_is_above_zero() {
let mut rng = StressTestingRng::new(vec![Int256::ZERO]);
assert_eq!(NonZeroExponentP256::gen_uniform(&mut rng), ONE);
}
}

View File

@@ -0,0 +1,260 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::int256::{Digit, Int256};
use core::ops::Mul;
use subtle::Choice;
// A field element on the elliptic curve, that is an element modulo the prime P.
// This is the format used to serialize coordinates of points on the curve.
// This implements enough methods to validate points and to convert them to/from the Montgomery
// form, which is more convenient to operate on.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct GFP256 {
int: Int256,
}
impl GFP256 {
pub const ZERO: GFP256 = GFP256 { int: Int256::ZERO };
pub const ONE: GFP256 = GFP256 { int: Int256::ONE };
pub const B: GFP256 = GFP256 { int: Int256::B };
pub const R: GFP256 = GFP256 { int: Int256::R };
pub const R_INV: GFP256 = GFP256 { int: Int256::R_INV };
/** Constructors **/
pub fn from_int_checked(int: Int256) -> Option<GFP256> {
if bool::from(int.ct_lt(&Int256::P)) {
Some(GFP256 { int })
} else {
None
}
}
/** Helpful getters **/
pub fn to_int(self) -> Int256 {
self.int
}
fn is_zero(&self) -> Choice {
self.int.is_zero()
}
/** Arithmetic **/
pub fn mul_top(&self, other: &Int256, other_top: Digit) -> GFP256 {
GFP256 {
int: Int256::modmul_top(&self.int, other, other_top, &Int256::P),
}
}
/** Point validation **/
// Verify that all of the following are true:
// * y^2 == x^3 - 3x + b mod p
// * 0 < x < p
// * 0 < y < p
//
// Not constant time.
pub fn is_valid_point_vartime(x: &GFP256, y: &GFP256) -> bool {
if bool::from(x.is_zero()) || bool::from(y.is_zero()) {
return false;
}
// y^2
let y2 = y * y;
// x^3
let x2 = x * x;
let x3 = &x2 * x;
// x^3 - 3x + b
let mut xx = x3;
xx = xx.sub_vartime(x);
xx = xx.sub_vartime(x);
xx = xx.sub_vartime(x);
xx = xx.add_vartime(&GFP256::B);
xx == y2
}
/** Arithmetic operators **/
fn add_vartime(self, other: &GFP256) -> GFP256 {
GFP256 {
int: Int256::modadd_vartime(&self.int, &other.int, &Int256::P),
}
}
fn sub_vartime(self, other: &GFP256) -> GFP256 {
GFP256 {
int: Int256::modsub_vartime(&self.int, &other.int, &Int256::P),
}
}
}
/** Arithmetic operators **/
impl Mul for &GFP256 {
type Output = GFP256;
fn mul(self, other: &GFP256) -> GFP256 {
GFP256 {
int: Int256::modmul(&self.int, &other.int, &Int256::P),
}
}
}
#[cfg(feature = "derive_debug")]
impl core::fmt::Debug for GFP256 {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "GFP256::{:?}", self.int)
}
}
#[cfg(test)]
mod test {
use super::super::montgomery::Montgomery;
use super::*;
use core::ops::{Add, Sub};
const P_MIN_1_INT: Int256 = Int256::new([
0xfffffffe, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
0xffffffff,
]);
fn get_test_values() -> Vec<GFP256> {
let mut values: Vec<GFP256> = Montgomery::PRECOMPUTED
.iter()
.flatten()
.flatten()
.map(|x| x.montgomery_to_field())
.collect();
values.extend(
super::super::int256::test::get_1bit_one_test_values()
.iter()
.filter_map(|&x| GFP256::from_int_checked(x)),
);
values.extend(
super::super::int256::test::get_1bit_zero_test_values()
.iter()
.filter_map(|&x| GFP256::from_int_checked(x)),
);
values.push(GFP256::ZERO);
values.push(GFP256::ONE);
values.push(GFP256::B);
values
}
/** Arithmetic operators, only for tests as these are not constant time **/
impl Add for &GFP256 {
type Output = GFP256;
fn add(self, other: &GFP256) -> GFP256 {
self.add_vartime(other)
}
}
impl Sub for &GFP256 {
type Output = GFP256;
fn sub(self, other: &GFP256) -> GFP256 {
self.sub_vartime(other)
}
}
/** Constructors **/
#[test]
fn test_from_int_checked() {
assert_eq!(
GFP256::from_int_checked(Int256::ZERO),
Some(GFP256 { int: Int256::ZERO })
);
assert_eq!(
GFP256::from_int_checked(Int256::ONE),
Some(GFP256 { int: Int256::ONE })
);
assert_eq!(
GFP256::from_int_checked(P_MIN_1_INT),
Some(GFP256 { int: P_MIN_1_INT })
);
assert_eq!(GFP256::from_int_checked(Int256::P), None);
}
/** Point validation **/
// See point.rs
/** Arithmetic operators **/
// Due to the 3 nested loops, this test is super slow with debug assertions enabled.
#[cfg(not(debug_assertions))]
#[test]
fn test_add_is_associative() {
for x in &get_test_values() {
for y in &get_test_values() {
for z in &get_test_values() {
assert_eq!(&(x + y) + z, x + &(y + z));
}
}
}
}
#[test]
fn test_add_is_commutative() {
for x in &get_test_values() {
for y in &get_test_values() {
assert_eq!(x + y, y + x);
}
}
}
#[test]
fn test_add_sub() {
for x in &get_test_values() {
for y in &get_test_values() {
assert_eq!(&(x - y) + y, *x);
assert_eq!(&(x + y) - y, *x);
}
}
}
// Due to the 3 nested loops, this test is super slow with debug assertions enabled.
#[cfg(not(debug_assertions))]
#[test]
fn test_mul_is_associative() {
for x in &get_test_values() {
for y in &get_test_values() {
for z in &get_test_values() {
assert_eq!(&(x * y) * z, x * &(y * z));
}
}
}
}
#[test]
fn test_mul_is_commutative() {
for x in &get_test_values() {
for y in &get_test_values() {
assert_eq!(x * y, y * x);
}
}
}
// Due to the 3 nested loops, this test is super slow with debug assertions enabled.
#[cfg(not(debug_assertions))]
#[test]
fn test_mul_is_distributive() {
for x in &get_test_values() {
for y in &get_test_values() {
for z in &get_test_values() {
assert_eq!(&(x + y) * z, &(x * z) + &(y * z));
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod exponent256;
mod gfp256;
pub mod int256;
mod montgomery;
pub mod point;
mod precomputed;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,324 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::montgomery::{Montgomery, NLIMBS};
pub const PRECOMPUTED: [[[Montgomery; 2]; 15]; 2] = [
[
[
Montgomery::new(PRECOMPUTED_LIMBS[0]),
Montgomery::new(PRECOMPUTED_LIMBS[1]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[2]),
Montgomery::new(PRECOMPUTED_LIMBS[3]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[4]),
Montgomery::new(PRECOMPUTED_LIMBS[5]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[6]),
Montgomery::new(PRECOMPUTED_LIMBS[7]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[8]),
Montgomery::new(PRECOMPUTED_LIMBS[9]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[10]),
Montgomery::new(PRECOMPUTED_LIMBS[11]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[12]),
Montgomery::new(PRECOMPUTED_LIMBS[13]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[14]),
Montgomery::new(PRECOMPUTED_LIMBS[15]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[16]),
Montgomery::new(PRECOMPUTED_LIMBS[17]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[18]),
Montgomery::new(PRECOMPUTED_LIMBS[19]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[20]),
Montgomery::new(PRECOMPUTED_LIMBS[21]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[22]),
Montgomery::new(PRECOMPUTED_LIMBS[23]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[24]),
Montgomery::new(PRECOMPUTED_LIMBS[25]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[26]),
Montgomery::new(PRECOMPUTED_LIMBS[27]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[28]),
Montgomery::new(PRECOMPUTED_LIMBS[29]),
],
],
[
[
Montgomery::new(PRECOMPUTED_LIMBS[30]),
Montgomery::new(PRECOMPUTED_LIMBS[31]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[32]),
Montgomery::new(PRECOMPUTED_LIMBS[33]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[34]),
Montgomery::new(PRECOMPUTED_LIMBS[35]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[36]),
Montgomery::new(PRECOMPUTED_LIMBS[37]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[38]),
Montgomery::new(PRECOMPUTED_LIMBS[39]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[40]),
Montgomery::new(PRECOMPUTED_LIMBS[41]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[42]),
Montgomery::new(PRECOMPUTED_LIMBS[43]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[44]),
Montgomery::new(PRECOMPUTED_LIMBS[45]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[46]),
Montgomery::new(PRECOMPUTED_LIMBS[47]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[48]),
Montgomery::new(PRECOMPUTED_LIMBS[49]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[50]),
Montgomery::new(PRECOMPUTED_LIMBS[51]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[52]),
Montgomery::new(PRECOMPUTED_LIMBS[53]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[54]),
Montgomery::new(PRECOMPUTED_LIMBS[55]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[56]),
Montgomery::new(PRECOMPUTED_LIMBS[57]),
],
[
Montgomery::new(PRECOMPUTED_LIMBS[58]),
Montgomery::new(PRECOMPUTED_LIMBS[59]),
],
],
];
#[rustfmt::skip]
#[allow(clippy::unreadable_literal)]
const PRECOMPUTED_LIMBS: [[u32; NLIMBS]; 60] = [
[0x11522878, 0x0e730d41, 0x0db60179, 0x04afe2ff, 0x12883add, 0x0caddd88, 0x119e7edc, 0x0d4a6eab, 0x03120bee],
[0x1d2aac15, 0x0f25357c, 0x19e45cdd, 0x05c721d0, 0x1992c5a5, 0x0a237487, 0x0154ba21, 0x014b10bb, 0x00ae3fe3],
[0x0d41a576, 0x0922fc51, 0x0234994f, 0x060b60d3, 0x164586ae, 0x0ce95f18, 0x1fe49073, 0x03fa36cc, 0x05ebcd2c],
[0x0b402f2f, 0x015c70bf, 0x1561925c, 0x05a26704, 0x0da91e90, 0x0cdc1c7f, 0x1ea12446, 0x0e1ade1e, 0x0ec91f22],
[0x026f7778, 0x0566847e, 0x0a0bec9e, 0x0234f453, 0x1a31f21a, 0x0d85e75c, 0x056c7109, 0x0a267a00, 0x0b57c050],
[0x0098fb57, 0x0aa837cc, 0x060c0792, 0x0cfa5e19, 0x061bab9e, 0x0589e39b, 0x00a324c5, 0x07d6dee7, 0x02976e4b],
[0x1fc4124a, 0x0a8c244b, 0x1ce86762, 0x0cd61c7e, 0x1831c8e0, 0x075774e1, 0x1d96a5a9, 0x0843a649, 0x0c3ab0fa],
[0x06e2e7d5, 0x07673a2a, 0x178b65e8, 0x04003e9b, 0x1a1f11c2, 0x007816ea, 0x0f643e11, 0x058c43df, 0x0f423fc2],
[0x19633ffa, 0x0891f2b2, 0x123c231c, 0x046add8c, 0x054700dd, 0x059e2b17, 0x172db40f, 0x083e277d, 0x0b0dd609],
[0x0fd1da12, 0x035c6e52, 0x19ede20c, 0x0d19e0c0, 0x097d0f40, 0x0b015b19, 0x0449e3f5, 0x00e10c9e, 0x033ab581],
[0x056a67ab, 0x0577734d, 0x1dddc062, 0x0c57b10d, 0x0149b39d, 0x026a9e7b, 0x0c35df9f, 0x048764cd, 0x076dbcca],
[0x0ca4b366, 0x0e9303ab, 0x1a7480e7, 0x057e9e81, 0x1e13eb50, 0x0f466cf3, 0x06f16b20, 0x04ba3173, 0x0c168c33],
[0x15cb5439, 0x06a38e11, 0x073658bd, 0x0b29564f, 0x03f6dc5b, 0x0053b97e, 0x1322c4c0, 0x065dd7ff, 0x03a1e4f6],
[0x14e614aa, 0x09246317, 0x1bc83aca, 0x0ad97eed, 0x0d38ce4a, 0x0f82b006, 0x0341f077, 0x0a6add89, 0x04894acd],
[0x09f162d5, 0x0f8410ef, 0x1b266a56, 0x00d7f223, 0x03e0cb92, 0x0e39b672, 0x06a2901a, 0x069a8556, 0x0007e7c0],
[0x09b7d8d3, 0x00309a80, 0x1ad05f7f, 0x0c2fb5dd, 0x0cbfd41d, 0x09ceb638, 0x1051825c, 0x0da0cf5b, 0x0812e881],
[0x06f35669, 0x06a56f2c, 0x1df8d184, 0x00345820, 0x1477d477, 0x01645db1, 0x0be80c51, 0x0c22be3e, 0x0e35e65a],
[0x1aeb7aa0, 0x0c375315, 0x0f67bc99, 0x07fdd7b9, 0x191fc1be, 0x0061235d, 0x02c184e9, 0x01c5a839, 0x047a1e26],
[0x0b7cb456, 0x093e225d, 0x14f3c6ed, 0x0ccc1ac9, 0x17fe37f3, 0x04988989, 0x1a90c502, 0x02f32042, 0x0a17769b],
[0x0afd8c7c, 0x08191c6e, 0x1dcdb237, 0x016200c0, 0x107b32a1, 0x066c08db, 0x10d06a02, 0x0003fc93, 0x05620023],
[0x16722b27, 0x068b5c59, 0x0270fcfc, 0x0fad0ecc, 0x0e5de1c2, 0x0eab466b, 0x02fc513c, 0x0407f75c, 0x0baab133],
[0x09705fe9, 0x0b88b8e7, 0x0734c993, 0x01e1ff8f, 0x19156970, 0x0abd0f00, 0x10469ea7, 0x03293ac0, 0x0cdc98aa],
[0x01d843fd, 0x0e14bfe8, 0x15be825f, 0x008b5212, 0x0eb3fb67, 0x081cbd29, 0x0bc62f16, 0x02b6fcc7, 0x0f5a4e29],
[0x13560b66, 0x0c0b6ac2, 0x051ae690, 0x0d41e271, 0x0f3e9bd4, 0x01d70aab, 0x01029f72, 0x073e1c35, 0x0ee70fbc],
[0x0ad81baf, 0x09ecc49a, 0x086c741e, 0x0fe6be30, 0x176752e7, 0x0023d416, 0x1f83de85, 0x027de188, 0x066f70b8],
[0x181cd51f, 0x096b6e4c, 0x188f2335, 0x0a5df759, 0x17a77eb6, 0x0feb0e73, 0x154ae914, 0x02f3ec51, 0x03826b59],
[0x0b91f17d, 0x01c72949, 0x1362bf0a, 0x0e23fddf, 0x0a5614b0, 0x000f7d8f, 0x00079061, 0x0823d9d2, 0x08213f39],
[0x1128ae0b, 0x0d095d05, 0x0b85c0c2, 0x01ecb2ef, 0x024ddc84, 0x0e35e901, 0x18411a4a, 0x0f5ddc3d, 0x03786689],
[0x052260e8, 0x05ae3564, 0x0542b10d, 0x08d93a45, 0x19952aa4, 0x0996cc41, 0x1051a729, 0x04be3499, 0x052b23aa],
[0x109f307e, 0x06f5b6bb, 0x1f84e1e7, 0x077a0cfa, 0x10c4df3f, 0x025a02ea, 0x0b048035, 0x0e31de66, 0x0c6ecaa3],
[0x028ea335, 0x02886024, 0x1372f020, 0x00f55d35, 0x15e4684c, 0x0f2a9e17, 0x1a4a7529, 0x0cb7beb1, 0x0b2a78a1],
[0x1ab21f1f, 0x06361ccf, 0x06c9179d, 0x0b135627, 0x1267b974, 0x04408bad, 0x1cbff658, 0x0e3d6511, 0x00c7d76f],
[0x01cc7a69, 0x0e7ee31b, 0x054fab4f, 0x002b914f, 0x1ad27a30, 0x0cd3579e, 0x0c50124c, 0x050daa90, 0x00b13f72],
[0x0b06aa75, 0x070f5cc6, 0x1649e5aa, 0x084a5312, 0x0329043c, 0x041c4011, 0x13d32411, 0x0b04a838, 0x0d760d2d],
[0x1713b532, 0x0baa0c03, 0x084022ab, 0x06bcf5c1, 0x02f45379, 0x018ae070, 0x18c9e11e, 0x020bca9a, 0x066f496b],
[0x03eef294, 0x067500d2, 0x0d7f613c, 0x002dbbeb, 0x0b741038, 0x0e04133f, 0x1582968d, 0x0be985f7, 0x01acbc1a],
[0x1a6a939f, 0x033e50f6, 0x0d665ed4, 0x0b4b7bd6, 0x1e5a3799, 0x06b33847, 0x17fa56ff, 0x065ef930, 0x0021dc4a],
[0x02b37659, 0x0450fe17, 0x0b357b65, 0x0df5efac, 0x15397bef, 0x09d35a7f, 0x112ac15f, 0x0624e62e, 0x0a90ae2f],
[0x107eecd2, 0x01f69bbe, 0x077d6bce, 0x05741394, 0x13c684fc, 0x0950c910, 0x0725522b, 0x0dc78583, 0x040eeabb],
[0x1fde328a, 0x0bd61d96, 0x0d28c387, 0x09e77d89, 0x12550c40, 0x0759cb7d, 0x0367ef34, 0x0ae2a960, 0x091b8bdc],
[0x093462a9, 0x00f469ef, 0x0b2e9aef, 0x0d2ca771, 0x054e1f42, 0x007aaa49, 0x06316abb, 0x02413c8e, 0x05425bf9],
[0x1bed3e3a, 0x0f272274, 0x1f5e7326, 0x06416517, 0x0ea27072, 0x09cedea7, 0x006e7633, 0x07c91952, 0x0d806dce],
[0x08e2a7e1, 0x0e421e1a, 0x0418c9e1, 0x01dbc890, 0x1b395c36, 0x0a1dc175, 0x1dc4ef73, 0x08956f34, 0x0e4b5cf2],
[0x1b0d3a18, 0x03194a36, 0x06c2641f, 0x0e44124c, 0x0a2f4eaa, 0x0a8c25ba, 0x0f927ed7, 0x0627b614, 0x07371cca],
[0x0ba16694, 0x0417bc03, 0x07c0a7e3, 0x09c35c19, 0x1168a205, 0x08b6b00d, 0x10e3edc9, 0x09c19bf2, 0x05882229],
[0x1b2b4162, 0x0a5cef1a, 0x1543622b, 0x09bd433e, 0x0364e04d, 0x07480792, 0x05c9b5b3, 0x0e85ff25, 0x0408ef57],
[0x1814cfa4, 0x0121b41b, 0x0d248a0f, 0x03b05222, 0x039bb16a, 0x0c75966d, 0x0a038113, 0x0a4a1769, 0x011fbc6c],
[0x0917e50e, 0x0eec3da8, 0x169d6eac, 0x010c1699, 0x0a416153, 0x0f724912, 0x15cd60b7, 0x04acbad9, 0x05efc5fa],
[0x0f150ed7, 0x00122b51, 0x1104b40a, 0x0cb7f442, 0x0fbb28ff, 0x06ac53ca, 0x196142cc, 0x07bf0fa9, 0x00957651],
[0x04e0f215, 0x0ed439f8, 0x03f46bd5, 0x05ace82f, 0x110916b6, 0x006db078, 0x0ffd7d57, 0x0f2ecaac, 0x0ca86dec],
[0x15d6b2da, 0x0965ecc9, 0x1c92b4c2, 0x001f3811, 0x1cb080f5, 0x02d8b804, 0x19d1c12d, 0x0f20bd46, 0x01951fa7],
[0x0a3656c3, 0x0523a425, 0x0fcd0692, 0x0d44ddc8, 0x131f0f5b, 0x0af80e4a, 0x0cd9fc74, 0x099bb618, 0x02db944c],
[0x0a673090, 0x01c210e1, 0x178c8d23, 0x01474383, 0x10b8743d, 0x0985a55b, 0x02e74779, 0x00576138, 0x09587927],
[0x133130fa, 0x0be05516, 0x09f4d619, 0x0bb62570, 0x099ec591, 0x0d9468fe, 0x1d07782d, 0x0fc72e0b, 0x0701b298],
[0x1863863b, 0x085954b8, 0x121a0c36, 0x09e7fedf, 0x0f64b429, 0x09b9d71e, 0x14e2f5d8, 0x0f858d3a, 0x0942eea8],
[0x0da5b765, 0x06edafff, 0x0a9d18cc, 0x0c65e4ba, 0x1c747e86, 0x0e4ea915, 0x1981d7a1, 0x08395659, 0x052ed4e2],
[0x087d43b7, 0x037ab11b, 0x19d292ce, 0x0f8d4692, 0x18c3053f, 0x08863e13, 0x04c146c0, 0x06bdf55a, 0x04e4457d],
[0x16152289, 0x0ac78ec2, 0x1a59c5a2, 0x02028b97, 0x071c2d01, 0x0295851f, 0x0404747b, 0x0878558d, 0x07d29aa4],
[0x13d8341f, 0x08daefd7, 0x139c972d, 0x06b7ea75, 0x0d4a9dde, 0x0ff163d8, 0x081d55d7, 0x0a5bef68, 0x0b7b30d8],
[0x0be73d6f, 0x0aa88141, 0x0d976c81, 0x07e7a9cc, 0x18beb771, 0x0d773cbd, 0x13f51951, 0x09d0c177, 0x01c49a78],
];
#[cfg(test)]
mod test {
use super::super::montgomery::{BOTTOM_28_BITS, BOTTOM_29_BITS};
use super::super::point::test::{power_of_two, precomputed};
use super::super::point::PointProjective;
use super::*;
#[test]
fn test_precomputed_bits() {
for x in PRECOMPUTED_LIMBS.iter() {
for (i, &limb) in x.iter().enumerate() {
if i & 1 == 0 {
assert_eq!(limb & BOTTOM_29_BITS, limb);
} else {
assert_eq!(limb & BOTTOM_28_BITS, limb);
}
}
}
}
#[test]
fn test_precomputed_powers_of_g_are_correct() {
let gen = PointProjective::from_affine(&precomputed(0, 0));
let g32 = power_of_two(gen, 32);
let g64 = power_of_two(gen, 64);
let g96 = power_of_two(gen, 96);
let g128 = power_of_two(gen, 128);
let g160 = power_of_two(gen, 160);
let g192 = power_of_two(gen, 192);
let g224 = power_of_two(gen, 224);
assert_eq!(
PointProjective::from_affine(&precomputed(0, 0b0001 - 1)),
gen
);
assert_eq!(
PointProjective::from_affine(&precomputed(0, 0b0010 - 1)),
g64
);
assert_eq!(
PointProjective::from_affine(&precomputed(0, 0b0100 - 1)),
g128
);
assert_eq!(
PointProjective::from_affine(&precomputed(0, 0b1000 - 1)),
g192
);
assert_eq!(
PointProjective::from_affine(&precomputed(1, 0b0001 - 1)),
g32
);
assert_eq!(
PointProjective::from_affine(&precomputed(1, 0b0010 - 1)),
g96
);
assert_eq!(
PointProjective::from_affine(&precomputed(1, 0b0100 - 1)),
g160
);
assert_eq!(
PointProjective::from_affine(&precomputed(1, 0b1000 - 1)),
g224
);
}
#[test]
fn test_precomputed_table_0_is_correct() {
let gen = PointProjective::from_affine(&precomputed(0, 0));
let g64 = power_of_two(gen, 64);
let g128 = power_of_two(gen, 128);
let g192 = power_of_two(gen, 192);
for i in 1..16 {
let mut x = PointProjective::INFINITY;
if i & 1 != 0 {
x = &x + &gen;
}
if i & 2 != 0 {
x = &x + &g64;
}
if i & 4 != 0 {
x = &x + &g128;
}
if i & 8 != 0 {
x = &x + &g192;
}
assert_eq!(PointProjective::from_affine(&precomputed(0, i - 1)), x);
}
}
#[test]
fn test_precomputed_table_1_is_correct() {
let gen = PointProjective::from_affine(&precomputed(0, 0));
let g32 = power_of_two(gen, 32);
let g96 = power_of_two(gen, 96);
let g160 = power_of_two(gen, 160);
let g224 = power_of_two(gen, 224);
for i in 1..16 {
let mut x = PointProjective::INFINITY;
if i & 1 != 0 {
x = &x + &g32;
}
if i & 2 != 0 {
x = &x + &g96;
}
if i & 4 != 0 {
x = &x + &g160;
}
if i & 8 != 0 {
x = &x + &g224;
}
assert_eq!(PointProjective::from_affine(&precomputed(1, i - 1)), x);
}
}
}

View File

@@ -0,0 +1,154 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::ec::exponent256::NonZeroExponentP256;
use super::ec::int256;
use super::ec::int256::Int256;
use super::ec::point::PointP256;
use super::rng256::Rng256;
use super::sha256::Sha256;
use super::Hash256;
pub const NBYTES: usize = int256::NBYTES;
pub struct SecKey {
a: NonZeroExponentP256,
}
#[cfg_attr(feature = "derive_debug", derive(Clone, PartialEq, Debug))]
pub struct PubKey {
p: PointP256,
}
impl SecKey {
pub fn gensk<R>(rng: &mut R) -> SecKey
where
R: Rng256,
{
SecKey {
a: NonZeroExponentP256::gen_uniform(rng),
}
}
pub fn genpk(&self) -> PubKey {
PubKey {
p: PointP256::base_point_mul(self.a.as_exponent()),
}
}
fn exchange_raw(&self, other: &PubKey) -> PointP256 {
// At this point, the PubKey type guarantees that other.p is a valid point on the curve.
// It's the responsibility of the caller to handle errors when converting serialized bytes
// to a PubKey.
other.p.mul(self.a.as_exponent())
// TODO: Do we need to check that the exchanged point is not infinite, and if yes handle
// the error? The following argument should be reviewed:
//
// In principle this isn't needed on the P-256 curve, which has a prime order and a
// cofactor of 1.
//
// Some pointers on this:
// - https://www.secg.org/sec1-v2.pdf
}
// DH key agreement method defined in the FIDO2 specification, Section 5.5.4. "Getting
// sharedSecret from Authenticator"
pub fn exchange_x_sha256(&self, other: &PubKey) -> [u8; 32] {
let p = self.exchange_raw(other);
let mut x: [u8; 32] = [Default::default(); 32];
p.getx().to_int().to_bin(&mut x);
Sha256::hash(&x)
}
}
impl PubKey {
#[cfg(test)]
fn from_bytes_uncompressed(bytes: &[u8]) -> Option<PubKey> {
PointP256::from_bytes_uncompressed_vartime(bytes).map(|p| PubKey { p })
}
#[cfg(test)]
fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
self.p.to_bytes_uncompressed(bytes);
}
pub fn from_coordinates(x: &[u8; NBYTES], y: &[u8; NBYTES]) -> Option<PubKey> {
PointP256::new_checked_vartime(Int256::from_bin(x), Int256::from_bin(y))
.map(|p| PubKey { p })
}
pub fn to_coordinates(&self, x: &mut [u8; NBYTES], y: &mut [u8; NBYTES]) {
self.p.getx().to_int().to_bin(x);
self.p.gety().to_int().to_bin(y);
}
}
#[cfg(test)]
mod test {
use super::super::rng256::ThreadRng256;
use super::*;
// Run more test iterations in release mode, as the code should be faster.
#[cfg(not(debug_assertions))]
const ITERATIONS: u32 = 10000;
#[cfg(debug_assertions)]
const ITERATIONS: u32 = 1000;
/** Test that key generation creates valid keys **/
#[test]
fn test_gen_pub_is_valid_random() {
let mut rng = ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
assert!(pk.p.is_valid_vartime());
}
}
/** Test that the exchanged key is the same on both sides **/
#[test]
fn test_exchange_x_sha256_is_symmetric() {
let mut rng = ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk_a = SecKey::gensk(&mut rng);
let pk_a = sk_a.genpk();
let sk_b = SecKey::gensk(&mut rng);
let pk_b = sk_b.genpk();
assert_eq!(sk_a.exchange_x_sha256(&pk_b), sk_b.exchange_x_sha256(&pk_a));
}
}
#[test]
fn test_exchange_x_sha256_bytes_is_symmetric() {
let mut rng = ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk_a = SecKey::gensk(&mut rng);
let mut pk_bytes_a = [Default::default(); 65];
sk_a.genpk().to_bytes_uncompressed(&mut pk_bytes_a);
let sk_b = SecKey::gensk(&mut rng);
let mut pk_bytes_b = [Default::default(); 65];
sk_b.genpk().to_bytes_uncompressed(&mut pk_bytes_b);
let pk_a = PubKey::from_bytes_uncompressed(&pk_bytes_a).unwrap();
let pk_b = PubKey::from_bytes_uncompressed(&pk_bytes_b).unwrap();
assert_eq!(sk_a.exchange_x_sha256(&pk_b), sk_b.exchange_x_sha256(&pk_a));
}
}
// TODO: tests with invalid public shares.
}

View File

@@ -0,0 +1,643 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::ec::exponent256::{ExponentP256, NonZeroExponentP256};
use super::ec::int256;
use super::ec::int256::Int256;
use super::ec::point::PointP256;
use super::hmac::hmac_256;
use super::rng256::Rng256;
use super::{Hash256, HashBlockSize64Bytes};
use alloc::vec::Vec;
use core::marker::PhantomData;
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "derive_debug", derive(Debug))]
pub struct SecKey {
k: NonZeroExponentP256,
}
pub struct Signature {
r: NonZeroExponentP256,
s: NonZeroExponentP256,
}
pub struct PubKey {
p: PointP256,
}
impl SecKey {
pub fn gensk<R>(rng: &mut R) -> SecKey
where
R: Rng256,
{
SecKey {
k: NonZeroExponentP256::gen_uniform(rng),
}
}
pub fn genpk(&self) -> PubKey {
PubKey {
p: PointP256::base_point_mul(self.k.as_exponent()),
}
}
// ECDSA signature based on a RNG to generate a suitable randomization parameter.
// Under the hood, rejection sampling is used to make sure that the randomization parameter is
// uniformly distributed.
// The provided RNG must be cryptographically secure; otherwise this method is insecure.
pub fn sign_rng<H, R>(&self, msg: &[u8], rng: &mut R) -> Signature
where
H: Hash256,
R: Rng256,
{
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
loop {
let k = NonZeroExponentP256::gen_uniform(rng);
if let Some(sign) = self.try_sign(&k, &m) {
return sign;
}
}
}
// Deterministic ECDSA signature based on RFC 6979 to generate a suitable randomization
// parameter.
pub fn sign_rfc6979<H>(&self, msg: &[u8]) -> Signature
where
H: Hash256 + HashBlockSize64Bytes,
{
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
let mut rfc_6979 = Rfc6979::<H>::new(self, &msg);
loop {
let k = NonZeroExponentP256::from_int_checked(rfc_6979.next());
// The branching here is fine. By design the algorithm of RFC 6976 has a running time
// that depends on the sequence of generated k.
if bool::from(k.is_none()) {
continue;
}
let k = k.unwrap();
if let Some(sign) = self.try_sign(&k, &m) {
return sign;
}
}
}
// Try signing a curve element given a randomization parameter k. If no signature can be
// obtained from this k, None is returned and the caller should try again with another value.
fn try_sign(&self, k: &NonZeroExponentP256, msg: &ExponentP256) -> Option<Signature> {
let r = ExponentP256::modn(PointP256::base_point_mul(k.as_exponent()).getx().to_int());
// The branching here is fine because all this reveals is that k generated an unsuitable r.
let r = r.non_zero();
if bool::from(r.is_none()) {
return None;
}
let r = r.unwrap();
let (s, top) = &(&r * &self.k).to_int() + &msg.to_int();
let s = k.inv().as_exponent().mul_top(&s, top);
// The branching here is fine because all this reveals is that k generated an unsuitable s.
let s = s.non_zero();
if bool::from(s.is_none()) {
return None;
}
let s = s.unwrap();
Some(Signature { r, s })
}
#[cfg(test)]
pub fn get_k_rfc6979<H>(&self, msg: &[u8]) -> NonZeroExponentP256
where
H: Hash256 + HashBlockSize64Bytes,
{
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
let mut rfc_6979 = Rfc6979::<H>::new(self, &msg);
loop {
let k = NonZeroExponentP256::from_int_checked(rfc_6979.next());
if bool::from(k.is_none()) {
continue;
}
let k = k.unwrap();
if self.try_sign(&k, &m).is_some() {
return k;
}
}
}
pub fn from_bytes(bytes: &[u8; 32]) -> Option<SecKey> {
let k = NonZeroExponentP256::from_int_checked(Int256::from_bin(bytes));
// The branching here is fine because all this reveals is whether the key was invalid.
if bool::from(k.is_none()) {
return None;
}
let k = k.unwrap();
Some(SecKey { k })
}
pub fn to_bytes(&self, bytes: &mut [u8; 32]) {
self.k.to_int().to_bin(bytes);
}
}
impl Signature {
pub fn to_asn1_der(&self) -> Vec<u8> {
const DER_INTEGER_TYPE: u8 = 0x02;
const DER_DEF_LENGTH_SEQUENCE: u8 = 0x30;
let r_encoding = self.r.to_int().to_minimal_encoding();
let s_encoding = self.s.to_int().to_minimal_encoding();
// We rely on the encoding to be short enough such that
// sum of lengths + 4 still fits into 7 bits.
#[cfg(test)]
assert!(r_encoding.len() <= 33);
#[cfg(test)]
assert!(s_encoding.len() <= 33);
// The ASN1 of a signature is a two member sequence. Its length is the
// sum of the integer encoding lengths and 2 header bytes per integer.
let mut encoding = vec![
DER_DEF_LENGTH_SEQUENCE,
(r_encoding.len() + s_encoding.len() + 4) as u8,
];
encoding.push(DER_INTEGER_TYPE);
encoding.push(r_encoding.len() as u8);
encoding.extend(r_encoding);
encoding.push(DER_INTEGER_TYPE);
encoding.push(s_encoding.len() as u8);
encoding.extend(s_encoding);
encoding
}
#[cfg(feature = "std")]
pub fn from_bytes(bytes: &[u8]) -> Option<Signature> {
if bytes.len() != 64 {
None
} else {
let r =
NonZeroExponentP256::from_int_checked(Int256::from_bin(array_ref![bytes, 0, 32]));
let s =
NonZeroExponentP256::from_int_checked(Int256::from_bin(array_ref![bytes, 32, 32]));
if bool::from(r.is_none()) || bool::from(s.is_none()) {
return None;
}
let r = r.unwrap();
let s = s.unwrap();
Some(Signature { r, s })
}
}
#[cfg(test)]
fn to_bytes(&self, bytes: &mut [u8; 64]) {
self.r.to_int().to_bin(array_mut_ref![bytes, 0, 32]);
self.s.to_int().to_bin(array_mut_ref![bytes, 32, 32]);
}
}
impl PubKey {
pub const ES256_ALGORITHM: i64 = -7;
#[cfg(feature = "with_ctap1")]
const UNCOMPRESSED_LENGTH: usize = 1 + 2 * int256::NBYTES;
#[cfg(feature = "std")]
pub fn from_bytes_uncompressed(bytes: &[u8]) -> Option<PubKey> {
PointP256::from_bytes_uncompressed_vartime(bytes).map(|p| PubKey { p })
}
#[cfg(test)]
fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
self.p.to_bytes_uncompressed(bytes);
}
#[cfg(feature = "with_ctap1")]
pub fn to_uncompressed(&self) -> [u8; PubKey::UNCOMPRESSED_LENGTH] {
// Formatting according to:
// https://tools.ietf.org/id/draft-jivsov-ecc-compact-05.html#overview
const B0_BYTE_MARKER: u8 = 0x04;
let mut representation = [0; PubKey::UNCOMPRESSED_LENGTH];
let (marker, x, y) =
mut_array_refs![&mut representation, 1, int256::NBYTES, int256::NBYTES];
marker[0] = B0_BYTE_MARKER;
self.p.getx().to_int().to_bin(x);
self.p.gety().to_int().to_bin(y);
representation
}
// Encodes the key according to CBOR Object Signing and Encryption, defined in RFC 8152.
pub fn to_cose_key(&self) -> Option<Vec<u8>> {
const EC2_KEY_TYPE: i64 = 2;
const P_256_CURVE: i64 = 1;
let mut x_bytes = vec![0; int256::NBYTES];
self.p
.getx()
.to_int()
.to_bin(array_mut_ref![x_bytes.as_mut_slice(), 0, int256::NBYTES]);
let x_byte_cbor: cbor::Value = cbor_bytes!(x_bytes);
let mut y_bytes = vec![0; int256::NBYTES];
self.p
.gety()
.to_int()
.to_bin(array_mut_ref![y_bytes.as_mut_slice(), 0, int256::NBYTES]);
let y_byte_cbor: cbor::Value = cbor_bytes!(y_bytes);
let cbor_value = cbor_map_options! {
1 => EC2_KEY_TYPE,
3 => PubKey::ES256_ALGORITHM,
-1 => P_256_CURVE,
-2 => x_byte_cbor,
-3 => y_byte_cbor,
};
let mut encoded_key = Vec::new();
if cbor::write(cbor_value, &mut encoded_key) {
Some(encoded_key)
} else {
None
}
}
#[cfg(feature = "std")]
pub fn verify_vartime<H>(&self, msg: &[u8], sign: &Signature) -> bool
where
H: Hash256,
{
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
let v = sign.s.inv();
let u = &m * v.as_exponent();
let v = &sign.r * &v;
let u = self.p.points_mul(&u, v.as_exponent()).getx();
ExponentP256::modn(u.to_int()) == *sign.r.as_exponent()
}
}
struct Rfc6979<H>
where
H: Hash256 + HashBlockSize64Bytes,
{
k: [u8; 32],
v: [u8; 32],
hash_marker: PhantomData<H>,
}
impl<H> Rfc6979<H>
where
H: Hash256 + HashBlockSize64Bytes,
{
pub fn new(sk: &SecKey, msg: &[u8]) -> Rfc6979<H> {
let h1 = H::hash(msg);
let v = [0x01; 32];
let k = [0x00; 32];
let mut contents = [0; 3 * 32 + 1];
let (contents_v, marker, contents_k, contents_h1) =
mut_array_refs![&mut contents, 32, 1, 32, 32];
contents_v.copy_from_slice(&v);
marker[0] = 0x00;
Int256::to_bin(&sk.k.to_int(), contents_k);
Int256::to_bin(&Int256::from_bin(&h1).modd(&Int256::N), contents_h1);
let k = hmac_256::<H>(&k, &contents);
let v = hmac_256::<H>(&k, &v);
let (contents_v, marker, _) = mut_array_refs![&mut contents, 32, 1, 64];
contents_v.copy_from_slice(&v);
marker[0] = 0x01;
let k = hmac_256::<H>(&k, &contents);
let v = hmac_256::<H>(&k, &v);
Rfc6979 {
k,
v,
hash_marker: PhantomData,
}
}
fn next(&mut self) -> Int256 {
// Note: at this step, the logic from RFC 6979 is simplified, because the HMAC produces 256
// bits and we need 256 bits.
let t = hmac_256::<H>(&self.k, &self.v);
let result = Int256::from_bin(&t);
let mut v1 = [0; 33];
v1[..32].copy_from_slice(&self.v);
v1[32] = 0x00;
self.k = hmac_256::<H>(&self.k, &v1);
self.v = hmac_256::<H>(&self.k, &self.v);
result
}
}
#[cfg(test)]
mod test {
use super::super::rng256::ThreadRng256;
use super::super::sha256::Sha256;
use super::*;
extern crate hex;
extern crate ring;
extern crate untrusted;
// Run more test iterations in release mode, as the code should be faster.
#[cfg(not(debug_assertions))]
const ITERATIONS: u32 = 10000;
#[cfg(debug_assertions)]
const ITERATIONS: u32 = 1000;
/** Test that key generation creates valid keys **/
#[test]
fn test_genpk_is_valid_random() {
let mut rng = ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
assert!(pk.p.is_valid_vartime());
}
}
/** Serialization **/
#[test]
fn test_seckey_to_bytes_from_bytes() {
let mut rng = ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
let mut bytes = [0; 32];
sk.to_bytes(&mut bytes);
let decoded_sk = SecKey::from_bytes(&bytes);
assert_eq!(decoded_sk, Some(sk));
}
}
#[test]
fn test_seckey_from_bytes_zero() {
// Zero is not a valid exponent for a secret key.
let bytes = [0; 32];
let sk = SecKey::from_bytes(&bytes);
assert!(sk.is_none());
}
#[test]
fn test_seckey_from_bytes_n() {
let mut bytes = [0; 32];
Int256::N.to_bin(&mut bytes);
let sk = SecKey::from_bytes(&bytes);
assert!(sk.is_none());
}
#[test]
fn test_seckey_from_bytes_ge_n() {
let bytes = [0xFF; 32];
let sk = SecKey::from_bytes(&bytes);
assert!(sk.is_none());
}
/** Test vectors from RFC6979 **/
fn int256_from_hex(x: &str) -> Int256 {
let bytes = hex::decode(x).unwrap();
assert_eq!(bytes.len(), 32);
Int256::from_bin(array_ref![bytes.as_slice(), 0, 32])
}
// Test vectors from RFC6979, Section A.2.5.
const RFC6979_X: &str = "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721";
const RFC6979_UX: &str = "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6";
const RFC6979_UY: &str = "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299";
#[test]
fn test_rfc6979_keypair() {
let sk = SecKey {
k: NonZeroExponentP256::from_int_checked(int256_from_hex(RFC6979_X)).unwrap(),
};
let pk = sk.genpk();
assert_eq!(pk.p.getx().to_int(), int256_from_hex(RFC6979_UX));
assert_eq!(pk.p.gety().to_int(), int256_from_hex(RFC6979_UY));
}
fn test_rfc6979(msg: &str, k: &str, r: &str, s: &str) {
let sk = SecKey {
k: NonZeroExponentP256::from_int_checked(int256_from_hex(RFC6979_X)).unwrap(),
};
assert_eq!(
sk.get_k_rfc6979::<Sha256>(msg.as_bytes()).to_int(),
int256_from_hex(k)
);
let sign = sk.sign_rfc6979::<Sha256>(msg.as_bytes());
assert_eq!(sign.r.to_int(), int256_from_hex(r));
assert_eq!(sign.s.to_int(), int256_from_hex(s));
}
#[test]
fn test_rfc6979_sample() {
let msg = "sample";
let k = "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60";
let r = "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716";
let s = "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8";
test_rfc6979(msg, k, r, s);
}
#[test]
fn test_rfc6979_test() {
let msg = "test";
let k = "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0";
let r = "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367";
let s = "019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083";
test_rfc6979(msg, k, r, s);
}
/** Tests that sign and verify are consistent **/
// Test that signed messages are correctly verified.
#[test]
fn test_sign_rfc6979_verify_random() {
let mut rng = ThreadRng256 {};
for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32();
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let sign = sk.sign_rfc6979::<Sha256>(&msg);
assert!(pk.verify_vartime::<Sha256>(&msg, &sign));
}
}
// Test that signed messages are correctly verified.
#[test]
fn test_sign_verify_random() {
let mut rng = ThreadRng256 {};
for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32();
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let sign = sk.sign_rng::<Sha256, _>(&msg, &mut rng);
assert!(pk.verify_vartime::<Sha256>(&msg, &sign));
}
}
/** Tests that this code is compatible with the ring crate **/
// Test that the ring crate works properly.
#[test]
fn test_ring_sign_ring_verify() {
use ring::rand::SecureRandom;
use ring::signature::KeyPair;
let ring_rng = ring::rand::SystemRandom::new();
for _ in 0..ITERATIONS {
let mut msg_bytes: [u8; 64] = [Default::default(); 64];
ring_rng.fill(&mut msg_bytes).unwrap();
let msg = untrusted::Input::from(&msg_bytes);
let pkcs8_bytes = ring::signature::EcdsaKeyPair::generate_pkcs8(
&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
&ring_rng,
)
.unwrap();
let key_pair = ring::signature::EcdsaKeyPair::from_pkcs8(
&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
untrusted::Input::from(pkcs8_bytes.as_ref()),
)
.unwrap();
let public_key_bytes = key_pair.public_key().as_ref();
let sig = key_pair.sign(&ring_rng, msg).unwrap();
let sig_bytes = sig.as_ref();
assert!(ring::signature::verify(
&ring::signature::ECDSA_P256_SHA256_FIXED,
untrusted::Input::from(public_key_bytes),
msg,
untrusted::Input::from(sig_bytes)
)
.is_ok());
}
}
// Test that messages signed by the ring crate are correctly verified by this code.
#[test]
fn test_ring_sign_self_verify() {
use ring::rand::SecureRandom;
use ring::signature::KeyPair;
let ring_rng = ring::rand::SystemRandom::new();
for _ in 0..ITERATIONS {
let mut msg_bytes: [u8; 64] = [Default::default(); 64];
ring_rng.fill(&mut msg_bytes).unwrap();
let pkcs8_bytes = ring::signature::EcdsaKeyPair::generate_pkcs8(
&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
&ring_rng,
)
.unwrap();
let key_pair = ring::signature::EcdsaKeyPair::from_pkcs8(
&ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
untrusted::Input::from(pkcs8_bytes.as_ref()),
)
.unwrap();
let public_key_bytes = key_pair.public_key().as_ref();
let sig = key_pair
.sign(&ring_rng, untrusted::Input::from(&msg_bytes))
.unwrap();
let sig_bytes = sig.as_ref();
let pk = PubKey::from_bytes_uncompressed(public_key_bytes).unwrap();
let sign = Signature::from_bytes(sig_bytes).unwrap();
assert!(pk.verify_vartime::<Sha256>(&msg_bytes, &sign));
}
}
// Test that messages signed by this code are correctly verified by the ring crate.
#[test]
fn test_self_sign_ring_verify() {
let mut rng = ThreadRng256 {};
for _ in 0..ITERATIONS {
let msg_bytes = rng.gen_uniform_u8x32();
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let sign = sk.sign_rng::<Sha256, _>(&msg_bytes, &mut rng);
let mut public_key_bytes: [u8; 65] = [Default::default(); 65];
pk.to_bytes_uncompressed(&mut public_key_bytes);
let mut sig_bytes: [u8; 64] = [Default::default(); 64];
sign.to_bytes(&mut sig_bytes);
assert!(ring::signature::verify(
&ring::signature::ECDSA_P256_SHA256_FIXED,
untrusted::Input::from(&public_key_bytes),
untrusted::Input::from(&msg_bytes),
untrusted::Input::from(&sig_bytes)
)
.is_ok());
}
}
#[test]
fn test_signature_to_asn1_der_short_encodings() {
let r_bytes = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
];
let r = NonZeroExponentP256::from_int_checked(Int256::from_bin(&r_bytes)).unwrap();
let s_bytes = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF,
];
let s = NonZeroExponentP256::from_int_checked(Int256::from_bin(&s_bytes)).unwrap();
let signature = Signature { r, s };
let expected_encoding = vec![0x30, 0x07, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00, 0xFF];
assert_eq!(signature.to_asn1_der(), expected_encoding);
}
#[test]
fn test_signature_to_asn1_der_long_encodings() {
let r_bytes = [
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,
];
let r = NonZeroExponentP256::from_int_checked(Int256::from_bin(&r_bytes)).unwrap();
let s_bytes = [
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xBB, 0xBB, 0xBB, 0xBB,
];
let s = NonZeroExponentP256::from_int_checked(Int256::from_bin(&s_bytes)).unwrap();
let signature = Signature { r, s };
let expected_encoding = vec![
0x30, 0x46, 0x02, 0x21, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x02, 0x21, 0x00, 0xBB, 0xBB,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
0xBB, 0xBB,
];
assert_eq!(signature.to_asn1_der(), expected_encoding);
}
// TODO: Test edge-cases and compare the behavior with ring.
// - Invalid public key (at infinity, values not less than the prime p), but ring doesn't
// directly exposes key validation in its API.
}

View File

@@ -0,0 +1,281 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::{Hash256, HashBlockSize64Bytes};
use subtle::ConstantTimeEq;
const BLOCK_SIZE: usize = 64;
const HASH_SIZE: usize = 32;
pub fn verify_hmac_256<H>(key: &[u8], contents: &[u8], mac: &[u8; HASH_SIZE]) -> bool
where
H: Hash256 + HashBlockSize64Bytes,
{
let expected_mac = hmac_256::<H>(key, contents);
bool::from(expected_mac.ct_eq(mac))
}
// FIDO2's PIN verification is just matching the first 16 bytes of the HMAC
// against the pin ¯\_(ツ)_/¯
pub fn verify_hmac_256_first_128bits<H>(key: &[u8], contents: &[u8], pin: &[u8; 16]) -> bool
where
H: Hash256 + HashBlockSize64Bytes,
{
let expected_mac = hmac_256::<H>(key, contents);
bool::from(array_ref![expected_mac, 0, 16].ct_eq(pin))
}
pub fn hmac_256<H>(key: &[u8], contents: &[u8]) -> [u8; HASH_SIZE]
where
H: Hash256 + HashBlockSize64Bytes,
{
let mut ipad: [u8; BLOCK_SIZE] = [0x36; BLOCK_SIZE];
let mut opad: [u8; BLOCK_SIZE] = [0x5c; BLOCK_SIZE];
if key.len() <= BLOCK_SIZE {
xor_pads(&mut ipad, &mut opad, key);
} else {
xor_pads(&mut ipad, &mut opad, &H::hash(key));
}
let mut ihasher = H::new();
ihasher.update(&ipad);
ihasher.update(contents);
let ihash = ihasher.finalize();
let mut ohasher = H::new();
ohasher.update(&opad);
ohasher.update(&ihash);
ohasher.finalize()
}
fn xor_pads(ipad: &mut [u8; BLOCK_SIZE], opad: &mut [u8; BLOCK_SIZE], key: &[u8]) {
for (i, k) in key.iter().enumerate() {
ipad[i] ^= k;
opad[i] ^= k;
}
}
#[cfg(test)]
mod test {
use super::super::sha256::Sha256;
use super::*;
extern crate hex;
#[test]
fn test_verify_hmac_valid() {
// Test for various lengths of the key and contents.
for len in 0..128 {
let key = vec![0; len];
let contents = vec![0; len];
let mac = hmac_256::<Sha256>(&key, &contents);
assert!(verify_hmac_256::<Sha256>(&key, &contents, &mac));
}
}
#[test]
fn test_verify_hmac_invalid() {
// Test for various lengths of the key and contents.
for len in 0..128 {
let key = vec![0; len];
let contents = vec![0; len];
let mac = hmac_256::<Sha256>(&key, &contents);
// Check that invalid MACs don't verify, by changing any byte of the valid MAC.
for i in 0..HASH_SIZE {
let mut bad_mac = mac;
bad_mac[i] ^= 0x01;
assert!(!verify_hmac_256::<Sha256>(&key, &contents, &bad_mac));
}
}
}
#[test]
fn test_hmac_sha256_empty() {
let mut buf = [0; 96];
buf[..64].copy_from_slice(&[0x5c; 64]);
buf[64..].copy_from_slice(&Sha256::hash(&[0x36; 64]));
assert_eq!(hmac_256::<Sha256>(&[], &[]), Sha256::hash(&buf));
}
#[test]
fn test_hmac_sha256_examples() {
assert_eq!(
hmac_256::<Sha256>(&[], &[]),
hex::decode("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad")
.unwrap()
.as_slice()
);
assert_eq!(
hmac_256::<Sha256>(b"key", b"The quick brown fox jumps over the lazy dog"),
hex::decode("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8")
.unwrap()
.as_slice()
);
}
#[test]
fn test_hash_sha256_for_various_lengths() {
// This test makes sure that the key hashing and hash padding are implemented properly.
//
// Test vectors generated with the following Python script:
//
// import hashlib
// import hmac
// for n in range(128):
// print('b"' + hmac.new('A' * n, 'A' * n, hashlib.sha256).hexdigest() + '",')
//
let hashes: [&[u8; 64]; 128] = [
b"b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad",
b"ff333794c5afd126a4e75aef1a35595a846e9e1d4053017d78d7aa3d8373182a",
b"7c1d0c177d40e7fa03cd1fa9cfc314888985aecde8f586edfb05e71e5f109c20",
b"8f7afbaef39ad155ba09bcbb386a08257731fc06fb2c1d3cff451af5386c0e7d",
b"a4dbd2915084ba3bed9306ba674c1eb22fae1dffd971c95b62ab17f0711480cd",
b"f59d521db107b4265d995f197b189de468b984816d2a01dc8ca3fcfc24d6ff37",
b"29e0656a90f3975e41c8b7e55d225353c3bb8bc0b36328c8066a61763df70b83",
b"25a85cdd13b683f3cac732fa1f19757afffe7013ddbea6e441af883379bf4232",
b"5d0b0812ecb57fb4be7f29a8978cc4f2c35b32417cc9854e2702f7fb08f6d84d",
b"d5e12df428ebd9d991a280c714c9197b977520a7fea87200177cf03618868cb3",
b"fa311e0cd19106ab33f8ee84cafdc2f03be787679c1fe7b6e64df2b2e7466ca2",
b"9a481f04a2f40d561e8e6c4850498699b36e915993153e9f9b5a4485cb0541b1",
b"c8ae9a117e3a5c9125cc21c7f9df09de50de1a6846caf13586d1e5efdfcc1ce6",
b"5ef3a488aaffb5db9173ef59e65c2dd27f4cd1a10e1b464ef5bf82d2e35eddd5",
b"e5753e8febbb38a97c1dfee23a6103fc58416b7172bab834fe5684b00800abd5",
b"0ed714c729a3db2ffde2c4ccb9f5da498c5a73a2c7010d463a7b5da8d18127aa",
b"950918cfdb0cb20f327ba0b5095d53c0befb66b9f639d389020453fcf18e8c40",
b"699470b9775ec45e9024394e7ebb16463534ed7a617bafddca11a3a0e61a3694",
b"95e8c0520fc4dc4c85e00e3868c16ab22a82e8c71ca8ea329ae1ecef0ee3968a",
b"7964fba6a123164167cbf51dc2c53948e13b2fee67d09f532e8b7bc56447c091",
b"c7d07a5f715b3ea44c258de03f2000ba79a44dd8213feb6e6006e1c3becbedff",
b"3eb1a7bf7e4f5c2d9b8cc12667ada8d7773cb9e9424104a30063778567df9422",
b"19cc344ad67db96ea936ef15cc751b29fa0409f5c9894d2cfeb100d604653ffc",
b"91001e472df16d68ee8033cd13d76a26543ccdfe1426cc6e969759b05ee7d115",
b"65f1f4670f8537f37263dabedce049b0e7d1e71f741781413cc2d5c81ecd6ac3",
b"0cf5de0ada8b717296a34fc386a8b77f60b607a48a899bee37650891a616dae7",
b"de3d56f0c83c992163aac087c999ed8eb5a039f21b0536a1967e747868dafd56",
b"0bc3fd1d46d2dc4e2d357d1f6b437d168051d6f19975223505fc2d0abddc3faa",
b"1e30596f4144ca58f3e306548cd079cc92a51ab825a4ad3246393c22283af640",
b"c2fbc726bf3eb7f0216c7e1d5f5b475a93b033b3f901a4a4dca6bbefc65b68b2",
b"1c4ef56d530bb8b627df49ea7b31cf9520e067a2fd0c671896103e146dd4564a",
b"9aeed0f7808bd6c13ce54aa5724484f41bd7cbb5e39fd1d7730befbbf056a957",
b"e58aa85e83553b7fec841cbaf42cede943b6b7ded22661cd3b1867effe91b745",
b"790fc5689193ac57c97dd25729003f2a0d8d3e5f9d2a39e007b794282a51cd3e",
b"be067b95a45cdc0060d2c3757597d8d9b858128435e93346c28ce2e82a68e951",
b"8734f497f5cd2c8667c7d8e1c2328e7e11fa80fc26c7d933937490d37718871f",
b"e8a2d0e77dfad5b046bcff0340a975300b051a21ac403dd802348511a80ba8c8",
b"4afec38787117ab6e71c34a4be7575643d8e74fc16b9d5666157fd9aee0f6e86",
b"ac8b2831d636384d1d3ff5dd77b249860bd88d5aa9af3e1d4ee70be2a1b03db9",
b"e92e1ab3934d3ed2073973204aaba03de3bc4e864cc74677b560c42971b26ab1",
b"312effff0c19cf410b9e227654211133f29276c781baadbe00a1e8319e06e361",
b"d46158da3c64439f8f176fd5e3d5ac59dcaa6c0835715c5ef30abedf34b13c59",
b"693d18266ec508515b9a3839e5336918d41ec7891feadd684b49c03093bd2061",
b"440b6a14be7bc2a1ec475a197fe4bea720d1214883e4d1e2029cf0f75fcdba29",
b"ca8e30319508df21a851a06f543f59bf6fd3b241e5a52b36fb674b0d9d5e8f67",
b"fa4f327635ff5c7051d6968daf5ffcc827bbd0da1e1c56d59918895bc418be98",
b"0e6d0dd75bc42aa6e245a212ff027bc701a7ef61179b335365a29f545bcf45e0",
b"57a08bef7822c2111ac79062240e725611322543f10758763c1c6467021c4fe7",
b"29768d5fb640a46e0129303128669eb3c7fb357ef1c49506f6300cc8e451d5e2",
b"009a868f1065ccb4227dc28084484263495ad90378dc928fc61d361eef2d072e",
b"6808e39e343af0fd53309fc02b05da1a0e68b87d5cd434e94521c635a78d7fdb",
b"8fe1668eba03be5444e0956396ac9d81ac1c4a7beb6a01151ad679f5ca0cd206",
b"01f41c1cc6d9d260ec3d938d681fc476415aae96a318862a492ba1a56f1b0a88",
b"3100bc758eeccb959376b334f999a2b4e5fcced5b5d4956510a86b654f1f0c04",
b"6225330aedced9909d4a190dba55e807624f44e7c6e0c50cac5e4ccf8e2e0029",
b"783111276f7218e3e525c83cdf117e2d5ce251f6a04beabb65ef565f513a9301",
b"4b365ab05720ad517f46df03ff441f9e0769a2ce5279663b7d90eb7d980625ef",
b"52431871c39a881c63df82860e32ccf05c1addbc630aaa580733f2e6a2fff5a6",
b"f017486486b0e308a10862e910f22545c29670daa26bf0c6791827a7f9f625a4",
b"85efd1eface951759a4642e882d0ef8d0be58afd483e0945d03a7a35fac789ac",
b"880872df19c7ff14105ba59cebc07d9e9d7e67f4896a14acae5346c66c6ce2da",
b"85ba2aa3634c619d604a964d62ae3c97f9eba7fcb7e4db2ebfa2bd23338c2d60",
b"5aa9736d405016676878fcc63e84b286cfbc843799ea786d089b2200281d5a5c",
b"30f43d84f3d5ffac60323a126fe321c6cc1e9c440249a8d69abe172494cba7ae",
b"7dce62ce40f8f4cda666341730e7dfcde8839eed4236c58ae273e6687d229d85",
b"83d670a41779f63fad0ece766a19920e0cfdd9d02f5a5900c888de21f6ae0526",
b"bb2acf0d6d39e58b09204dedcc2fe68ad829ba471a077e6e03246d8a0b0c0858",
b"1f94db9ee970a9fcc9089865eb2aa485765345f6d4de54815507ce363bc20711",
b"b4bceedc935c574935117f7ad280a7d858da7ca5a6b0920b4975111206fcac77",
b"b9da394c337e9aa150c12e54c574978773ff953270f5aefde88a766e9874c260",
b"1769fcb5d31c8c09868e4e3dcd9db92b4cccefb5660e72bfc52159fda9da8518",
b"d8ceb568f85e30cb48cabf8e84d577369033511cbbdac6a7996cf9f397c2e203",
b"64c35795b87cbb02afcdc6a5e6bacb10d98cdd1bd810ccf12c847fbdcf4d2634",
b"76ccd4e2b71a826128b60bc9fe33613d82f0ae1f57fa192f107ed54d25a842e0",
b"095450e0f61a4201bb2197371247bb7ced09056d86e901202ecc561c3568e032",
b"0e928f8e201fd3019f11037bf164cc3d719ecf08e6eac985f429702c41f25d0a",
b"135f37174ff19409cef67f3263511ed9286901090eec2b54d9444036308a72cf",
b"51eafe6978c32396022a31230b8b9120ac7bd79ad7a3303e6b6979063275c9b8",
b"fd2fb9443156429b2bc042248bf022f18ee6ed11fefea222893c49e8fef6a17e",
b"ed9a240e63644aa55c71fb339d79e1a38de71002c30baf14af38359c513de2e0",
b"c925e74d4740558277a55fe57ba88ed05ce8f5d5c35c19e7228adc09351ecfa4",
b"cd99660a7c2aded095152bc6d5fa160077355819fbf421acb95ab39ad8c27862",
b"42cf7593a535a1e79299c2839f4e0ffba5b429cb0df6c77d3fe86b6a1535d505",
b"348c6014dcb0cd583862c09ad24aa5d93e81e2f6ca4b04f4e77e50067f34e625",
b"8b00c1d89bd10b24bda2c8f6e45c4112112baacab29d0330b377d811a7b0184e",
b"dfe3960732f8e5958085a581859f6ccf40169df965bb8ff5feb4b0229a02c6f8",
b"de0aa4189c97d17df38c0ea3bc9376287076939afd515336d5d7d851f81f2517",
b"543190454858ff5396a1de3f753f84bdd2869fd2b59e3a89f090ce06bd94d626",
b"541ddbe00a0237c5c8bd043e6cced9ce78209dd83b057272cd46c2cc2f39a88c",
b"11c82017445f7e295d4c734a40cf28793df855dd321d507d4a0f3e212293ca2b",
b"cda1ecd6ca2f3858352985b4833170589e17e1f7f464e279cc78051911b8e8d3",
b"5feb471949318b26898b3339ac7a66e464a752223cf764aa0af9292fe087c39a",
b"eb48e5de63ecd22f7b305c7e74ce8cc714ab858cf834cf485727868e017e473e",
b"03428482b5208a35032777c7d628a6c8f3b07c5c87c641ddfb3adf46ffefe449",
b"a8e0cd1dfcf6e1a29ba032d3889fca2f25e3fad1a9b1c36e4978e48945b06092",
b"6cf4280b75da3bb22ddee9a9a3fdd1d0cd04627c00f73b608e44be9ce84869db",
b"9fa7648f23c405938b6fb8eaf6a24c476dafd05625a9a8f6c52e1abb9d432a76",
b"2906f0a6276e9a1ba4fbca2f335d9f7d3c331684814ac5407145d86891ba37f7",
b"1b667ee18a909e3f828f2bd6a162e3aa1361f3801b7cbc863b1b54a1ccfbf580",
b"a75e75962b3f950f7718839ef06cc09112806dbf88b142e369cf1ef99069c226",
b"71b2e2f6d66f13b919a842843b201c25249ff4b4caa4c7ab079b2980de8a18f6",
b"c4a9e73df196f876f5a3af1c8836504ee61daac5d9e15cc043a511310c22ddd8",
b"88e3303a6a2ab03430652fea942ae7cd96618fae4addcf8e92989d542777e496",
b"9a727095299564e2f5e1598f1a4095a2a000cb9196fe4eb13447932af777be3c",
b"5643a1c72b189d462236a43afc7d0b9504cbf81b4fa9a6c9cca49bd50da299df",
b"caebc47e2204fe19e757372c2e0469a34051415a09c927e63be7747903d80af5",
b"e5c9fd4bd27e7a55958cb5f66ff88baf80ab40d9690e81a9cf03ada5bd08cd44",
b"dc606eb9a631ca3f080f6d6f610444201608f47b5b49c75c2c0ec03ba9000009",
b"bce230b32a7dc676fb98a4a3d41c4171e9e173e840b92c194fb1dc4accc079b9",
b"51542ff3b57cd2ff6b1542649f7a44dbed32194b98c3af32b6ff3eefe6b490cf",
b"703f5dea8c9e3ed75c691fc17699b9648a65a331add554fa3613ddcb7267565a",
b"d74f9f60763467ce0b35ced0630ecf58605da0ca49e058de21524b5c532b5de8",
b"e9dacaf1fefaad6d9d372affab8fb5216004fb3fa7a9b86b25ecd00e583c22a5",
b"abe2c75f1ac881b743da99c543506c4b7532f3fc445fa8cbf1df22689770d66a",
b"7be506d2fd6dc79f0b14ddfff0147c79d78d99140547efcd03d0a73819b84c5a",
b"78dbc5c946ee8aa147ccfa8b5d9231c95c4257d8c79bd219ab95d53303367309",
b"1d75ee600f2ba216d211189493d793aa610aa57ccbfc4d9a7f44194e7166a062",
b"368a4d0ae1b139d71f35ba5f917a7ad4c18e6aa51b095cb135193dcd09e299b4",
b"a9d3202db927be8f0d15d2dfb83ea09db32fec3b1fc10a6acfb91da8c3c5eaf3",
b"c2284f8efeee554cc29a8802aadd7cd88e84561d353282ee31322ed497a3336c",
b"7695648a111e2ea51013f03c9de91d81a2435a7777f303e51d027750f8381680",
b"719fc44e0f64f7da9ac5d33d9ca912fdc839bb4535c66a21f0804f2cdf800666",
b"6940c082413b0c1ced6f9cb6583588c472ff72b48b00a4fb6d2710d7ac4dad99",
b"af1f26fcf070d9f5926dd41db3c09ec6b4c3f2208775cf983330cd0ff5aa239e",
b"ae50df4404a7f46146d8112bfb1cde876e591abe5ef1640e27c4d178a84b6335",
b"50f91f48df7f0f96af954be7e1b518bac537173cea38be300d98761da1d9b10f",
b"9c9aee382b3e3417e87352bdcb48837e88335e9dd0112fc22ecf61e766a6ac43",
b"d53cee1696c613f988520cf9c923c7cb6e6933b4faf57e640867d5f45a0f2569",
];
let mut input = Vec::new();
for i in 0..128 {
assert_eq!(
hmac_256::<Sha256>(&input, &input),
hex::decode(hashes[i] as &[u8]).unwrap().as_slice()
);
input.push(b'A');
}
}
// TODO: more tests
}

View File

@@ -0,0 +1,67 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg_attr(not(feature = "std"), no_std)]
#![feature(wrapping_int_impl)]
#[macro_use]
extern crate alloc;
extern crate subtle;
#[macro_use]
extern crate arrayref;
extern crate byteorder;
extern crate libtock;
#[macro_use]
extern crate cbor;
pub mod aes256;
pub mod cbc;
mod ec;
pub mod ecdh;
pub mod ecdsa;
pub mod hmac;
pub mod rng256;
pub mod sha256;
pub mod util;
// Trait for hash functions that returns a 256-bit hash.
// The type must be Sized (size known at compile time) so that we can instanciate one on the stack
// in the hash() method.
pub trait Hash256: Sized {
fn new() -> Self;
fn update(&mut self, contents: &[u8]);
fn finalize(self) -> [u8; 32];
fn hash(contents: &[u8]) -> [u8; 32] {
let mut h = Self::new();
h.update(contents);
h.finalize()
}
}
// Traits for block ciphers that operate on 16-byte blocks.
pub trait Encrypt16BytesBlock {
fn encrypt_block(&self, block: &mut [u8; 16]);
}
pub trait Decrypt16BytesBlock {
fn decrypt_block(&self, block: &mut [u8; 16]);
}
// Trait for hash functions that operate on 64-byte input blocks.
pub trait HashBlockSize64Bytes {
type State;
fn hash_block(state: &mut Self::State, block: &[u8; 64]);
}

View File

@@ -0,0 +1,91 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use libtock::rng;
// Lightweight RNG trait to generate uniformly distributed 256 bits.
pub trait Rng256 {
fn gen_uniform_u8x32(&mut self) -> [u8; 32];
fn gen_uniform_u32x8(&mut self) -> [u32; 8] {
bytes_to_u32(self.gen_uniform_u8x32())
}
}
// The TockOS rng driver fills a buffer of bytes, but we need 32-bit words for ECDSA.
// This function does the conversion in safe Rust, using the native endianness to avoid unnecessary
// instructions.
// An unsafe one-line equivalent could be implemented with mem::transmute, but let's use safe Rust
// when possible.
fn bytes_to_u32(bytes: [u8; 32]) -> [u32; 8] {
let mut result: [u32; 8] = [Default::default(); 8];
for (i, r) in result.iter_mut().enumerate() {
*r = u32::from_ne_bytes(*array_ref![bytes, 4 * i, 4]);
}
result
}
// RNG backed by the TockOS rng driver.
pub struct TockRng256 {}
impl Rng256 for TockRng256 {
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
let mut buf: [u8; 32] = [Default::default(); 32];
rng::fill_buffer(&mut buf);
buf
}
}
// For tests on the desktop, we use the cryptographically secure thread rng as entropy source.
#[cfg(feature = "std")]
pub struct ThreadRng256 {}
#[cfg(feature = "std")]
impl Rng256 for ThreadRng256 {
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut result = [Default::default(); 32];
rng.fill(&mut result);
result
}
}
#[cfg(test)]
pub mod test {
use super::*;
#[test]
fn test_bytes_to_u32() {
// This tests that all bytes of the input are indeed used in the output, once each.
// Otherwise the result of gen_uniform_u32x8 wouldn't be uniformly distributed.
let bytes = b"\x00\x01\x02\x03\x04\x05\x06\x07\
\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\
\x10\x11\x12\x13\x14\x15\x16\x17\
\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
#[cfg(target_endian = "big")]
let expected = [
0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f, 0x10111213, 0x14151617, 0x18191a1b,
0x1c1d1e1f,
];
#[cfg(target_endian = "little")]
let expected = [
0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, 0x13121110, 0x17161514, 0x1b1a1918,
0x1f1e1d1c,
];
assert_eq!(bytes_to_u32(*bytes), expected);
}
}

View File

@@ -0,0 +1,423 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::{Hash256, HashBlockSize64Bytes};
use byteorder::{BigEndian, ByteOrder};
use core::num::Wrapping;
const BLOCK_SIZE: usize = 64;
pub struct Sha256 {
state: [Wrapping<u32>; 8],
block: [u8; BLOCK_SIZE],
total_len: usize,
}
impl Hash256 for Sha256 {
fn new() -> Self {
Sha256 {
state: Sha256::H,
block: [0; BLOCK_SIZE],
total_len: 0,
}
}
fn update(&mut self, mut contents: &[u8]) {
let cursor_in_block = self.total_len % BLOCK_SIZE;
let left_in_block = BLOCK_SIZE - cursor_in_block;
// Increment the total length before we mutate the contents slice.
self.total_len += contents.len();
if contents.len() < left_in_block {
// The contents don't fill the current block. Simply copy the bytes.
self.block[cursor_in_block..(cursor_in_block + contents.len())]
.copy_from_slice(contents);
} else {
// First, fill and process the current block.
let (this_block, rest) = contents.split_at(left_in_block);
self.block[cursor_in_block..].copy_from_slice(this_block);
Sha256::hash_block(&mut self.state, &self.block);
contents = rest;
// Process full blocks.
while contents.len() >= 64 {
let (block, rest) = contents.split_at(64);
Sha256::hash_block(&mut self.state, array_ref![block, 0, 64]);
contents = rest;
}
// Copy the last block for further processing.
self.block[..contents.len()].copy_from_slice(contents);
}
}
fn finalize(mut self) -> [u8; 32] {
// Last block and padding.
let cursor_in_block = self.total_len % BLOCK_SIZE;
self.block[cursor_in_block] = 0x80;
// Clear the rest of the block.
for byte in self.block[(cursor_in_block + 1)..].iter_mut() {
*byte = 0;
}
if cursor_in_block >= 56 {
// Padding doesn't fit in this block, so we first hash this block and then hash a
// padding block.
Sha256::hash_block(&mut self.state, &self.block);
// Clear buffer for the padding block.
for byte in self.block.iter_mut() {
*byte = 0;
}
}
// The last 8 bytes of the last block contain the length of the contents. It must be
// expressed in bits, whereas `total_len` is in bytes.
BigEndian::write_u64(array_mut_ref![self.block, 56, 8], self.total_len as u64 * 8);
Sha256::hash_block(&mut self.state, &self.block);
// Encode the state's 32-bit words into bytes, using big-endian.
let mut result: [u8; 32] = [0; 32];
for i in 0..8 {
BigEndian::write_u32(array_mut_ref![result, 4 * i, 4], self.state[i].0);
}
result
}
}
impl HashBlockSize64Bytes for Sha256 {
type State = [Wrapping<u32>; 8];
#[allow(clippy::many_single_char_names)]
fn hash_block(state: &mut Self::State, block: &[u8; 64]) {
let mut w: [Wrapping<u32>; 64] = [Wrapping(0); 64];
// Read the block as big-endian 32-bit words.
for (i, item) in w.iter_mut().take(16).enumerate() {
*item = Wrapping(BigEndian::read_u32(array_ref![block, 4 * i, 4]));
}
for i in 16..64 {
w[i] = w[i - 16] + Sha256::ssig0(w[i - 15]) + w[i - 7] + Sha256::ssig1(w[i - 2]);
}
let mut a = state[0];
let mut b = state[1];
let mut c = state[2];
let mut d = state[3];
let mut e = state[4];
let mut f = state[5];
let mut g = state[6];
let mut h = state[7];
for (i, item) in w.iter().enumerate() {
let tmp1 =
h + Sha256::bsig1(e) + Sha256::choice(e, f, g) + Wrapping(Sha256::K[i]) + *item;
let tmp2 = Sha256::bsig0(a) + Sha256::majority(a, b, c);
h = g;
g = f;
f = e;
e = d + tmp1;
d = c;
c = b;
b = a;
a = tmp1 + tmp2;
}
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
}
}
impl Sha256 {
// SHA-256 constants.
#[allow(clippy::unreadable_literal)]
const H: [Wrapping<u32>; 8] = [
Wrapping(0x6a09e667),
Wrapping(0xbb67ae85),
Wrapping(0x3c6ef372),
Wrapping(0xa54ff53a),
Wrapping(0x510e527f),
Wrapping(0x9b05688c),
Wrapping(0x1f83d9ab),
Wrapping(0x5be0cd19),
];
#[allow(clippy::unreadable_literal)]
const K: [u32; 64] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
0xc67178f2,
];
// SHA-256 helper functions.
#[inline(always)]
fn choice(e: Wrapping<u32>, f: Wrapping<u32>, g: Wrapping<u32>) -> Wrapping<u32> {
(e & f) ^ (!e & g)
}
#[inline(always)]
fn majority(a: Wrapping<u32>, b: Wrapping<u32>, c: Wrapping<u32>) -> Wrapping<u32> {
(a & b) ^ (a & c) ^ (b & c)
}
#[inline(always)]
fn bsig0(x: Wrapping<u32>) -> Wrapping<u32> {
x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22)
}
#[inline(always)]
fn bsig1(x: Wrapping<u32>) -> Wrapping<u32> {
x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25)
}
#[inline(always)]
fn ssig0(x: Wrapping<u32>) -> Wrapping<u32> {
x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
}
#[inline(always)]
fn ssig1(x: Wrapping<u32>) -> Wrapping<u32> {
x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
}
}
#[cfg(test)]
mod test {
use super::*;
extern crate hex;
#[test]
fn test_choice() {
assert_eq!(
Sha256::choice(
Wrapping(0b00001111),
Wrapping(0b00110011),
Wrapping(0b01010101)
),
Wrapping(0b01010011)
);
}
#[test]
fn test_majority() {
assert_eq!(
Sha256::majority(
Wrapping(0b00001111),
Wrapping(0b00110011),
Wrapping(0b01010101)
),
Wrapping(0b00010111)
);
}
#[test]
fn test_hash_empty() {
assert_eq!(
Sha256::hash(&[]),
hex::decode("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
.unwrap()
.as_slice()
);
}
#[test]
fn test_update_for_various_splits() {
// Test vector generated with the following Python script:
//
// import hashlib
// print(hashlib.sha256('A' * 512).hexdigest())
//
let input = vec![b'A'; 512];
let hash = hex::decode("32beecb58a128af8248504600bd203dcc676adf41045300485655e6b8780a01d")
.unwrap();
for i in 0..512 {
for j in i..512 {
let mut h = Sha256::new();
h.update(&input[..i]);
h.update(&input[i..j]);
h.update(&input[j..]);
assert_eq!(h.finalize(), hash.as_slice());
}
}
}
#[test]
fn test_hash_for_various_lengths() {
// This test makes sure that the padding is implemented properly.
//
// Test vectors generated with the following Python script:
//
// import hashlib
// for n in range(128):
// print('b"' + hashlib.sha256('A' * n).hexdigest() + '",')
//
let hashes: [&[u8; 64]; 128] = [
b"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
b"559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd",
b"58bb119c35513a451d24dc20ef0e9031ec85b35bfc919d263e7e5d9868909cb5",
b"cb1ad2119d8fafb69566510ee712661f9f14b83385006ef92aec47f523a38358",
b"63c1dd951ffedf6f7fd968ad4efa39b8ed584f162f46e715114ee184f8de9201",
b"11770b3ea657fe68cba19675143e4715c8de9d763d3c21a85af6b7513d43997d",
b"69dc6c3210e25e62c5938ff4e841e81ce3c7d2cde583553478a77d7fcb389f30",
b"0f0cf9286f065a2f38e3c4e4886578e35af4050c108e507998a05888c98667ea",
b"c34ab6abb7b2bb595bc25c3b388c872fd1d575819a8f55cc689510285e212385",
b"e5f9176ecd90317cf2d4673926c9db65475b0b58e7f468586ddaef280a98cdbd",
b"1d65bf29403e4fb1767522a107c827b8884d16640cf0e3b18c4c1dd107e0d49d",
b"dd20088919031875b7bcca29995545dd40ca994be0558183f9b942b51b3b2249",
b"0592cedeabbf836d8d1c7456417c7653ac208f71e904d3d0ab37faf711021aff",
b"3461164897596e65b79bc0b7bee8cc7685487e37f52ecf0b34c000329675b859",
b"14f99c4b0a6493e3a3f52022cd75276b4cff9a7c8eef74793267f687b600af96",
b"6f9f84c09a5950e1ea7888f17922a69e5292dcbcb1e682ddfc977a9b4ea1a8c0",
b"991204fba2b6216d476282d375ab88d20e6108d109aecded97ef424ddd114706",
b"444074d5328d52b4e0036d37b1b6ea0a9fe3b0c96872d1157fbf01b6fdb2ce8d",
b"d273c6b6de3f5260e123348e0feb270126fa06e164bb82818df7c71b30ab0ef5",
b"234b7f9389f9b521f407805760775940d79a48188338d02a1fe654e826a83f69",
b"edfcaac579024f574adbcaa3c13e4fd2b7f1797826afe679f2144af2cb5c062d",
b"f48de1653fdfa9b637b7fb4da9c169a1f2be6a1ec001e3d2cca44c669a693ecf",
b"8a5bdb4cc15164126c6ef2668de9dd240d299ce6397a42c95a9411b93d080ed8",
b"1786ac1492c6c922c2734e4d3d8e9b030cfba291a72bc135989c49fc31171ac2",
b"1bda9f0aed80857d43c9329457f28b1ca29f736a0c539901e1ba16a909eb07b4",
b"6724431fc312ba42c98b38b8595a49749419526aa89722c77a85c6c813dfdb5a",
b"06f469c97c14e84c74853bb96aa79305eb4f6635291bf1202c4fdadb82706204",
b"568f214d529544bf4430513c2993495a5b434611533c63d1cf095b51c5e1f8af",
b"c84f7630cbe823fc4d80f605b98294592f15b14db1f78d6f18e686c1f8cb5ded",
b"a7951e0ca2e9612a985a36747309822a67a9b8c1a5abd848c03e82216c85f1b3",
b"37b9403cf88cc2639d0a118d757a43a0ff6d4871823707ab6a8bb56bc68e8e79",
b"55ee740f58335c97d42c32125218eb7c325fbe34206912f1aa7af7fd6580c9a1",
b"22a48051594c1949deed7040850c1f0f8764537f5191be56732d16a54c1d8153",
b"5d873590851b7b00b60490c8e6966b3409c385adcc9590d801f0e03e268b5ba5",
b"1e98a405718c430a4067d75125015a947a971449bc433b078418438c48bc6046",
b"015c50632207f69408c05d20e36facfad9bde74c727f933023f54cd6e8b87372",
b"a3b99d59dbb025726312e812c2821cfbe55189f515414bdabd5e3d284c8ad6f9",
b"7d24c321bfb2a5b6d2c7a3c2948855cef421d08352dc296ed95c6f645fcce441",
b"876fc5bf6bde065afea543aceb645ce17ffe3c9d8df9c6073ab31f3a562f4257",
b"b9b515854e040b8de31d85d597aba28db4467fd0a7d6eb77a31005f4a67a8fb3",
b"f0a2fb80ac0699075fb6c7b0ee2bcc204a1d909ee3149571216ec9cc1d4b9f8e",
b"b78244167af116f2b3597b4a81421bd2b28f3d8bf616025a5ae424f689fd7632",
b"d85ce644bf4e82cee032eaa5c3d9030a090276d9bae3703112bdfc6f8fdde307",
b"0f007385b6f9d4b7eeb2748605afe1a984a0a3bfa3f014d09e2a784ce9e5cd1a",
b"b06b3f20c246db70a136e3ae4787d0df96db4f693d215c21883d3c19700fb276",
b"ac752ced452069c55c7567a0717b87615824c568dc98c8626ac85fc34b234c3b",
b"91a07088de2d0fe9f31567b05d290e65feb06758d000ec463f7f5a6e82ce00a5",
b"abf6c5d1b6512e188f1da6a72e974f7b98b5bac62453f1748c8f9ab180803fdb",
b"4739dcdbab0c377161c539af55d47c5c90c87807d0728aabe91697b66e29096c",
b"ff85f0693c8e6bbeeaa1f90c32e1159b9b545d830ffe58cd80cb94d9d8140d21",
b"509ddb85fdf92f197d32570c005cdcb6dffa398f088bd1a013459f6fb1f730ef",
b"1d31616e307323bd80775ae7483fce654a3b65bced7134c22e179a2e25155009",
b"3e1ae21112ec8fad05e3676e1940da52d56771162142aac4d73743e7df70b686",
b"5f2671f97427c8873e5af72686d244e4c8126a4f618983bae880a48a834a0607",
b"2d0009d7df28cdc6b5a4c36063d97415a8fe99515317458fcb0b0e2a821dbcb9",
b"8963cc0afd622cc7574ac2011f93a3059b3d65548a77542a1559e3d202e6ab00",
b"6ea719cefa4b31862035a7fa606b7cc3602f46231117d135cc7119b3c1412314",
b"a00df74fbdadd9eb0e7742a019e5b2d77374de5417eba5b7a0730a60cce5e7bf",
b"cee244d999f8cf49f2a4ee4d89695130c9c95c33538cedf0306881ebd42714d2",
b"5b29354ee33cba5b924ded5e3c873a76e1d12527d824ace01ff9683d24e06816",
b"c5fb235befd875b915fa6c4702a7abb93cacf3d7c414b71cbeff9e1b0a9fbd41",
b"0ae45129ef1edf64309559f6cb7bb0af16eff14ad82f24d55fa029c1b4144078",
b"5a2aafcacb9828e41fb7c8f8098952638645874b3a8ca45d2523fb2d5fc7166d",
b"1b58d00f5b1fbd2a1884d666a2be33c2fa7463dff32cd60ef200c0f750a6b70f",
b"d53eda7a637c99cc7fb566d96e9fa109bf15c478410a3f5eb4d4c4e26cd081f6",
b"836203944f4c0280461ad73d31457c22ba19d1d99e232dc231000085899e00a2",
b"fd8afe9151793a84a21af054ba985d1486a705561e2a50d4a50f814664f5e806",
b"f495547fca5a5a2c40dccebefe40160efb8bc2888e8afef712b096b5f2585b44",
b"ba31b89f9486439fdf551f597fede0c10260f9b404866dba4a6555375f486359",
b"46f23cc7ccba8af67978bea568e63cd045be72aba974132b1b14cc59277329f1",
b"01d3a187638cc1a7740a74fbeb57aa2648dbdec42d497321912bf393d283ccd1",
b"96b437b3df7c62fc877a121b087899f5e36a58f6d87ba52d997e92bb016aa575",
b"6a6d691ac9ba70955046757cd685b6257773ff3ad93f43d4d4812c5b106f4b5b",
b"beb869adc22a7e8fbd5af12cbf3ad36dd92dca6ebf52ef3441ed6cd0dff24dc6",
b"0f40cb2f3661d73dfaec511e8ebea082fb1f77db45bf8c9ba7c9708da6ba6301",
b"ddd5d1ecc7af6a5b0d18e0825004d3bc9d52e2cdf14bc00c7474f16941a64acc",
b"6a10b9a8a33d7814ce73679ace5c43657aa6d63169ce215fd85177c77a94147d",
b"9d887d47c78267827dac4afb2cbdcc593d1b89c1d0c1f22c3800cae7916962cd",
b"e45ca598e970afb0f1f57bd34e87065839d2fac524421048fbec489f68e1fd0d",
b"1581baebc5f9dcfd89c658b3c3303203fc0e2f93e3f9e0b593d8b2b8112c6eda",
b"d9b1f3e2c6d528668a73f22575c44ed9f98d9c684964761b621417efd80d7a60",
b"9feacd760dfda20e5e0accf9ddeb8b5c01276a56dc3518046a26f5276fe15041",
b"6aacf5279e24979684fab16fb5495c3ac1dfcf7138b0825376af83473d07cae9",
b"cd2f0deb953014ee400eddef094602d9676e0fd2269d22818f0d5bc198d44d8d",
b"ff9265df14681e44d170fd2b10c6cdf3991f731601d6b89cafe39691d3b42559",
b"6c99e32b005a3a4956b9406ab15411e666c7f67982db170ae1fb111ec634b9c4",
b"e1659ad54063a379f77fee108a376a6a7d5ae3d0c437bf847203963bd0078dfc",
b"572d07a66fccf05d5f73c913552e12d9ffb39a15d01a8fd48cd6aaaab86f4f14",
b"ca97d312ef8551820844548f300f9528f27d53f6ad3910ed2709f2b35c9591f3",
b"97654dc78f4f7d4cec4b4870e6ee0a87abacc89337ed0629e2e511e4466df56d",
b"fde923c1ed5e5cd32c629bdf341db32c0f72ba8f1e2afd9c194e87e0e3d9da5f",
b"d6624a66f3bcc4adef8a17abf9eeb1fbf23746165b2f90f9cb3a679a58e4958e",
b"8676909e9578a790f84be31fe94f4d22488f912b754ee816ba0a5c4a392305a5",
b"57f65fd8a95ff738b95dba0f1606025535e34591f1b58b00d33958093808360c",
b"f6afcaf794fe0e04d6ec18bbde55412a60c0c5ef55e75223b817e97f208bbccc",
b"6121f27b52c1f17ddce365143ba58a720fa303707faa32a4e5e89029f34ac618",
b"69d62c062d67d8d2ce9068c1898fb9746c911839aa88ad1628d090f4c8e47f05",
b"eb9f8b69313e19e14b1043b3cac05d18d40321536ad485be8145007aefa9295d",
b"b1cfb0f511886ca07ade919740ca95e1b3d998ba7cb66ba2badd53be28f5f509",
b"d0118863549f990558685da9090ca8eae8c809c5545c4aa85f8e5eec413b2555",
b"d82c6aa133a0fc25b087f46ad7ed2a3042772e612e015571e61753ff55ba6da8",
b"aac76dab773c00c8ad4bb128147945c70798eae5a2511fef01e853c6e3051ab9",
b"ccd77d7adb6178ee3e3560ba4583044a36b296257ae4c5cfead96d46af31fccd",
b"3c4f48a886b2de7e908d6a626074e7515265cc9d1188c161cf159fd376d3d5f8",
b"7f9578a31905e95a16cc9d3e7b57dc3158a23dccf359a1f2cf09e73eb13e5cde",
b"770492ebaee89a20d19f9972c3e3d0c7d51c9baaedf06fdfe9a7b69da3394779",
b"893785aaddea396621c31dc5d465e2775cbc6b7423dc3498e80aa5da7a6a819d",
b"1b2b69fbec485ef3f347ee6dc9c87d73505e45b5c9b02599b823ac94f5d642a1",
b"724b4b3d3e8ac7588561ca00eec11693f6b85c03bb6b1302d458a7a4ce4b39e4",
b"6a30ef4094128b6fa463b70cb21d141da92711d80ea94c9b73fb8a0471cc49a9",
b"50968cf735e3f6a47834ae3745816234f72fd156aef1bec4b6a7d3a3151773bc",
b"3ed01dd816dc93ea2d445681df11aa24e9fd1441de429eb0ee7816ccc09a2b7a",
b"64bdc48c731313c7b37c1f1d13d6265ac7a2604ff630b50f591a86e610cb3005",
b"96666c386cf99a74ec9eb55a5545aa90a3e53a8bbbe74cd3334b32d4968a3214",
b"33555a41335654a29d5b7799bf180915e09095d21991dacf071583957b9e3f35",
b"ffd391d554ce0672ae818a149dd55325f4cb933c97017b8148934474355d5a88",
b"cf2050114ccaefd8a0ea6cf31d85e0232eadc8fd61277ff16496d2234b55c7d7",
b"e42142b4243d5a2c59a2977d0385d49eab288085f8d38ead3ae5d87145c562ec",
b"3bb810492422cc5c7466d86dcd8095b0d87e97634656a3fa5fe2270a2244c16b",
b"17d2f0f7197a6612e311d141781f2b9539c4aef7affd729246c401890e000dde",
b"a4f4256159ea6fb23b27eb8c5eb9cfb9083475985f355a85c78de8f2fef2b3ac",
b"a36c4cf85204c67047c00d5dcc16677978839af0f0fde7ff973c98b66e244552",
b"4a596559f450ce5e3a777d952d8d2ed8611e9f3facc8400483371f6eadc4bdb2",
b"64855e54c94d14ab53afc6109d3c0033c665fab85b57c0e7d4e8da55b3b26952",
b"a2ee2228d4798988ce3ac273c0cd8b9bbc4e3e58413eb22dfbe6395758659a2b",
b"35c28ee2e25f5ad70384f1ca9723f520c955fb5fe9f2e56b9dc809479a9ca8cc",
b"da3f6a7f55f821760330dd14495e68e7d153b05e472d38459d4728d63ad9df26",
b"026134f6117e45a37c5c2dc2f330bdd274c6dc087526b91ecec4d6dac9bb7346",
];
let mut input = Vec::new();
for i in 0..128 {
assert_eq!(
Sha256::hash(&input),
hex::decode(hashes[i] as &[u8]).unwrap().as_slice()
);
input.push(b'A');
}
}
// TODO: more tests
}

View File

@@ -0,0 +1,41 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[cfg(test)]
use subtle::CtOption;
pub type Block16 = [u8; 16];
#[inline(always)]
pub fn xor_block_16(block: &mut Block16, mask: &Block16) {
for i in 0..16 {
block[i] ^= mask[i];
}
}
#[cfg(test)]
pub trait ToOption<T> {
fn to_option(self) -> Option<T>;
}
#[cfg(test)]
impl<T> ToOption<T> for CtOption<T> {
fn to_option(self) -> Option<T> {
if bool::from(self.is_some()) {
Some(self.unwrap())
} else {
None
}
}
}

View File

@@ -0,0 +1,103 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// Test vectors for AES-ECB from NIST's validation suite.
///
/// See also https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/AESAVS.pdf
#[macro_use]
extern crate arrayref;
extern crate hex;
extern crate regex;
use crypto::{aes256, Decrypt16BytesBlock, Encrypt16BytesBlock};
use regex::Regex;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
#[test]
fn aesavs() {
// These data files are taken from https://csrc.nist.gov/groups/STM/cavp/documents/aes/KAT_AES.zip.
test_aesavs_file("tests/data/ECBVarKey256.rsp");
test_aesavs_file("tests/data/ECBVarTxt256.rsp");
}
fn test_aesavs_file<P: AsRef<Path>>(path: P) {
// Implements some custom parsing for NIST's test vectors.
let re_count = Regex::new("^COUNT = ([0-9]+)$").unwrap();
let re_key = Regex::new("^KEY = ([0-9a-f]{64})$").unwrap();
let re_plaintext = Regex::new("^PLAINTEXT = ([0-9a-f]{32})$").unwrap();
let re_ciphertext = Regex::new("^CIPHERTEXT = ([0-9a-f]{32})$").unwrap();
let file = BufReader::new(File::open(path).unwrap());
let mut lines = file.lines();
loop {
let line = lines.next().unwrap().unwrap();
if line == "[ENCRYPT]" {
break;
}
}
for i in 0.. {
// empty line
let line = lines.next().unwrap().unwrap();
assert_eq!(line, "");
let line = lines.next().unwrap().unwrap();
if line == "[DECRYPT]" {
// Skip the decryption tests, they are the same as the encryption tests.
break;
}
// "COUNT = "
let captures = re_count.captures(&line).unwrap();
let count = captures.get(1).unwrap().as_str().parse::<usize>().unwrap();
assert_eq!(count, i);
// "KEY = "
let line = lines.next().unwrap().unwrap();
let captures = re_key.captures(&line).unwrap();
let key = hex::decode(captures.get(1).unwrap().as_str()).unwrap();
assert_eq!(key.len(), 32);
// "PLAINTEXT = "
let line = lines.next().unwrap().unwrap();
let captures = re_plaintext.captures(&line).unwrap();
let plaintext = hex::decode(captures.get(1).unwrap().as_str()).unwrap();
assert_eq!(plaintext.len(), 16);
// "CIPHERTEXT = "
let line = lines.next().unwrap().unwrap();
let captures = re_ciphertext.captures(&line).unwrap();
let ciphertext = hex::decode(captures.get(1).unwrap().as_str()).unwrap();
assert_eq!(ciphertext.len(), 16);
{
let encryption_key = aes256::EncryptionKey::new(array_ref![key, 0, 32]);
let mut block: [u8; 16] = [Default::default(); 16];
block.copy_from_slice(&plaintext);
encryption_key.encrypt_block(&mut block);
assert_eq!(&block, ciphertext.as_slice());
}
{
let encryption_key = aes256::EncryptionKey::new(array_ref![key, 0, 32]);
let decryption_key = aes256::DecryptionKey::new(&encryption_key);
let mut block: [u8; 16] = [Default::default(); 16];
block.copy_from_slice(&ciphertext);
decryption_key.decrypt_block(&mut block);
assert_eq!(&block, plaintext.as_slice());
}
}
}

View File

@@ -0,0 +1,232 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// A minimalist parser for ASN.1 encoded ECDSA signatures in DER form.
use arrayref::mut_array_refs;
use crypto::ecdsa;
use std::convert::TryFrom;
use std::io::Read;
#[derive(Debug)]
pub enum Asn1Error {
IoError(std::io::Error),
InvalidTagClass,
InvalidLongFormEncoding,
ArithmeticOverflow,
ExpectedSequenceTag(Tag),
ExpectedIntegerTag(Tag),
InvalidSequenceLen(usize),
InvalidIntegerLen(usize),
UnexpectedTrailingBytes,
InvalidSignature,
}
impl From<std::io::Error> for Asn1Error {
fn from(e: std::io::Error) -> Asn1Error {
Asn1Error::IoError(e)
}
}
#[derive(PartialEq, Debug)]
pub enum TagClass {
Universal = 0,
Application = 1,
ContextSpecific = 2,
Private = 3,
}
impl TryFrom<u8> for TagClass {
type Error = Asn1Error;
fn try_from(x: u8) -> Result<TagClass, Asn1Error> {
match x {
0 => Ok(TagClass::Universal),
1 => Ok(TagClass::Application),
2 => Ok(TagClass::ContextSpecific),
3 => Ok(TagClass::Private),
_ => Err(Asn1Error::InvalidTagClass),
}
}
}
#[allow(dead_code)]
enum UniversalTag {
Boolean = 1,
Integer = 2,
BitString = 3,
OctetString = 4,
Null = 5,
ObjectIdentifier = 6,
Utf8String = 12,
Sequence = 16,
Set = 17,
PrintableString = 19,
UtcTime = 23,
GeneralizedTime = 24,
}
#[derive(Debug)]
pub struct Tag {
class: TagClass,
constructed: bool,
number: u64,
}
impl Tag {
fn is_sequence(&self) -> bool {
self.class == TagClass::Universal
&& self.constructed
&& self.number == UniversalTag::Sequence as u64
}
fn is_number(&self) -> bool {
self.class == TagClass::Universal
&& !self.constructed
&& self.number == UniversalTag::Integer as u64
}
// Parse an ASN.1 tag encoded in DER form.
fn parse<R: Read>(input: &mut R) -> Result<Tag, Asn1Error> {
let mut buf = [0u8; 1];
input.read_exact(&mut buf)?;
let mut tag = buf[0];
let class = TagClass::try_from(tag >> 6)?;
let constructed = tag & 0x20 != 0;
tag &= 0x1F;
if tag < 31 {
// Short tag number
let number = tag as u64;
Ok(Tag {
class,
constructed,
number,
})
} else {
// Long tag number
let mut number: u64 = 0;
loop {
input.read_exact(&mut buf)?;
let x = buf[0];
if number == 0 && x == 0 {
return Err(Asn1Error::InvalidLongFormEncoding);
}
if number >> ((8 * std::mem::size_of::<u64>()) - 7) != 0 {
return Err(Asn1Error::ArithmeticOverflow);
}
number = (number << 7) | (x & 0x7F) as u64;
if (x & 0x80) == 0 {
if number < 31 {
return Err(Asn1Error::InvalidLongFormEncoding);
}
return Ok(Tag {
class,
constructed,
number,
});
}
}
}
}
}
// Parse an ASN.1 length encoded in DER form.
fn parse_len<R: Read>(input: &mut R) -> Result<usize, Asn1Error> {
let mut buf = [0u8; 1];
input.read_exact(&mut buf)?;
let first_byte = buf[0];
if (first_byte & 0x80) == 0 {
// Short form
Ok(first_byte as usize)
} else {
// Long form
let nbytes = (first_byte & 0x7F) as usize;
let mut length: usize = 0;
for _ in 0..nbytes {
input.read_exact(&mut buf)?;
let x = buf[0];
if length == 0 && x == 0 {
return Err(Asn1Error::InvalidLongFormEncoding);
}
if length >> (8 * (std::mem::size_of::<usize>() - 1)) != 0 {
return Err(Asn1Error::ArithmeticOverflow);
}
length = (length << 8) | x as usize;
}
if length < 0x80 {
return Err(Asn1Error::InvalidLongFormEncoding);
}
Ok(length)
}
}
fn parse_coordinate<R: Read>(mut input: R, bytes: &mut [u8; 32]) -> Result<usize, Asn1Error> {
let tag = Tag::parse(&mut input)?;
if !tag.is_number() {
return Err(Asn1Error::ExpectedIntegerTag(tag));
}
let len = parse_len(&mut input)?;
if len > 33 {
return Err(Asn1Error::InvalidIntegerLen(len));
}
let mut buf = vec![0; len];
input.read_exact(&mut buf)?;
if len == 33 {
if buf.remove(0) != 0 {
return Err(Asn1Error::InvalidIntegerLen(len));
}
}
bytes[(32 - buf.len())..].copy_from_slice(&buf);
Ok(len)
}
pub fn parse_signature<R: Read>(mut input: R) -> Result<ecdsa::Signature, Asn1Error> {
let tag = Tag::parse(&mut input)?;
if !tag.is_sequence() {
return Err(Asn1Error::ExpectedSequenceTag(tag));
}
let len = parse_len(&mut input)?;
let mut bytes = [0; 64];
let (xbytes, ybytes) = mut_array_refs![&mut bytes, 32, 32];
let xlen = parse_coordinate(&mut input, xbytes)?;
let ylen = parse_coordinate(&mut input, ybytes)?;
// Each coordinate has, besides (x|y)len bytes of integer, one byte for the tag and one
// byte for the length (the length is at most 33 and therefore encoded on one byte).
if len != xlen + ylen + 4 {
return Err(Asn1Error::InvalidSequenceLen(len));
}
// Check for unexpected bytes at the end.
let is_eof = {
let mut buf = [0u8; 1];
match input.read_exact(&mut buf) {
Ok(_) => false,
Err(e) => e.kind() == std::io::ErrorKind::UnexpectedEof,
}
};
if !is_eof {
return Err(Asn1Error::UnexpectedTrailingBytes);
}
ecdsa::Signature::from_bytes(&bytes).ok_or(Asn1Error::InvalidSignature)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crypto::ecdsa;
use serde::Deserialize;
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
mod asn1;
#[test]
fn wycheproof() {
let wycheproof = load_tests("tests/data/ecdsa_secp256r1_sha256_test.json").unwrap();
wycheproof.type_check();
assert!(wycheproof.run_tests());
}
fn load_tests<P: AsRef<Path>>(path: P) -> Result<Wycheproof, Box<dyn Error>> {
let file = File::open(path)?;
let wycheproof = serde_json::from_reader(BufReader::new(file))?;
Ok(wycheproof)
}
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Wycheproof {
algorithm: String,
#[allow(dead_code)]
generatorVersion: String,
#[allow(dead_code)]
numberOfTests: u32,
#[allow(dead_code)]
header: Vec<String>,
notes: HashMap<String, String>,
schema: String,
testGroups: Vec<TestGroup>,
}
impl Wycheproof {
fn type_check(&self) {
assert_eq!(self.algorithm, "ECDSA");
assert_eq!(self.schema, "ecdsa_verify_schema.json");
for group in &self.testGroups {
group.type_check();
}
}
fn run_tests(&self) -> bool {
let mut result = true;
for group in &self.testGroups {
result &= group.run_tests(&self.notes);
}
result
}
}
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct TestGroup {
key: Key,
#[allow(dead_code)]
keyDer: String,
#[allow(dead_code)]
keyPem: String,
sha: String,
r#type: String,
tests: Vec<TestCase>,
}
impl TestGroup {
fn type_check(&self) {
self.key.type_check();
assert_eq!(self.sha, "SHA-256");
assert_eq!(self.r#type, "EcdsaVerify");
for test in &self.tests {
test.type_check();
}
}
fn run_tests(&self, notes: &HashMap<String, String>) -> bool {
let key = self.key.get_key();
let mut result = true;
for test in &self.tests {
result &= test.run_test(&key, notes);
}
result
}
}
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Key {
curve: String,
keySize: u32,
r#type: String,
uncompressed: String,
#[allow(dead_code)]
wx: String,
#[allow(dead_code)]
wy: String,
}
impl Key {
fn type_check(&self) {
assert_eq!(self.curve, "secp256r1");
assert_eq!(self.keySize, 256);
assert_eq!(self.r#type, "EcPublicKey");
assert_eq!(self.uncompressed.len(), 130);
}
fn get_key(&self) -> Option<ecdsa::PubKey> {
let bytes = hex::decode(&self.uncompressed).unwrap();
ecdsa::PubKey::from_bytes_uncompressed(&bytes)
}
}
#[derive(Deserialize, Debug)]
#[allow(non_camel_case_types)]
enum TestResult {
valid,
invalid,
acceptable,
}
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct TestCase {
tcId: u32,
comment: String,
msg: String,
sig: String,
result: TestResult,
flags: Vec<String>,
}
impl TestCase {
fn type_check(&self) {
// Nothing to do.
}
fn print(&self, notes: &HashMap<String, String>, error_msg: &str) {
println!("Test case #{} => {}", self.tcId, error_msg);
println!(" {}", self.comment);
println!(" result = {:?}", self.result);
for f in &self.flags {
println!(
" flag {} = {}",
f,
notes.get(f).map_or("unknown flag", |x| &x)
);
}
}
fn run_test(&self, key: &Option<ecdsa::PubKey>, notes: &HashMap<String, String>) -> bool {
match key {
None => {
let pass = match self.result {
TestResult::invalid | TestResult::acceptable => true,
TestResult::valid => false,
};
if !pass {
self.print(notes, "Invalid public key");
}
pass
}
Some(k) => {
let msg = hex::decode(&self.msg).unwrap();
let sig = hex::decode(&self.sig).unwrap();
match asn1::parse_signature(sig.as_slice()) {
Err(e) => {
let pass = match self.result {
TestResult::invalid | TestResult::acceptable => true,
TestResult::valid => false,
};
if !pass {
self.print(notes, "Invalid ASN.1 encoding for the signature");
println!(" {:?}", e);
}
pass
}
Ok(signature) => {
let verified = k.verify_vartime::<crypto::sha256::Sha256>(&msg, &signature);
let pass = match self.result {
TestResult::acceptable => true,
TestResult::valid => verified,
TestResult::invalid => !verified,
};
if !pass {
self.print(
notes,
&format!(
"Expected {:?} result, but the signature verification was {}",
self.result, verified
),
);
}
pass
}
}
}
}
}
}