Skip to content

Commit

Permalink
Extend Cipher types (#330)
Browse files Browse the repository at this point in the history
* feat: update CipherId CipherMode CipherType

* build: use a pre-release ver

* style: fmt

* feat: add derives for CipherId

* fix: make chachapoly valid ciphermode

Add chachapoly as valid ciphermode for Authenticated Cipher.

* feat: add fn for EcPoint

Add a no compress version import fn:
`from_binary_no_compress`. It seems current way of detect compression is
not always true.

* feat: make Hmac clone-able

* Revert "feat: make Hmac clone-able"

This reverts commit 78af5e2.

* fix: naming and type
  • Loading branch information
Taowyoo authored Oct 31, 2023
1 parent 5c2a215 commit 0a79c87
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mbedtls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "mbedtls"
# We jumped from v0.9 to v0.12 because v0.10 and v0.11 were based on mbedtls 3.X, which
# we decided not to support.
version = "0.12.0"
version = "0.12.0-alpha.1"
authors = ["Jethro Beekman <[email protected]>"]
build = "build.rs"
edition = "2018"
Expand Down
34 changes: 33 additions & 1 deletion mbedtls/src/cipher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ pub enum Authenticated {}
impl Type for Authenticated {
fn is_valid_mode(mode: raw::CipherMode) -> bool {
match mode {
raw::CipherMode::GCM | raw::CipherMode::CCM | raw::CipherMode::KW | raw::CipherMode::KWP => true,
raw::CipherMode::GCM
| raw::CipherMode::CCM
| raw::CipherMode::KW
| raw::CipherMode::KWP
| raw::CipherMode::CHACHAPOLY => true,
_ => false,
}
}
Expand Down Expand Up @@ -457,3 +461,31 @@ fn aes_kwp() {
let out_len = cipher.decrypt_auth(&[], &c, &mut p_out, 0).unwrap().0;
assert_eq!(p, &p_out[..out_len]);
}

#[test]
fn aes_gcm() {
let k = [
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x40, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
];
let iv = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16];

let ad = [0x03, 0x04, 0x05];
let p = [0x20, 0x21, 0x22, 0x23];
let c = [0x01, 0x08, 0x55, 0x0f];
let t = [0x3f, 0xd9, 0x8e, 0x74];
let mut p_out = [0u8; 4];
let mut c_out = [0u8; 8];

let cipher =
Cipher::<Encryption, Authenticated, Fresh>::new(raw::CipherId::Aes, raw::CipherMode::GCM, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &iv).unwrap();

cipher.encrypt_auth(&ad, &p, &mut c_out, 4).unwrap();
assert_eq!(c, c_out[0..4]);
assert_eq!(t, c_out[4..8]);
let cipher = Cipher::<_, Authenticated, _>::new(raw::CipherId::Aes, raw::CipherMode::GCM, (k.len() * 8) as _).unwrap();
let cipher = cipher.set_key_iv(&k, &iv).unwrap();
cipher.decrypt_auth(&ad, &c_out, &mut p_out, 4).unwrap();
assert_eq!(p, p_out);
}
78 changes: 55 additions & 23 deletions mbedtls/src/cipher/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod serde;

define!(
#[c_ty(cipher_id_t)]
#[derive(Copy, Clone, Eq, PartialEq)]
enum CipherId {
None = CIPHER_ID_NONE,
Null = CIPHER_ID_NULL,
Expand All @@ -24,6 +25,7 @@ define!(
Blowfish = CIPHER_ID_BLOWFISH,
Arc4 = CIPHER_ID_ARC4,
Aria = CIPHER_ID_ARIA,
Chacha20 = CIPHER_ID_CHACHA20,
}
);

Expand All @@ -39,6 +41,7 @@ impl From<cipher_id_t> for CipherId {
CIPHER_ID_BLOWFISH => CipherId::Blowfish,
CIPHER_ID_ARC4 => CipherId::Arc4,
CIPHER_ID_ARIA => CipherId::Aria,
CIPHER_ID_CHACHA20 => CipherId::Chacha20,
// This should be replaced with TryFrom once it is stable.
_ => panic!("Invalid cipher_id_t"),
}
Expand All @@ -58,6 +61,8 @@ define!(
GCM = MODE_GCM,
STREAM = MODE_STREAM,
CCM = MODE_CCM,
XTS = MODE_XTS,
CHACHAPOLY = MODE_CHACHAPOLY,
KW = MODE_KW,
KWP = MODE_KWP,
}
Expand All @@ -75,6 +80,8 @@ impl From<cipher_mode_t> for CipherMode {
MODE_GCM => CipherMode::GCM,
MODE_STREAM => CipherMode::STREAM,
MODE_CCM => CipherMode::CCM,
MODE_XTS => CipherMode::XTS,
MODE_CHACHAPOLY => CipherMode::CHACHAPOLY,
MODE_KW => CipherMode::KW,
MODE_KWP => CipherMode::KWP,
// This should be replaced with TryFrom once it is stable.
Expand Down Expand Up @@ -135,6 +142,31 @@ define!(
Camellia128Ccm = CIPHER_CAMELLIA_128_CCM,
Camellia192Ccm = CIPHER_CAMELLIA_192_CCM,
Camellia256Ccm = CIPHER_CAMELLIA_256_CCM,
Aria128Ecb = CIPHER_ARIA_128_ECB,
Aria192Ecb = CIPHER_ARIA_192_ECB,
Aria256Ecb = CIPHER_ARIA_256_ECB,
Aria128Cbc = CIPHER_ARIA_128_CBC,
Aria192Cbc = CIPHER_ARIA_192_CBC,
Aria256Cbc = CIPHER_ARIA_256_CBC,
Aria128Cfb128 = CIPHER_ARIA_128_CFB128,
Aria192Cfb128 = CIPHER_ARIA_192_CFB128,
Aria256Cfb128 = CIPHER_ARIA_256_CFB128,
Aria128Ctr = CIPHER_ARIA_128_CTR,
Aria192Ctr = CIPHER_ARIA_192_CTR,
Aria256Ctr = CIPHER_ARIA_256_CTR,
Aria128Gcm = CIPHER_ARIA_128_GCM,
Aria192Gcm = CIPHER_ARIA_192_GCM,
Aria256Gcm = CIPHER_ARIA_256_GCM,
Aria128Ccm = CIPHER_ARIA_128_CCM,
Aria192Ccm = CIPHER_ARIA_192_CCM,
Aria256Ccm = CIPHER_ARIA_256_CCM,
Aes128Ofb = CIPHER_AES_128_OFB,
Aes192Ofb = CIPHER_AES_192_OFB,
Aes256Ofb = CIPHER_AES_256_OFB,
Aes128Xts = CIPHER_AES_128_XTS,
Aes256Xts = CIPHER_AES_256_XTS,
Chacha20 = CIPHER_CHACHA20,
Chacha20Poly1305 = CIPHER_CHACHA20_POLY1305,
Aes128Kw = CIPHER_AES_128_KW,
Aes192Kw = CIPHER_AES_192_KW,
Aes256Kw = CIPHER_AES_256_KW,
Expand Down Expand Up @@ -213,41 +245,41 @@ impl Cipher {
unsafe { cipher_update_ad(&mut self.inner, ad.as_ptr(), ad.len()).into_result_discard() }
}

pub fn update(&mut self, indata: &[u8], outdata: &mut [u8]) -> Result<usize> {
// Check that minimum required space is available in outdata buffer
let reqd_size = if unsafe { *self.inner.cipher_info }.mode == MODE_ECB {
pub fn update(&mut self, in_data: &[u8], out_data: &mut [u8]) -> Result<usize> {
// Check that minimum required space is available in out_data buffer
let required_size = if unsafe { *self.inner.cipher_info }.mode == MODE_ECB {
self.block_size()
} else {
indata.len() + self.block_size()
in_data.len() + self.block_size()
};

if outdata.len() < reqd_size {
if out_data.len() < required_size {
return Err(Error::CipherFullBlockExpected);
}

let mut olen = 0;
unsafe {
cipher_update(
&mut self.inner,
indata.as_ptr(),
indata.len(),
outdata.as_mut_ptr(),
in_data.as_ptr(),
in_data.len(),
out_data.as_mut_ptr(),
&mut olen,
)
.into_result()?;
}
Ok(olen)
}

pub fn finish(&mut self, outdata: &mut [u8]) -> Result<usize> {
// Check that minimum required space is available in outdata buffer
if outdata.len() < self.block_size() {
pub fn finish(&mut self, out_data: &mut [u8]) -> Result<usize> {
// Check that minimum required space is available in out_data buffer
if out_data.len() < self.block_size() {
return Err(Error::CipherFullBlockExpected);
}

let mut olen = 0;
unsafe {
cipher_finish(&mut self.inner, outdata.as_mut_ptr(), &mut olen).into_result()?;
cipher_finish(&mut self.inner, out_data.as_mut_ptr(), &mut olen).into_result()?;
}
Ok(olen)
}
Expand All @@ -274,7 +306,7 @@ impl Cipher {
unsafe { (*self.inner.cipher_info).mode.into() }
}

// Utility function to get mdoe for the selected / setup cipher_info
// Utility function to get mode for the selected / setup cipher_info
pub fn is_authenticated(&self) -> bool {
unsafe {
if (*self.inner.cipher_info).mode == MODE_GCM || (*self.inner.cipher_info).mode == MODE_CCM {
Expand Down Expand Up @@ -413,31 +445,31 @@ impl Cipher {
Ok(plain_len)
}

fn do_crypto(&mut self, indata: &[u8], outdata: &mut [u8]) -> Result<usize> {
fn do_crypto(&mut self, in_data: &[u8], out_data: &mut [u8]) -> Result<usize> {
self.reset()?;

// The total number of bytes writte to outdata so far. It's safe to
// The total number of bytes written to out_data so far. It's safe to
// use this as a start index for slicing: &slice[slice.len()..] will
// return an empty slice, it doesn't panic.
let mut total_len = 0;

if unsafe { *self.inner.cipher_info }.mode == MODE_ECB {
// ECB mode requires single-block updates
for chunk in indata.chunks(self.block_size()) {
let len = self.update(chunk, &mut outdata[total_len..])?;
for chunk in in_data.chunks(self.block_size()) {
let len = self.update(chunk, &mut out_data[total_len..])?;
total_len += len;
}
} else {
total_len = self.update(indata, outdata)?;
total_len += self.finish(&mut outdata[total_len..])?;
total_len = self.update(in_data, out_data)?;
total_len += self.finish(&mut out_data[total_len..])?;
}

Ok(total_len)
}

pub fn cmac(&mut self, key: &[u8], data: &[u8], outdata: &mut [u8]) -> Result<()> {
// Check that outdata buffer has enough space
if outdata.len() < self.block_size() {
pub fn cmac(&mut self, key: &[u8], data: &[u8], out_data: &mut [u8]) -> Result<()> {
// Check that out_data buffer has enough space
if out_data.len() < self.block_size() {
return Err(Error::CipherFullBlockExpected);
}
self.reset()?;
Expand All @@ -448,7 +480,7 @@ impl Cipher {
(key.len() * 8) as _,
data.as_ptr(),
data.len(),
outdata.as_mut_ptr(),
out_data.as_mut_ptr(),
)
.into_result()?;
}
Expand Down
6 changes: 6 additions & 0 deletions mbedtls/src/ecp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,12 @@ impl EcPoint {
}
}

pub fn from_binary_no_compress(group: &EcGroup, bin: &[u8]) -> Result<EcPoint> {
let mut ret = Self::init();
unsafe { ecp_point_read_binary(&group.inner, &mut ret.inner, bin.as_ptr(), bin.len()) }.into_result()?;
Ok(ret)
}

pub fn from_components(x: Mpi, y: Mpi) -> Result<EcPoint> {
let mut ret = Self::init();

Expand Down

0 comments on commit 0a79c87

Please sign in to comment.