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

Wrap cryptolib functions #132

Merged
merged 8 commits into from
Feb 27, 2024
Merged
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
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 ledger_device_sdk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ledger_device_sdk"
version = "1.5.2"
version = "1.6.0"
authors = ["yhql", "yogh333"]
edition = "2021"
license.workspace = true
Expand Down
90 changes: 63 additions & 27 deletions ledger_device_sdk/src/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,28 +377,37 @@ impl<const P: usize> ECPublicKey<P, 'E'> {
///
/// Checks consistency of curve choice and key length
/// in order to prevent the underlying syscall from throwing
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
pub fn bip32_derive(curve: CurvesId, path: &[u32], key: &mut [u8]) -> Result<(), CxError> {
pub fn bip32_derive(
curve: CurvesId,
path: &[u32],
key: &mut [u8],
cc: Option<&mut [u8]>,
) -> Result<(), CxError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get why for ed25519 the requested length is 96 few lines below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, looks to be ok with 64 🤔. Maybe a typo @yhql ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix in this commit, waiting feedback from @yhql if revert is needed

match curve {
CurvesId::Secp256k1 | CurvesId::Secp256r1 => {
CurvesId::Secp256k1 | CurvesId::Secp256r1 | CurvesId::Ed25519 => {
if key.len() < 64 {
return Err(CxError::InvalidParameter);
}
}
CurvesId::Ed25519 => {
if key.len() < 96 {
return Err(CxError::InvalidParameter);
}
}
_ => return Err(CxError::InvalidParameter),
}
unsafe {
os_perso_derive_node_bip32(
curve as u8,
path.as_ptr(),
path.len() as u32,
key.as_mut_ptr(),
core::ptr::null_mut(),
)
match cc {
Some(buf) => os_perso_derive_node_bip32(
curve as u8,
path.as_ptr(),
path.len() as u32,
key.as_mut_ptr(),
buf.as_mut_ptr(),
),
None => os_perso_derive_node_bip32(
curve as u8,
path.as_ptr(),
path.len() as u32,
key.as_mut_ptr(),
core::ptr::null_mut(),
),
}
};
Ok(())
}
Expand Down Expand Up @@ -436,6 +445,12 @@ impl<const N: usize> Drop for Secret<N> {
}
}

#[repr(C)]
#[derive(Default)]
pub struct ChainCode {
value: [u8; 32],
}

/// Fill the key buffer `ECPrivateKey<_,_>.key` with bytes
/// derived from the seed through BIP32 or other standard
/// derivation scheme.
Expand All @@ -444,54 +459,75 @@ impl<const N: usize> Drop for Secret<N> {
/// curves.
pub trait SeedDerive {
type Target;
fn derive_from_path(path: &[u32]) -> Self::Target;
fn derive_from(path: &[u32]) -> (Self::Target, Option<ChainCode>);
fn derive_from_path(path: &[u32]) -> Self::Target {
Self::derive_from(path).0
}
}

impl SeedDerive for Secp256k1 {
type Target = ECPrivateKey<32, 'W'>;
fn derive_from_path(path: &[u32]) -> Self::Target {
fn derive_from(path: &[u32]) -> (Self::Target, Option<ChainCode>) {
let mut tmp = Secret::<64>::new();
let mut cc: ChainCode = Default::default();
// Ignoring 'Result' here because known to be valid
let _ = bip32_derive(CurvesId::Secp256k1, path, tmp.as_mut());
let _ = bip32_derive(
CurvesId::Secp256k1,
path,
tmp.as_mut(),
Some(cc.value.as_mut()),
);
let mut sk = Self::Target::new(CurvesId::Secp256k1);
let keylen = sk.key.len();
sk.key.copy_from_slice(&tmp.0[..keylen]);
sk
(sk, Some(cc))
}
}

impl SeedDerive for Secp256r1 {
type Target = ECPrivateKey<32, 'W'>;
fn derive_from_path(path: &[u32]) -> Self::Target {
fn derive_from(path: &[u32]) -> (Self::Target, Option<ChainCode>) {
let mut tmp = Secret::<64>::new();
let mut cc: ChainCode = Default::default();
// Ignoring 'Result' here because known to be valid
let _ = bip32_derive(CurvesId::Secp256r1, path, tmp.as_mut());
let _ = bip32_derive(
CurvesId::Secp256r1,
path,
tmp.as_mut(),
Some(cc.value.as_mut()),
);
let mut sk = Self::Target::new(CurvesId::Secp256r1);
let keylen = sk.key.len();
sk.key.copy_from_slice(&tmp.0[..keylen]);
sk
(sk, Some(cc))
}
}

impl SeedDerive for Ed25519 {
type Target = ECPrivateKey<32, 'E'>;
fn derive_from_path(path: &[u32]) -> Self::Target {
let mut tmp = Secret::<96>::new();
fn derive_from(path: &[u32]) -> (Self::Target, Option<ChainCode>) {
let mut tmp = Secret::<64>::new();
let mut cc: ChainCode = Default::default();
// Ignoring 'Result' here because known to be valid
let _ = bip32_derive(CurvesId::Ed25519, path, tmp.as_mut());
let _ = bip32_derive(
CurvesId::Ed25519,
path,
tmp.as_mut(),
Some(cc.value.as_mut()),
);
let mut sk = Self::Target::new(CurvesId::Ed25519);
let keylen = sk.key.len();
sk.key.copy_from_slice(&tmp.0[..keylen]);
sk
(sk, Some(cc))
}
}

impl SeedDerive for Stark256 {
type Target = ECPrivateKey<32, 'W'>;
fn derive_from_path(path: &[u32]) -> Self::Target {
fn derive_from(path: &[u32]) -> (Self::Target, Option<ChainCode>) {
let mut sk = Self::Target::new(CurvesId::Stark256);
stark::eip2645_derive(path, &mut sk.key);
sk
(sk, None)
}
}

Expand Down
2 changes: 1 addition & 1 deletion ledger_device_sdk/src/ecc/stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const C_CX_STARK256_N: [u8; 32] = [
pub fn eip2645_derive(path: &[u32], key: &mut [u8]) {
let mut x_key = Secret::<64>::new();
// Ignoring 'Result' here because known to be valid
let _ = super::bip32_derive(CurvesId::Secp256k1, path, x_key.as_mut());
let _ = super::bip32_derive(CurvesId::Secp256k1, path, x_key.as_mut(), None);

let mut index = 0;
let mut cmp = 0;
Expand Down
184 changes: 184 additions & 0 deletions ledger_device_sdk/src/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
use ledger_secure_sdk_sys::{
cx_hash_final, cx_hash_get_size, cx_hash_no_throw, cx_hash_t, cx_hash_update,
CX_INVALID_PARAMETER, CX_LAST, CX_OK,
};

mod blake2;
mod ripemd;
mod sha2;
mod sha3;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum HashError {
InvalidParameter,
InvalidOutputLength,
InternalError,
}

impl From<u32> for HashError {
fn from(x: u32) -> HashError {
match x {
CX_INVALID_PARAMETER => HashError::InvalidParameter,
_ => HashError::InternalError,
}
}
}

impl From<HashError> for u32 {
fn from(e: HashError) -> u32 {
e as u32
}
}

pub trait HashInit: Sized {
fn as_ctx_mut(&mut self) -> &mut cx_hash_t;
fn as_ctx(&self) -> &cx_hash_t;
fn new() -> Self;
fn get_size(&mut self) -> usize {
unsafe { cx_hash_get_size(self.as_ctx()) }
}
fn hash(mut self, input: &[u8], output: &mut [u8]) -> Result<(), HashError> {
let output_size = self.get_size();
if output_size > output.len() {
return Err(HashError::InvalidOutputLength);
}

let err = unsafe {
cx_hash_no_throw(
self.as_ctx_mut(),
CX_LAST,
input.as_ptr(),
input.len(),
output.as_mut_ptr(),
output.len(),
)
};
if err != CX_OK {
Err(err.into())
} else {
Ok(())
}
}
fn update(&mut self, input: &[u8]) -> Result<(), HashError> {
let err = unsafe { cx_hash_update(self.as_ctx_mut(), input.as_ptr(), input.len()) };
if err != CX_OK {
Err(err.into())
} else {
Ok(())
}
}
fn finalize(mut self, output: &mut [u8]) -> Result<(), HashError> {
let output_size = self.get_size();
if output_size > output.len() {
return Err(HashError::InvalidOutputLength);
}

let err = unsafe { cx_hash_final(self.as_ctx_mut(), output.as_mut_ptr()) };
if err != CX_OK {
Err(err.into())
} else {
Ok(())
}
}
}

macro_rules! impl_hash {
($typename:ident, $ctxname:ident, $initfname:ident, $size:expr) => {
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct $typename {
ctx: $ctxname,
}
impl HashInit for $typename {
fn as_ctx_mut(&mut self) -> &mut cx_hash_t {
&mut self.ctx.header
}

fn as_ctx(&self) -> &cx_hash_t {
&self.ctx.header
}

fn new() -> Self {
let mut ctx: $typename = Default::default();
let _err = unsafe { $initfname(&mut ctx.ctx, $size) };
ctx
}
}
};

($typename:ident, $ctxname:ident, $initfname:ident) => {
#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct $typename {
ctx: $ctxname,
}
impl HashInit for $typename {
fn as_ctx_mut(&mut self) -> &mut cx_hash_t {
&mut self.ctx.header
}

fn as_ctx(&self) -> &cx_hash_t {
&self.ctx.header
}

fn new() -> Self {
let mut ctx: $typename = Default::default();
let _err = unsafe { $initfname(&mut ctx.ctx) };
ctx
}
}
};
}
pub(crate) use impl_hash;

#[cfg(test)]
mod tests {
use crate::assert_eq_err as assert_eq;
use crate::hash::sha2::Sha2_256;
use crate::hash::sha3::*;
use crate::hash::HashInit;
use crate::testing::TestType;
use testmacro::test_item as test;

const TEST_HASH: &[u8; 29] = b"Not your keys, not your coins";

#[test]
fn test_hash() {
let mut keccak = Keccak256::new();

let mut output: [u8; 32] = [0u8; 32];

let ouput_size = keccak.get_size();
assert_eq!(ouput_size, 32);

let _ = keccak.hash(TEST_HASH, &mut output);

let expected = [
0x1f, 0x20, 0x7c, 0xd9, 0xfd, 0x9f, 0x0b, 0x09, 0xb0, 0x04, 0x93, 0x6c, 0xa5, 0xe0,
0xd3, 0x1b, 0xa1, 0x6c, 0xd6, 0x14, 0x53, 0xaa, 0x28, 0x7e, 0x65, 0xaa, 0x88, 0x25,
0x3c, 0xdc, 0x1c, 0x94,
];
assert_eq!(&output, &expected);
}

#[test]
fn test_sha2_update() {
let mut hasher = Sha2_256::new();

let mut output: [u8; 32] = [0u8; 32];

let ouput_size = hasher.get_size();
assert_eq!(ouput_size, 32);

let _ = hasher.update(TEST_HASH);

let _ = hasher.finalize(&mut output);

let expected = [
0x52, 0x49, 0x2e, 0x81, 0x92, 0x16, 0xf3, 0x6b, 0x74, 0x7d, 0xd5, 0xda, 0x70, 0x3a,
0x26, 0x60, 0x14, 0x34, 0x60, 0x42, 0x42, 0xfa, 0xb2, 0x7e, 0x85, 0x51, 0xe7, 0x82,
0xa5, 0x11, 0x13, 0x40,
];
assert_eq!(&output, &expected);
}
}
Loading
Loading