Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new crypto backend based on mbedtls #115

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ jobs:
strategy:
fail-fast: false
matrix:
crypto_backend: [crypto-hacspec, crypto-psa]
crypto_backend: [crypto-hacspec, crypto-psa, crypto-mbedtls]
ead: [ead-none, ead-zeroconf]

steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Run unit tests # note that we only add `--package edhoc-hacspec` when testing the hacspec version of the lib
- name: Run unit tests
run: cargo test --package edhoc-rs --package edhoc-crypto --package edhoc-ead --no-default-features --features="${{ matrix.crypto_backend }}, ${{ matrix.ead }}" --no-fail-fast


Expand All @@ -46,7 +46,7 @@ jobs:
strategy:
fail-fast: false
matrix:
crypto_backend: [crypto-hacspec, crypto-psa, crypto-psa-baremetal, crypto-cryptocell310]
crypto_backend: [crypto-hacspec, crypto-psa, crypto-psa-baremetal, crypto-cryptocell310, crypto-mbedtls]
ead: [ead-none, ead-zeroconf]

steps:
Expand Down Expand Up @@ -102,7 +102,7 @@ jobs:
strategy:
fail-fast: false
matrix:
crypto_backend: [crypto-psa-baremetal, crypto-cryptocell310]
crypto_backend: [crypto-psa-baremetal, crypto-cryptocell310, crypto-mbedtls]

steps:
- name: Checkout repo
Expand Down Expand Up @@ -130,7 +130,7 @@ jobs:
strategy:
fail-fast: false
matrix:
crypto_backend: [crypto-psa]
crypto_backend: [crypto-psa, crypto-mbedtls]
ead: [ead-none, ead-zeroconf]

steps:
Expand All @@ -155,7 +155,7 @@ jobs:
strategy:
fail-fast: false
matrix:
crypto_backend: [crypto-psa, crypto-cryptocell310]
crypto_backend: [crypto-psa, crypto-mbedtls, crypto-cryptocell310]
ead: [ead-none, ead-zeroconf]

steps:
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ members = [
"crypto/edhoc-crypto-hacspec",
"crypto/edhoc-crypto-psa",
"crypto/edhoc-crypto-cryptocell310-sys",
"crypto/edhoc-crypto-mbedtls",
"examples/coap",
"examples/edhoc-rs-no_std",
"examples/edhoc-rs-cc2538",
Expand Down
5 changes: 5 additions & 0 deletions crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,15 @@ edhoc-crypto-psa = { path = "./edhoc-crypto-psa", default-features = false, opti
# cryptocell for nrf52840
edhoc-crypto-cryptocell310 = { path = "./edhoc-crypto-cryptocell310-sys", optional = true }

# mbedtls
edhoc-crypto-mbedtls = { path = "./edhoc-crypto-mbedtls", default-features = false, optional = true }

[features]
default = [ ]
hacspec = [ "edhoc-crypto-hacspec" ]
cc2538 = [ "edhoc-crypto-cc2538" ]
psa = [ "edhoc-crypto-psa" ]
psa-baremetal = [ "psa", "edhoc-crypto-psa/baremetal" ]
cryptocell310 = [ "edhoc-crypto-cryptocell310" ]
mbedtls = [ "edhoc-crypto-mbedtls/std" ]
mbedtls-baremetal = [ "edhoc-crypto-mbedtls/baremetal" ]
15 changes: 15 additions & 0 deletions crypto/edhoc-crypto-mbedtls/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "edhoc-crypto-mbedtls"
version = "0.1.0"
edition = "2021"
authors = ["Mališa Vučinič <[email protected]>"]
license = "BSD"
description = "EDHOC crypto library mbedTLS backend"

[dependencies]
edhoc-consts = { path = "../../consts" }
mbedtls = { version = "0.9.3", default-features=false }

[features]
std = ["mbedtls/std"]
baremetal = ["mbedtls/no_std_deps"]
201 changes: 201 additions & 0 deletions crypto/edhoc-crypto-mbedtls/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#![no_std]

use edhoc_consts::*;
use mbedtls::bignum::Mpi;
use mbedtls::cipher::raw::Cipher;
use mbedtls::cipher::raw::CipherId;
use mbedtls::cipher::raw::CipherMode;
use mbedtls::cipher::raw::Operation::*;
use mbedtls::ecp::EcGroup;
use mbedtls::ecp::EcPoint;
use mbedtls::hash::Hmac;
use mbedtls::hash::Md;
use mbedtls::hash::Type::Sha256;
use mbedtls::pk::EcGroupId;
use mbedtls::pk::Pk;
use mbedtls::rng::CtrDrbg;
#[cfg(feature = "std")]
use mbedtls::rng::OsEntropy;
use mbedtls::rng::Random;

pub fn sha256_digest(message: &BytesMaxBuffer, message_len: usize) -> BytesHashLen {
let mut out: [u8; SHA256_DIGEST_LEN] = [0; SHA256_DIGEST_LEN];
Md::hash(Sha256, &message[..message_len], &mut out).unwrap();
out
}

pub fn hkdf_expand(
prk: &BytesHashLen,
info: &BytesMaxInfoBuffer,
info_len: usize,
length: usize,
) -> BytesMaxBuffer {
let mut output: [u8; MAX_BUFFER_LEN] = [0; MAX_BUFFER_LEN];
// Implementation of HKDF-Expand as per RFC5869

let mut n = 0;

// N = ceil(L/HashLen)
if length % SHA256_DIGEST_LEN == 0 {
n = length / SHA256_DIGEST_LEN;
} else {
n = length / SHA256_DIGEST_LEN + 1;
}

let mut message: [u8; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1] =
[0; MAX_INFO_LEN + SHA256_DIGEST_LEN + 1];
message[..info_len].copy_from_slice(&info[..info_len]);
message[info_len] = 0x01;
let mut t_i = hmac_sha256(&message[..info_len + 1], prk);
output[..SHA256_DIGEST_LEN].copy_from_slice(&t_i);

for i in 2..n {
message[..SHA256_DIGEST_LEN].copy_from_slice(&t_i);
message[SHA256_DIGEST_LEN..SHA256_DIGEST_LEN + info_len].copy_from_slice(&info[..info_len]);
message[SHA256_DIGEST_LEN + info_len] = i as u8;
t_i = hmac_sha256(&message[..SHA256_DIGEST_LEN + info_len + 1], prk);
output[i * SHA256_DIGEST_LEN..(i + 1) * SHA256_DIGEST_LEN].copy_from_slice(&t_i);
}

output[length..].fill(0x00);

output
}
pub fn hkdf_extract(salt: &BytesHashLen, ikm: &BytesP256ElemLen) -> BytesHashLen {
// Implementation of HKDF-Extract as per RFC 5869

// TODO generalize if salt is not provided
let output = hmac_sha256(ikm, salt);

output
}

pub fn aes_ccm_encrypt_tag_8(
key: &BytesCcmKeyLen,
iv: &BytesCcmIvLen,
ad: &BytesEncStructureLen,
plaintext: &BufferPlaintext3,
) -> BufferCiphertext3 {
let mut output_buffer: BufferCiphertext3 = BufferCiphertext3::new();

let mut cipher = Cipher::setup(CipherId::Aes, CipherMode::CCM, 128).unwrap();
cipher.set_key(Encrypt, key).unwrap();
cipher.set_iv(iv).unwrap();
let res = cipher
.encrypt_auth(
ad,
&plaintext.content[..plaintext.len],
&mut output_buffer.content,
8,
)
.unwrap();
output_buffer.len = res;

output_buffer
}

pub fn aes_ccm_decrypt_tag_8(
key: &BytesCcmKeyLen,
iv: &BytesCcmIvLen,
ad: &BytesEncStructureLen,
ciphertext: &BufferCiphertext3,
) -> Result<BufferPlaintext3, EDHOCError> {
let mut error = EDHOCError::UnknownError;
let mut output_buffer: BufferPlaintext3 = BufferPlaintext3::new();

let mut cipher = Cipher::setup(CipherId::Aes, CipherMode::CCM, 128).unwrap();
cipher.set_key(Decrypt, key).unwrap();
cipher.set_iv(iv).unwrap();

let res = cipher.decrypt_auth(
ad,
&ciphertext.content[..ciphertext.len],
&mut output_buffer.content,
8,
);

if res.is_ok() {
error = EDHOCError::Success;
output_buffer.len = res.unwrap();
} else {
error = EDHOCError::MacVerificationFailed;
}

match error {
EDHOCError::Success => Ok(output_buffer),
_ => Err(error),
}
}

pub fn p256_ecdh(
private_key: &BytesP256ElemLen,
public_key: &BytesP256ElemLen,
) -> BytesP256ElemLen {
let mut output_buffer = [0u8; P256_ELEM_LEN];
let mut peer_public_key = [0u8; P256_ELEM_LEN + 1];
peer_public_key[0] = 0x02; // sign does not matter for ECDH operation
peer_public_key[1..P256_ELEM_LEN + 1].copy_from_slice(&public_key[..]);
let mut group = EcGroup::new(EcGroupId::SecP256R1).unwrap();
let pubk = EcPoint::from_binary(&group, &peer_public_key).unwrap();
let privk = Mpi::from_binary(private_key).unwrap();
let secret = pubk.mul(&mut group, &privk).unwrap();
let secret_x = secret.x().unwrap().to_binary().unwrap();
output_buffer.copy_from_slice(&secret_x[..]);

output_buffer
}

#[cfg(feature = "std")]
pub fn get_random_byte() -> u8 {
let mut output = [0x00u8; 1];

// use OS entropy for the moment
let entropy = OsEntropy::new();

// init mbedTLS RNG
let mut ctr = CtrDrbg::new(entropy.into(), Some(&[0xcau8, 0xfeu8])).unwrap();

// get one random byte
ctr.random(&mut output).unwrap();
output[0]
}

#[cfg(feature = "baremetal")]
pub fn get_random_byte() -> u8 {
0x99
}

// This works on native using OS Entropy
#[cfg(feature = "std")]
pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) {
let mut private_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN];
let mut public_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN];

let secp256r1 = EcGroup::new(EcGroupId::SecP256R1).unwrap();
let entropy = OsEntropy::new();
let mut ctr = CtrDrbg::new(entropy.into(), Some(&[0xcau8, 0xfeu8])).unwrap();

// generate a key pair
let pk = Pk::generate_ec(&mut ctr, secp256r1).unwrap();

// export the keys to appropriate format
private_key.copy_from_slice(&pk.ec_private().unwrap().to_binary().unwrap()[..]);
public_key.copy_from_slice(&pk.ec_public().unwrap().x().unwrap().to_binary().unwrap()[..]);

(private_key, public_key)
}

#[cfg(feature = "baremetal")]
pub fn p256_generate_key_pair() -> (BytesP256ElemLen, BytesP256ElemLen) {
let mut private_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN];
let mut public_key: [u8; P256_ELEM_LEN] = [0; P256_ELEM_LEN];

(private_key, public_key)
}

pub fn hmac_sha256(message: &[u8], key: &[u8; SHA256_DIGEST_LEN]) -> BytesHashLen {
let mut out: [u8; SHA256_DIGEST_LEN] = [0; SHA256_DIGEST_LEN];
let res = Hmac::hmac(Sha256, key, message, &mut out).unwrap();

out
}
3 changes: 3 additions & 0 deletions crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ pub use edhoc_crypto_cc2538::*;
#[cfg(any(feature = "psa", feature = "psa-rust",))]
pub use edhoc_crypto_psa::*;

#[cfg(any(feature = "mbedtls", feature = "mbedtls-baremetal"))]
pub use edhoc_crypto_mbedtls::*;

#[cfg(any(feature = "cryptocell310", feature = "cryptocell310-rust"))]
pub use edhoc_crypto_cryptocell310::*;
8 changes: 7 additions & 1 deletion examples/coap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ version = "0.1.0"
edition = "2021"

[dependencies]
edhoc-rs = { path = "../../lib", features = [ "crypto-psa" ] }
edhoc-rs = { path = "../../lib", default-features = false }
hexlit = "0.5.3"
coap = { version = "0.13" }
coap-lite = { version = "0.11.3" }

[features]
default = [ "crypto-hacspec" ]
crypto-psa = [ "edhoc-rs/ead-none", "edhoc-rs/crypto-psa" ]
crypto-mbedtls = [ "edhoc-rs/ead-none", "edhoc-rs/crypto-mbedtls" ]
crypto-hacspec = [ "edhoc-rs/ead-none", "edhoc-rs/crypto-hacspec" ]
1 change: 1 addition & 0 deletions examples/edhoc-rs-no_std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ default = [ "rtt", "crypto-cryptocell310", "ead-none" ]
rtt = [ ]
crypto-psa = [ "edhoc-rs/crypto-psa-baremetal" ]
crypto-cryptocell310 = [ "edhoc-rs/crypto-cryptocell310" ]
crypto-mbedtls = [ "edhoc-rs/crypto-mbedtls-baremetal" ]
ead-none = [ "edhoc-rs/ead-none" ]
ead-zeroconf = [ "edhoc-rs/ead-zeroconf" ]
15 changes: 13 additions & 2 deletions examples/edhoc-rs-no_std/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,21 @@ fn main() -> ! {
loop {}
}

use core::ffi::{c_char, c_void};
use core::ffi::{c_char, c_ulong, c_void};

#[no_mangle]
pub extern "C" fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char {
pub extern "C" fn strstr(_cs: *const c_char, _ct: *const c_char) -> *mut c_char {
panic!("strstr handler!");
core::ptr::null_mut()
}

#[no_mangle]
pub unsafe extern "C" fn calloc(__count: c_ulong, __size: c_ulong) -> *mut c_void {
panic!("calloc handler!");
core::ptr::null_mut()
}

#[no_mangle]
pub unsafe extern "C" fn free(_ptr: *const c_void) {
panic!("free handler!");
}
2 changes: 2 additions & 0 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ default = [ "edhoc-ead/ead-none" ]
crypto-hacspec = ["hacspec-lib/std", "edhoc-crypto/hacspec" ]
crypto-psa = [ "edhoc-crypto/psa" ]
crypto-psa-baremetal = [ "edhoc-crypto/psa-baremetal", "panic-semihosting" ]
crypto-mbedtls = [ "edhoc-crypto/mbedtls" ]
crypto-mbedtls-baremetal = [ "edhoc-crypto/mbedtls-baremetal", "panic-semihosting" ]
crypto-cryptocell310 = [ "edhoc-crypto/cryptocell310", "panic-semihosting" ]
ead-none = [ "edhoc-ead/ead-none" ]
ead-zeroconf = [ "edhoc-ead/ead-zeroconf" ]
Expand Down
Loading