Skip to content

Commit

Permalink
Merge pull request #31 from drcapybara/fix/cure-timing-vulnerability
Browse files Browse the repository at this point in the history
fix: cure timing vulnerability
  • Loading branch information
drcapybara committed Nov 1, 2023
2 parents acda3e6 + 7def35e commit e2cc2ba
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 52 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ apt-get install m4
```rust
use capycrypt::{Hashable, Message};
// Hash the empty string
let mut data = Message::new(&mut vec![]);
let mut data = Message::new(vec![]);
// Obtained from OpenSSL
let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a";
// Compute a SHA3 digest with 128 bits of security
Expand All @@ -54,7 +54,7 @@ use capycrypt::{
// Get a random password
let pw = get_random_bytes(64);
// Get 5mb random data
let mut msg = Message::new(&mut get_random_bytes(5242880));
let mut msg = Message::new(get_random_bytes(5242880));
// Encrypt the data with 256 bits of security
msg.pw_encrypt(&mut pw.clone(), 512);
// Decrypt the data
Expand All @@ -73,7 +73,7 @@ use capycrypt::{
curves::EdCurves::E448};

// Get 5mb random data
let mut msg = Message::new(&mut get_random_bytes(5242880));
let mut msg = Message::new(get_random_bytes(5242880));
// Create a new private/public keypair
let key_pair = KeyPair::new(&get_random_bytes(32), "test key".to_string(), E448, 512);

Expand All @@ -94,7 +94,7 @@ use capycrypt::{
sha3::aux_functions::byte_utils::get_random_bytes,
curves::EdCurves::E448};
// Get random 5mb
let mut msg = Message::new(&mut get_random_bytes(5242880));
let mut msg = Message::new(get_random_bytes(5242880));
// Get a random password
let pw = get_random_bytes(64);
// Generate a signing keypair
Expand Down
6 changes: 3 additions & 3 deletions benches/benchmark_e222_224.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn bench_sign_verify(c: &mut Criterion) {
SELECTED_CURVE,
BIT_SECURITY,
),
Message::new(&mut get_random_bytes(5242880)),
Message::new(get_random_bytes(5242880)),
)
});
});
Expand All @@ -49,7 +49,7 @@ fn bench_sym_enc(c: &mut Criterion) {
b.iter(|| {
sym_enc(
&mut get_random_bytes(64),
Message::new(&mut get_random_bytes(5242880)),
Message::new(get_random_bytes(5242880)),
)
});
});
Expand All @@ -66,7 +66,7 @@ fn bench_key_gen_enc_dec(c: &mut Criterion) {
BIT_SECURITY,
)
.priv_key,
Message::new(&mut get_random_bytes(5242880)),
Message::new(get_random_bytes(5242880)),
)
});
});
Expand Down
7 changes: 3 additions & 4 deletions benches/benchmark_e521_512.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use criterion::{criterion_group, criterion_main, Criterion};
const SELECTED_CURVE: EdCurves = E521;
const BIT_SECURITY: u64 = 512;


/// Symmetric encrypt and decrypt roundtrip
fn sym_enc(pw: &mut Vec<u8>, mut msg: Message) {
msg.pw_encrypt(&mut pw.clone(), BIT_SECURITY);
Expand Down Expand Up @@ -39,7 +38,7 @@ fn bench_sign_verify(c: &mut Criterion) {
SELECTED_CURVE,
BIT_SECURITY,
),
Message::new(&mut get_random_bytes(5242880)),
Message::new(get_random_bytes(5242880)),
)
});
});
Expand All @@ -50,7 +49,7 @@ fn bench_sym_enc(c: &mut Criterion) {
b.iter(|| {
sym_enc(
&mut get_random_bytes(64),
Message::new(&mut get_random_bytes(5242880)),
Message::new(get_random_bytes(5242880)),
)
});
});
Expand All @@ -67,7 +66,7 @@ fn bench_key_gen_enc_dec(c: &mut Criterion) {
BIT_SECURITY,
)
.priv_key,
Message::new(&mut get_random_bytes(5242880)),
Message::new(get_random_bytes(5242880)),
)
});
});
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ pub struct KeyPair {
}

impl Message {
pub fn new(data: &mut Vec<u8>) -> Message {
pub fn new(data: Vec<u8>) -> Message {
Message {
msg: Box::new(data.to_owned()),
msg: Box::new(data),
sym_nonce: None,
asym_nonce: None,
digest: None,
Expand Down
49 changes: 26 additions & 23 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ pub fn cshake(x: &mut Vec<u8>, l: u64, n: &str, s: &str, d: u64) -> Vec<u8> {
if n.is_empty() && s.is_empty() {
shake(x, l);
}
let mut encoded_n = encode_string(&mut n.as_bytes().to_vec());
let encoded_s = encode_string(&mut s.as_bytes().to_vec());
let mut encoded_n = encode_string(&n.as_bytes().to_vec());
let encoded_s = encode_string(&s.as_bytes().to_vec());

encoded_n.extend_from_slice(&encoded_s);

Expand Down Expand Up @@ -126,7 +126,7 @@ impl Hashable for Message {
/// ```
/// use capycrypt::{Hashable, Message};
/// // Hash the empty string
/// let mut data = Message::new(&mut vec![]);
/// let mut data = Message::new(vec![]);
/// // Obtained from OpenSSL
/// let expected = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a";
/// // Compute a SHA3 digest with 256 bits of security
Expand Down Expand Up @@ -154,7 +154,7 @@ impl Hashable for Message {
/// ```
/// use capycrypt::{Hashable, Message};
/// let mut pw = "test".as_bytes().to_vec();
/// let mut data = Message::new(&mut vec![]);
/// let mut data = Message::new(vec![]);
/// let expected = "0f9b5dcd47dc08e08a173bbe9a57b1a65784e318cf93cccb7f1f79f186ee1caeff11b12f8ca3a39db82a63f4ca0b65836f5261ee64644ce5a88456d3d30efbed";
/// data.compute_tagged_hash(&mut pw, &"", 512);
/// assert!(hex::encode(data.digest.unwrap().to_vec()) == expected);
Expand Down Expand Up @@ -194,7 +194,7 @@ impl PwEncryptable for Message {
/// // Get a random password
/// let pw = get_random_bytes(64);
/// // Get 5mb random data
/// let mut msg = Message::new(&mut get_random_bytes(5242880));
/// let mut msg = Message::new(get_random_bytes(5242880));
/// // Encrypt the data with 512 bits of security
/// msg.pw_encrypt(&mut pw.clone(), 512);
/// // Decrypt the data
Expand All @@ -206,7 +206,7 @@ impl PwEncryptable for Message {
let z = get_random_bytes(512);
let mut ke_ka = z.clone();
ke_ka.append(&mut pw.to_owned());
let ke_ka = kmac_xof(&mut ke_ka, &vec![], 1024, "S", d);
let ke_ka = kmac_xof(&ke_ka, &vec![], 1024, "S", d);
let ke = &mut ke_ka[..64].to_vec();
let ka = &mut ke_ka[64..].to_vec();
self.digest = Some(kmac_xof(ka, &self.msg, 512, "SKA", d));
Expand Down Expand Up @@ -241,7 +241,7 @@ impl PwEncryptable for Message {
/// // Get a random password
/// let pw = get_random_bytes(64);
/// // Get 5mb random data
/// let mut msg = Message::new(&mut get_random_bytes(5242880));
/// let mut msg = Message::new(get_random_bytes(5242880));
/// // Encrypt the data with 512 bits of security
/// msg.pw_encrypt(&mut pw.clone(), 512);
/// // Decrypt the data
Expand All @@ -252,7 +252,7 @@ impl PwEncryptable for Message {
fn pw_decrypt(&mut self, pw: &[u8], d: u64) {
let mut z_pw = self.sym_nonce.clone().unwrap();
z_pw.append(&mut pw.to_owned());
let ke_ka = kmac_xof(&mut z_pw, &vec![], 1024, "S", d);
let ke_ka = kmac_xof(&z_pw, &vec![], 1024, "S", d);
let ke = &mut ke_ka[..64].to_vec();
let ka = &mut ke_ka[64..].to_vec();
let m = kmac_xof(ke, &vec![], (self.msg.len() * 8) as u64, "SKE", d);
Expand Down Expand Up @@ -289,9 +289,12 @@ impl KeyPair {
/// let key_pair = KeyPair::new(&pw, "test key".to_string(), E448, 512);
/// ```
pub fn new(pw: &Vec<u8>, owner: String, curve: EdCurves, d: u64) -> KeyPair {
let s: Integer = (bytes_to_big(kmac_xof(&mut pw.to_owned(), &vec![], 512, "K", d)) * 4)
% order(SELECTED_CURVE);
// Timing sidechannel on variable keysize is mitigated here due to modding by curve order.
let s: Integer =
(bytes_to_big(kmac_xof(pw, &vec![], 512, "K", d)) * 4) % order(SELECTED_CURVE);

let pub_key = EdCurvePoint::generator(curve, false) * (s);

KeyPair {
owner,
pub_key,
Expand Down Expand Up @@ -329,7 +332,7 @@ impl KeyEncryptable for Message {
/// sha3::aux_functions::byte_utils::get_random_bytes,
/// curves::EdCurves::E448};
/// // Get 5mb random data
/// let mut msg = Message::new(&mut get_random_bytes(5242880));
/// let mut msg = Message::new(get_random_bytes(5242880));
/// // Generate the keypair
/// let key_pair = KeyPair::new(&get_random_bytes(32), "test key".to_string(), E448, 512);
/// // Encrypt with the public key
Expand All @@ -340,7 +343,7 @@ impl KeyEncryptable for Message {
let w = pub_key.clone() * k.clone();
let z = EdCurvePoint::generator(pub_key.curve, false) * k;

let ke_ka = kmac_xof(&mut big_to_bytes(w.x), &vec![], 1024, "PK", d);
let ke_ka = kmac_xof(&big_to_bytes(w.x), &vec![], 1024, "PK", d);
let ke = &mut ke_ka[..64].to_vec();
let ka = &mut ke_ka[64..].to_vec();

Expand Down Expand Up @@ -387,7 +390,7 @@ impl KeyEncryptable for Message {
/// curves::EdCurves::E448};
///
/// // Get 5mb random data
/// let mut msg = Message::new(&mut get_random_bytes(5242880));
/// let mut msg = Message::new(get_random_bytes(5242880));
/// // Create a new private/public keypair
/// let key_pair = KeyPair::new(&get_random_bytes(32), "test key".to_string(), E448, 512);
///
Expand All @@ -401,16 +404,16 @@ impl KeyEncryptable for Message {
fn key_decrypt(&mut self, pw: &[u8], d: u64) {
let z = self.asym_nonce.clone().unwrap();
let s: Integer =
(bytes_to_big(kmac_xof(&mut pw.to_owned(), &vec![], 512, "K", d)) * 4) % z.clone().n;
(bytes_to_big(kmac_xof(&pw.to_owned(), &vec![], 512, "K", d)) * 4) % z.clone().n;
let w = z * s;

let ke_ka = kmac_xof(&mut big_to_bytes(w.x), &vec![], 1024, "PK", d);
let ke_ka = kmac_xof(&big_to_bytes(w.x), &vec![], 1024, "PK", d);
let ke = &mut ke_ka[..64].to_vec();
let ka = &mut ke_ka[64..].to_vec();

let m = Box::new(kmac_xof(ke, &vec![], (self.msg.len() * 8) as u64, "PKE", d));
xor_bytes(&mut self.msg, &m);
let t_p = kmac_xof(&mut ka.clone(), &self.msg, 512, "PKA", d);
let t_p = kmac_xof(&ka.clone(), &self.msg, 512, "PKA", d);
self.op_result = Some(t_p == self.digest.clone().unwrap());
}
}
Expand Down Expand Up @@ -441,7 +444,7 @@ impl Signable for Message {
/// sha3::aux_functions::byte_utils::get_random_bytes,
/// curves::EdCurves::E448};
/// // Get random 5mb
/// let mut msg = Message::new(&mut get_random_bytes(5242880));
/// let mut msg = Message::new(get_random_bytes(5242880));
/// // Get a random password
/// let pw = get_random_bytes(64);
/// // Generate a signing keypair
Expand All @@ -451,13 +454,13 @@ impl Signable for Message {
/// ```
fn sign(&mut self, key: &KeyPair, d: u64) {
let s: Integer = bytes_to_big(kmac_xof(&key.priv_key, &vec![], 512, "K", d)) * 4;
let mut s_bytes = big_to_bytes(s.clone());
let s_bytes = big_to_bytes(s.clone());

let k: Integer = bytes_to_big(kmac_xof(&mut s_bytes, &self.msg, 512, "N", d)) * 4;
let k: Integer = bytes_to_big(kmac_xof(&s_bytes, &self.msg, 512, "N", d)) * 4;

let u = EdCurvePoint::generator(SELECTED_CURVE, false) * k.clone();
let mut ux_bytes = big_to_bytes(u.x);
let h = kmac_xof(&mut ux_bytes, &self.msg, 512, "T", d);
let ux_bytes = big_to_bytes(u.x);
let h = kmac_xof(&ux_bytes, &self.msg, 512, "T", d);
let h_big = bytes_to_big(h.clone());
//(a % b + b) % b
let z = ((k - (h_big * s)) % u.r.clone() + u.r.clone()) % u.r;
Expand All @@ -484,7 +487,7 @@ impl Signable for Message {
/// sha3::aux_functions::byte_utils::get_random_bytes,
/// curves::EdCurves::E448};
/// // Get random 5mb
/// let mut msg = Message::new(&mut get_random_bytes(5242880));
/// let mut msg = Message::new(get_random_bytes(5242880));
/// // Get a random password
/// let pw = get_random_bytes(64);
/// // Generate a signing keypair
Expand All @@ -499,7 +502,7 @@ impl Signable for Message {
let mut u = EdCurvePoint::generator(pub_key.curve, false) * self.sig.clone().unwrap().z;
let hv = pub_key.clone() * bytes_to_big(self.sig.clone().unwrap().h);
u = u + &hv;
let h_p = kmac_xof(&mut big_to_bytes(u.x), &self.msg, 512, "T", d);
let h_p = kmac_xof(&big_to_bytes(u.x), &self.msg, 512, "T", d);
self.op_result = Some(h_p == self.sig.clone().unwrap().h)
}
}
14 changes: 7 additions & 7 deletions tests/ops_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub mod ops_tests {
#[test]
pub fn test_sym_enc_512() {
let pw = get_random_bytes(64);
let mut msg = Message::new(&mut get_random_bytes(5242880));
let mut msg = Message::new(get_random_bytes(5242880));

msg.pw_encrypt(&mut pw.clone(), 512);
msg.pw_decrypt(&mut pw.clone(), 512);
Expand All @@ -19,7 +19,7 @@ pub mod ops_tests {
#[test]
pub fn test_sym_enc_256() {
let pw = get_random_bytes(64);
let mut msg = Message::new(&mut get_random_bytes(5242880));
let mut msg = Message::new(get_random_bytes(5242880));

msg.pw_encrypt(&mut pw.clone(), 256);
msg.pw_decrypt(&mut pw.clone(), 256);
Expand All @@ -28,7 +28,7 @@ pub mod ops_tests {
}
#[test]
fn test_key_gen_enc_dec_256() {
let mut msg = Message::new(&mut get_random_bytes(5242880));
let mut msg = Message::new(get_random_bytes(5242880));
let key_pair = KeyPair::new(&get_random_bytes(32), "test key".to_string(), E448, 256);

msg.key_encrypt(&key_pair.pub_key, 256);
Expand All @@ -39,7 +39,7 @@ pub mod ops_tests {

#[test]
fn test_key_gen_enc_dec_512() {
let mut msg = Message::new(&mut get_random_bytes(5242880));
let mut msg = Message::new(get_random_bytes(5242880));
let key_pair = KeyPair::new(&get_random_bytes(32), "test key".to_string(), E448, 512);

msg.key_encrypt(&key_pair.pub_key, 512);
Expand All @@ -49,7 +49,7 @@ pub mod ops_tests {
}
#[test]
pub fn test_signature_512() {
let mut msg = Message::new(&mut get_random_bytes(5242880));
let mut msg = Message::new(get_random_bytes(5242880));
let pw = get_random_bytes(64);
let key_pair = KeyPair::new(&pw, "test key".to_string(), E448, 512);

Expand All @@ -61,8 +61,8 @@ pub mod ops_tests {
#[test]
fn test_sig_timing_side_channel() {
for i in 0..10 {
let mut msg = Message::new(&mut get_random_bytes(16));
let pw = get_random_bytes(2 ^ i);
let mut msg = Message::new(get_random_bytes(16));
let pw = get_random_bytes(1 << i);
let mut key_pair = KeyPair::new(&pw, "test key".to_string(), E448, 512);

let now = Instant::now();
Expand Down
Loading

0 comments on commit e2cc2ba

Please sign in to comment.