Skip to content

Commit

Permalink
chore: Merge branch 'release/v9.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Manuthor committed Sep 28, 2023
2 parents c37d357 + 5e23ee7 commit 4b33753
Show file tree
Hide file tree
Showing 51 changed files with 1,381 additions and 176 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: hack
args: build --feature-powerset --clean-per-run --no-dev-deps
args: check --feature-powerset --clean-per-run --no-dev-deps
cargo-publish:
needs:
- cargo-lint
Expand Down
5 changes: 0 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@ repos:
hooks:
- id: shellcheck

- repo: https://github.com/doublify/pre-commit-rust
rev: v1.0
hooks:
- id: cargo-check

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
Expand Down
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"Cloudproof",
"cosmian",
"Cosmian",
"decrypter",
"decryptor",
"Decryptor",
"decryptors",
Expand All @@ -14,19 +15,24 @@
"encryptor",
"Encryptor",
"encryptors",
"FIPS",
"hasher",
"hashers",
"keypair",
"libsodium",
"montgomery",
"nist",
"oaep",
"Oaep",
"OAEP",
"openssl",
"pkcs",
"sealbox",
"Seedable",
"xchacha",
"zeroize",
"zeroized",
"Zeroizes",
"Zeroizing"
]
}
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

All notable changes to this project will be documented in this file.

## [9.3.0] - 2023-09-26

### Features

- Add support for RSA key generation, key-wrapping and PKCS#8 import/export

### Fixed

- Fixed export of Curve25519Secret
- Aligned NIST Curves PKC8 import/export with the pkcs8 crate

## [9.2.1] - 2023-09-26

### Features
Expand Down
62 changes: 44 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[package]
name = "cosmian_crypto_core"
version = "9.2.1"
version = "9.3.0"
authors = [
"Bruno Grieder <bruno.grieder@cosmian.com>",
"Théophile BRÉZOT <theophile.brezot@cosmian.com>",
"Bruno GRIEDER <bruno.grieder@cosmian.com>",
"Théophile BRÉZOT <theophile.brezot@cosmian.com>",
"Emmanuel COSTE <emmanuel.coste@cosmian.com>",
]
categories = ["cryptography", "security"]
edition = "2021"
Expand All @@ -24,19 +25,21 @@ certificate = ["curve25519", "x509-cert", "uuid", "pkcs8"]
chacha = ["aead", "chacha20poly1305", "chacha20"]
curve25519 = ["curve25519-dalek", "ed25519-dalek", "signature", "sha2"]
default = [
"aes",
"chacha",
"certificate",
"ecies",
"curve25519",
"certificate",
"nist_curves",
"ser",
"blake",
"sha3",
"rfc5649",
"aes",
"chacha",
"certificate",
"ecies",
"curve25519",
"certificate",
"nist_curves",
"rsa",
"ser",
"blake",
"sha3",
"rfc5649",
]
ecies = ["aead", "crypto_box"]
rsa = ["digest", "dep:rsa", "sha1", "sha2", "dep:sha3", "pkcs8", "rfc5649"]
nist_curves = ["p384", "p256", "p224", "p192", "elliptic-curve", "pkcs8"]
rfc5649 = ["aes", "chacha"]
ser = ["leb128"]
Expand All @@ -50,22 +53,45 @@ chacha20 = { version = "0.9", optional = true }
chacha20poly1305 = { version = "0.10", optional = true }
crypto_box = { version = "0.9.1", features = ["seal"], optional = true }
curve25519-dalek = { version = "4.1.0", optional = true }
ed25519-dalek = { version = "2.0.0", optional = true, features = ["default", "hazmat"] }
elliptic-curve = { version = "0.13.5", default-features = false, features = ["hazmat", "sec1", "pkcs8", "ecdh"], optional = true }
digest = { version = "0.10", optional = true }
ed25519-dalek = { version = "2.0.0", optional = true, features = [
"default",
"hazmat",
] }
elliptic-curve = { version = "0.13.5", default-features = false, features = [
"hazmat",
"sec1",
"pkcs8",
"ecdh",
], optional = true }
getrandom = { version = "0.2", features = ["js"] } # needed to compile into WASM
leb128 = { version = "0.2", optional = true }
p192 = { version = "0.13", optional = true }
p224 = { version = "0.13", optional = true }
p256 = { version = "0.13", optional = true }
p384 = { version = "0.13", optional = true }
pkcs8 = { version = "0.10", features = ["encryption", "std", "alloc", "pem"], optional = true }
pkcs8 = { version = "0.10", features = [
"encryption",
"std",
"alloc",
"pem",
], optional = true }
rand_chacha = "0.3"
rand_core = { version = "0.6.4", features = ["getrandom"] }
rsa = { version = "0.9", optional = true }
sha1 = { version = "0.10", optional = true }
sha2 = { version = "0.10", optional = true }
sha3 = { version = "0.10", optional = true }
signature = { version = "2.1", optional = true }
tiny-keccak = { version = "2.0.2", features = ["shake"], optional = true }
uuid = { version = "1.4", features = ["v4"], optional = true }
x509-cert = { version = "0.2.4", features = ["pem", "std", "builder", "arbitrary", "hazmat"], optional = true }
x509-cert = { version = "0.2.4", features = [
"pem",
"std",
"builder",
"arbitrary",
"hazmat",
], optional = true }
zeroize = { version = "1.6", features = ["zeroize_derive"] }

[dev-dependencies]
Expand Down
154 changes: 154 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ This crate implements the cryptographic primitives (modern encryption and signat
- [Security](#security)
- [ECIES encryption of a vector of bytes](#ecies-encryption-of-a-vector-of-bytes)
- [ECIES encryption of a stream of bytes](#ecies-encryption-of-a-stream-of-bytes)
- [Key wrapping](#key-wrapping)
- [RFC 5649](#rfc-5649)
- [ECIES Key Wrapping](#ecies-key-wrapping)
- [RSA Key Wrapping](#rsa-key-wrapping)
- [Signature](#signature)
- [Static implementation](#static-implementation)
- [Cached implementation](#cached-implementation)
Expand Down Expand Up @@ -470,6 +474,156 @@ assert_eq!(
);
```

## Key Wrapping

Key wrapping and unwrapping is supported using:

- a symmetric key wrapping scheme based on the [RFC 5649](https://tools.ietf.org/html/rfc5649).
- an Elliptic Curve keypair using one of the ECIES schemes above
- using an RSA keypair

### RFC 5649

The RFC 5649 key wrapping scheme is implemented using the `key_wrap` and `Key_unwrap` methods exposed in the [key_wrapping_rfc_5649.rs](src/symmetric_crypto/key_wrapping_rfc_5649.rs). These methods are compatible with the PKCS#11 CKM_AES_KEY_WRAP_KWP mechanism (which is used in the hybrid RSA-AES key wrapping scheme, see below)

**Example**

```Rust
let kek =
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
let key_to_wrap =
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
let wrapped_key = [
199, 131, 191, 63, 110, 233, 156, 72, 218, 187, 196, 16, 226, 132, 197, 44, 191, 117,
133, 120, 152, 157, 225, 138, 50, 148, 201, 164, 209, 151, 200, 162, 98, 112, 72, 139,
28, 233, 128, 22,
];

assert_eq!(
key_wrap(key_to_wrap, kek).expect("Failed to wrap"),
wrapped_key
);
assert_eq!(
key_unwrap(&wrapped_key, kek).expect("Failed to unwrap"),
key_to_wrap
);

```

### ECIES Key Wrapping

See [Ecies](#ecies---elliptic-curve-integrated-encryption-scheme) above for details on the ECIES schemes.

### RSA Key Wrapping

Various PKCS#11 compatible key wrapping schemes are implemented for RSA keys of size, 2048, 3072 and 4096 bits.

The algorithms are listed below with the corresponding CKM mechanism. Preferably, the **Aes256Sha256** algorithm should be used.

- **Pkcs1v1_5**,
PKCS #1 v1.5 RS following PKCS#11 CKM_RSA_PKCS
The maximum possible plaintext length is m = k - 11,
where k is the size of the RSA modulus.

- **OaepSha256**,
PKCS #1 RSA with OAEP block format following PKCS#11 CKM*RSA_PKCS_OAEP
The hash function used is SHA256
The maximum possible plaintext length is m = k - 2 * h_len - 2,
where k is the size of the RSA modulus
and h_len is the size of the hash of the optional label.

- **OaepSha1**,
PKCS #1 RSA with OAEP block format following PKCS#11 CKM*RSA_PKCS_OAEP
The hash function used is SHA1. For that reason this algorithm is not recommended
and is only kept here for compatibility with legacy systems.
The maximum possible plaintext length is m = k - 2 * h_len - 2,
where k is the size of the RSA modulus
and h_len is the size of the hash of the optional label.
This algorithm is compatible with Google Cloud KMS

- RSA_OAEP_3072_SHA256 with RSA 3072 bits key
- RSA_OAEP_4096_SHA256 with RSA 4096 bits key

- **OaepSha3**,
PKCS #1 RSA with OAEP block format following PKCS#11 CKM_RSA_PKCS_OAEP
The hash function used is SHA3.
and is only kept here for compatibility with legacy systems.
The maximum possible plaintext length is m = k - 2 \* h_len - 2,
where k is the size of the RSA modulus
and h_len is the size of the hash of the optional label.

- **Aes256Sha256**,
Key wrap with AES following PKCS#11 CKM_RSA_AES_KEY_WRAP
using an AES key of 256 bits. The hash function used is SHA256.
The AES wrapping follows the RFC 5649 which is compatible with PKCS#11 CKM_AES_KEY_WRAP_KWP
and there is no limitation on the size of the plaintext (other than those of AES); the recommended
plaintext format for an EC Private key is PKCS#8.
This algorithm is compatible with Google Cloud KMS

- RSA_OAEP_3072_SHA256_AES_256 for RSA 3072 bits key
- RSA_OAEP_4096_SHA256_AES_256 for RSA 4096 bits key

- **Aes256Sha1**,
Key wrap with AES following PKCS#11 CKM_RSA_AES_KEY_WRAP
using an AES key of 256 bits. The hash function used is SHA1.
For that reason this algorithm is not recommended
and is only kept here for compatibility with legacy systems.
The AES wrapping follows the RFC 5649 which is compatible with PKCS#11 CKM_AES_KEY_WRAP_KWP
since there is no limitation on the size of the plaintext; the recommended
plaintext format for an EC Private key is PKCS#8.
This algorithm is compatible with Google Cloud KMS

- RSA_OAEP_3072_SHA1_AES_256 for RSA 3072 bits key
- RSA_OAEP_4096_SHA1_AES_256 for RSA 4096 bits key

- **Aes256Sha3**,
Key wrap with AES following PKCS#11 CKM_RSA_AES_KEY_WRAP
using an AES key of 256 bits. The hash function used is SHA3-256 (defined in FIPS 202).
The AES wrapping follows the RFC 5649 which is compatible with PKCS#11 CKM_AES_KEY_WRAP_KWP
since there is no limitation on the size of the plaintext; the recommended
plaintext format for an EC Private key is PKCS#8.

**Example using CKM_RSA_AES_KEY_WRAP with SHA-256 and AES 256**

```Rust
use cosmian_crypto_core::{
reexport::rand_core::{RngCore, SeedableRng},
CsRng, RsaKeyLength, RsaKeyWrappingAlgorithm, RsaPrivateKey,
};
use zeroize::Zeroizing;

let mut rng = CsRng::from_entropy();
println!("... Generating a 3072 bit RSA key ...");
let rsa_private_key = RsaPrivateKey::new(&mut rng, RsaKeyLength::Modulus3072).unwrap();

let mut key_to_wrap = [0_u8; 32];
rng.fill_bytes(&mut key_to_wrap);

let mut key_to_wrap = [0_u8; 189];
rng.fill_bytes(&mut key_to_wrap);
let key_to_wrap = Zeroizing::from(key_to_wrap.to_vec());

let rsa_public_key = rsa_private_key.public_key();

print!("Key wrapping with PKCS#11 CKM_RSA_AES_KEY_WRAP SHA-256 AES 256 ...");
let wrapped_key = rsa_public_key
.wrap_key(
&mut rng,
RsaKeyWrappingAlgorithm::Aes256Sha256,
&key_to_wrap,
)
.unwrap();

print!("unwrapping ...: ");
let unwrapped_key = rsa_private_key
.unwrap_key(RsaKeyWrappingAlgorithm::Aes256Sha256, &wrapped_key)
.unwrap();

assert_eq!(unwrapped_key, key_to_wrap);
println!("OK");

```

## Signature

The crate currently exposes the EdDSA (Ed25519) signature scheme.
Expand Down
4 changes: 4 additions & 0 deletions examples/examples/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
#[cfg(feature = "ecies")]
mod ecies;
#[cfg(feature = "rsa")]
mod rsa_key_wrapping;
#[cfg(feature = "curve25519")]
mod signature;
#[cfg(feature = "chacha")]
mod symmetric_crypto;

#[cfg(feature = "ecies")]
pub use self::ecies::*;
#[cfg(feature = "rsa")]
pub use self::rsa_key_wrapping::*;
#[cfg(feature = "curve25519")]
pub use self::signature::*;
#[cfg(feature = "chacha")]
Expand Down
38 changes: 38 additions & 0 deletions examples/examples/rsa_key_wrapping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#[cfg(feature = "rsa")]
pub fn rsa_key_wrapping() {
use cosmian_crypto_core::{
reexport::rand_core::{RngCore, SeedableRng},
CsRng, RsaKeyLength, RsaKeyWrappingAlgorithm, RsaPrivateKey,
};
use zeroize::Zeroizing;

let mut rng = CsRng::from_entropy();
println!("... Generating a 3072 bit RSA key ...");
let rsa_private_key = RsaPrivateKey::new(&mut rng, RsaKeyLength::Modulus3072).unwrap();

let mut key_to_wrap = [0_u8; 32];
rng.fill_bytes(&mut key_to_wrap);

let mut key_to_wrap = [0_u8; 189];
rng.fill_bytes(&mut key_to_wrap);
let key_to_wrap = Zeroizing::from(key_to_wrap.to_vec());

let rsa_public_key = rsa_private_key.public_key();

print!("Key wrapping with PKCS#11 CKM_RSA_AES_KEY_WRAP SHA-256 AES 256 ...");
let wrapped_key = rsa_public_key
.wrap_key(
&mut rng,
RsaKeyWrappingAlgorithm::Aes256Sha256,
&key_to_wrap,
)
.unwrap();

print!("unwrapping ...: ");
let unwrapped_key = rsa_private_key
.unwrap_key(RsaKeyWrappingAlgorithm::Aes256Sha256, &wrapped_key)
.unwrap();

assert_eq!(unwrapped_key, key_to_wrap);
println!("OK");
}
Loading

0 comments on commit 4b33753

Please sign in to comment.