Skip to content

Commit

Permalink
chore: improve code signature; add more document
Browse files Browse the repository at this point in the history
  • Loading branch information
zensh committed Jan 9, 2025
1 parent 52a3d5b commit fb42580
Show file tree
Hide file tree
Showing 18 changed files with 469 additions and 101 deletions.
46 changes: 23 additions & 23 deletions 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ strip = true
opt-level = 's'

[workspace.package]
version = "0.6.3"
version = "0.6.4"
edition = "2021"
repository = "https://github.com/ldclabs/ic-cose"
keywords = ["config", "cbor", "canister", "icp", "encryption"]
Expand Down
4 changes: 2 additions & 2 deletions src/ic_cose_canister/src/api_cose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ic_cose_types::{
ECDHInput, ECDHOutput, PublicKeyInput, PublicKeyOutput, SchnorrAlgorithm, SettingPath,
SignIdentityInput, SignInput,
},
validate_key, MILLISECONDS,
validate_str, MILLISECONDS,
};
use serde_bytes::{ByteArray, ByteBuf};

Expand Down Expand Up @@ -81,7 +81,7 @@ async fn schnorr_sign_identity(
input: SignIdentityInput,
) -> Result<ByteBuf, String> {
store::state::allowed_api("schnorr_sign_identity")?;
validate_key(&input.ns)?;
validate_str(&input.ns)?;

let caller = ic_cdk::caller();
let now_ms = ic_cdk::api::time() / MILLISECONDS;
Expand Down
6 changes: 3 additions & 3 deletions src/ic_cose_canister/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1205,7 +1205,7 @@ pub mod ns {
if setting.version != spk.4 {
Err("version mismatch".to_string())?;
}
if setting.status == 1 {
if setting.status >= 1 {
Err("readonly setting can not be updated".to_string())?;
}

Expand Down Expand Up @@ -1234,7 +1234,7 @@ pub mod ns {
if setting.version != spk.4 {
Err("version mismatch".to_string())?;
}
if setting.status == 1 {
if setting.status >= 1 {
Err("readonly setting can not be deleted".to_string())?;
}

Expand Down Expand Up @@ -1285,7 +1285,7 @@ pub mod ns {
if setting.version != spk.4 {
Err("version mismatch".to_string())?;
}
if setting.status == 1 {
if setting.status >= 1 {
Err("readonly setting can not be updated".to_string())?;
}

Expand Down
46 changes: 44 additions & 2 deletions src/ic_cose_types/src/cose/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ use aes_gcm::{aead::KeyInit, AeadInPlace, Aes256Gcm, Key, Nonce, Tag};

use super::format_error;

/// Encrypts data using AES-256-GCM algorithm.
///
/// # Arguments
/// * `key` - 32-byte encryption key
/// * `nonce` - 12-byte nonce (unique value for each encryption)
/// * `aad` - Additional authenticated data (optional)
/// * `plain_data` - Data to be encrypted
///
/// # Returns
/// Encrypted data with appended authentication tag (16 bytes) on success,
/// or error message if encryption fails.
pub fn aes256_gcm_encrypt(
key: &[u8; 32],
nonce: &[u8; 12],
Expand All @@ -17,6 +28,16 @@ pub fn aes256_gcm_encrypt(
Ok(buf)
}

/// Decrypts data using AES-256-GCM algorithm.
///
/// # Arguments
/// * `key` - 32-byte decryption key
/// * `nonce` - 12-byte nonce (must match encryption nonce)
/// * `aad` - Additional authenticated data (must match encryption aad)
/// * `cipher_data` - Encrypted data with appended authentication tag
///
/// # Returns
/// Decrypted data on success, or error message if decryption fails
pub fn aes256_gcm_decrypt(
key: &[u8; 32],
nonce: &[u8; 12],
Expand All @@ -33,7 +54,17 @@ pub fn aes256_gcm_decrypt(
Ok(buf)
}

fn aes256_gcm_encrypt_in(
/// Encrypts data in-place using AES-256-GCM.
///
/// # Arguments
/// * `cipher` - Initialized AES-256-GCM cipher
/// * `nonce` - 12-byte unique value
/// * `aad` - Additional authenticated data
/// * `data` - Mutable buffer containing plaintext (will be overwritten with ciphertext)
///
/// # Returns
/// Authentication tag (16 bytes) on success, or error message
pub fn aes256_gcm_encrypt_in(
cipher: &Aes256Gcm,
nonce: &[u8; 12],
aad: &[u8],
Expand All @@ -45,7 +76,18 @@ fn aes256_gcm_encrypt_in(
Ok(tag.into())
}

fn aes256_gcm_decrypt_in(
/// Decrypts data in-place using AES-256-GCM.
///
/// # Arguments
/// * `cipher` - Initialized AES-256-GCM cipher
/// * `nonce` - 12-byte nonce (must match encryption nonce)
/// * `aad` - Additional authenticated data (must match encryption aad)
/// * `data` - Mutable buffer containing ciphertext (will be overwritten with plaintext)
/// * `tag` - 16-byte authentication tag
///
/// # Returns
/// Unit on success, or error message if decryption fails
pub fn aes256_gcm_decrypt_in(
cipher: &Aes256Gcm,
nonce: &[u8; 12],
aad: &[u8],
Expand Down
21 changes: 21 additions & 0 deletions src/ic_cose_types/src/cose/cwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ pub use coset::cwt::*;
const CLOCK_SKEW: i64 = 5 * 60; // 5 minutes
pub static SCOPE_NAME: ClaimName = ClaimName::Assigned(iana::CwtClaimName::Scope);

/// Parses and validates a CWT (CBOR Web Token) from raw bytes.
///
/// # Arguments
/// * `data` - Raw CBOR-encoded CWT data
/// * `now_sec` - Current timestamp in seconds for validation
///
/// # Returns
/// * `Ok(ClaimsSet)` if token is valid
/// * `Err(String)` if token is invalid or expired
///
/// # Validation
/// * Checks expiration time (exp) with 5-minute clock skew
/// * Checks not-before time (nbf) with 5-minute clock skew
pub fn cwt_from(data: &[u8], now_sec: i64) -> Result<ClaimsSet, String> {
let claims = ClaimsSet::from_slice(data).map_err(|err| format!("invalid claims: {}", err))?;
if let Some(ref exp) = claims.expiration_time {
Expand All @@ -30,6 +43,14 @@ pub fn cwt_from(data: &[u8], now_sec: i64) -> Result<ClaimsSet, String> {
Ok(claims)
}

/// Extracts scope claim from CWT claims set.
///
/// # Arguments
/// * `claims` - CWT claims set to search
///
/// # Returns
/// * `Ok(String)` with scope value if found and valid
/// * `Err(String)` if scope is missing or invalid
pub fn get_scope(claims: &ClaimsSet) -> Result<String, String> {
let scope = claims
.rest
Expand Down
10 changes: 10 additions & 0 deletions src/ic_cose_types/src/cose/ecdh.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
pub use x25519_dalek::{PublicKey, SharedSecret, StaticSecret};

/// Performs X25519 Elliptic Curve Diffie-Hellman key exchange.
///
/// # Arguments
/// * `secret` - 32-byte private key
/// * `their_public` - 32-byte public key of the other party
///
/// # Returns
/// A tuple containing:
/// * Shared secret for symmetric encryption
/// * Public key corresponding to the input secret
pub fn ecdh_x25519(secret: [u8; 32], their_public: [u8; 32]) -> (SharedSecret, PublicKey) {
let secret = StaticSecret::from(secret);
let public = PublicKey::from(&secret);
Expand Down
20 changes: 20 additions & 0 deletions src/ic_cose_types/src/cose/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ use super::format_error;

pub use ed25519_dalek::{Signature, SigningKey, VerifyingKey};

/// Verifies an Ed25519 signature using the provided public key.
///
/// # Arguments
/// * `public_key` - 32-byte Ed25519 public key
/// * `message` - The message that was signed
/// * `signature` - 64-byte Ed25519 signature to verify
///
/// # Returns
/// * `Ok(())` if the signature is valid
/// * `Err(String)` with error message if verification fails
pub fn ed25519_verify(
public_key: &[u8; 32],
message: &[u8],
Expand All @@ -16,6 +26,16 @@ pub fn ed25519_verify(
}
}

/// Verifies an Ed25519 signature against multiple public keys.
///
/// # Arguments
/// * `public_keys` - List of Ed25519 public keys to try
/// * `message` - The message that was signed
/// * `signature` - 64-byte Ed25519 signature to verify
///
/// # Returns
/// * `Ok(())` if any key verifies the signature
/// * `Err(String)` if no key verifies the signature
pub fn ed25519_verify_any(
public_keys: &[VerifyingKey],
message: &[u8],
Expand Down
Loading

0 comments on commit fb42580

Please sign in to comment.