2 unstable releases
0.2.0 | Oct 14, 2024 |
---|---|
0.1.0 | Oct 11, 2024 |
#483 in Cryptography
52 downloads per month
445KB
7.5K
SLoC
QuantCrypt
The goal of this library is to provide a simple and easy-to-use interface for generating key pairs, certificates, signing and verifying messages, and encrypting and decrypting messages using post-quantum cryptographic algorithms.
A secondary goal is to provide a set of cryptographic algorithms that are compatible with existing X.509, PKIX, and CMS data structures and protocols and to support the efforts of the LAMPS Working Group in the IETF especially the draft-ietf-lamps-pq-composite-sigs and draft-ietf-lamps-pq-composite-kem drafts.
Including quantcrypt in your project
Import quantcrypt into your project by adding the following lines to your Cargo.toml.
[dependencies]
quantcrypt = "0.2.0"
For the purposes of the PQC Hackathon, the library can also be included in IPD mode (for ML-DSA and ML-KEM only). This mode is enabled by setting the ipd
feature in your Cargo.toml.
[dependencies]
quantcrypt = { version = "0.2.0", features = ["ipd"] }
When the ipd
feature is enabled, the library will use IPD OIDs and will not use the newly introduced context
parameter in the finalized FIPS 204 standard. SLH-DSA signatures will not be supported in this mode.
Otherwise, it will use the finalized OIDs where possible, and will use the context
parameter in the finalized FIPS 204 standard by setting it to an empty string.
Generating PQC Hackathon Artifacts for IETF Hackathon - PQC Certificates
For IPD artifacts (presently compatible with OQS provider)
cargo test gen_pq_hackathon_artifacts_r3 --release --features ipd # generate artifacts in r3 format
cargo test gen_pq_hackathon_artifacts_r4 --release --features ipd # generate artifacts in r4 format
For non-IPD artifacts (with the NIST context
parameter)
cargo test gen_pq_hackathon_artifacts_r3 --release # generate artifacts in r3 format
cargo test gen_pq_hackathon_artifacts_r4 --release # generate artifacts in r4 format
To generate submissios zips:
python prepare_submission.py # Select appropriate certificates and archive them as zips for submission
Artifacts in both r3 and r4 format are generated. They can be found in artifacts/submission
folder.
Interoperability Results
Once the artifacts are submitted to the IETF Hackathon PQC Certificates repository, the interoperability results can be found at the IETF PQC Hackathon Certificate Automated Verification Interoperability Results page.
Generating Key Pairs and Certificates
The following snippet demonstrates how to generate a key pair and a certificate using the DSA and KEM algorithms. In addition to pure ML-DSA and ML-KEM algorithms, the library also supports composite algorithms that combine a traditional and post-quantum algorithm into a single key pair and certificate.
use quantcrypt::certificates::CertificateBuilder;
use quantcrypt::dsas::DsaAlgorithm;
use quantcrypt::kems::KemAlgorithm;
use quantcrypt::certificates::Profile;
use quantcrypt::dsas::DsaKeyGenerator;
use quantcrypt::kems::KemKeyGenerator;
use quantcrypt::certificates::CertValidity;
// Create a TA key pair
let (pk_root, sk_root) = DsaKeyGenerator::new(DsaAlgorithm::MlDsa44).generate().unwrap();
let profile = Profile::Root;
let serial_no = None; // This will generate a random serial number
let validity = CertValidity::new(None, "2035-01-01T00:00:00Z").unwrap(); // Not before is now
let subject = "CN=example.com".to_string();
let cert_public_key = pk_root.clone();
let signer = &sk_root;
// Create the TA certificate builder
let builder = CertificateBuilder::new(
profile,
serial_no,
validity.clone(),
subject.clone(),
cert_public_key,
signer
).unwrap();
let cert_root = builder.build().unwrap();
assert!(cert_root.verify_self_signed().unwrap());
// Create a leaf (EE) key pair for KEM
let (pk_kem, sk_kem) = KemKeyGenerator::new(KemAlgorithm::MlKem512).generate().unwrap();
let builder = CertificateBuilder::new(
Profile::Leaf {
issuer: cert_root.get_subject(),
enable_key_agreement: false,
enable_key_encipherment: true,
},
serial_no,
validity,
subject,
pk_kem,
signer
).unwrap();
let cert_kem = builder.build().unwrap();
// It's not self signed so verification so self signed should fail
assert!(!cert_kem.verify_self_signed().unwrap());
// But it should verify against the root
assert!(cert_root.verify_child(&cert_kem).unwrap());
Generating Enveloped Data CMS Message
The following snippet demonstrates how to generate a CMS message using the DSA and KEM algorithms.
use quantcrypt::content::EnvelopedDataContent;
use quantcrypt::content::ContentEncryptionAlgorithm;
use quantcrypt::certificates::Certificate;
use quantcrypt::keys::PrivateKey;
use quantcrypt::kdfs::KdfType;
use quantcrypt::wraps::WrapType;
use quantcrypt::content::UserKeyingMaterial;
use quantcrypt::content::ObjectIdentifier;
use quantcrypt::content::Attribute;
use quantcrypt::content::Tag;
use quantcrypt::content::AttributeValue;
use quantcrypt::content::SetOfVec;
// Based on whether IPD feature is enabled or not, use the appropriate test data
let rc_filename = if quantcrypt::is_ipd_mode_enabled() {
"test/data_ipd/cms_cw/1.3.6.1.4.1.22554.5.6.1_ML-KEM-512-ipd_ee.der"
} else {
"test/data/cms/2.16.840.1.101.3.4.4.1_MlKem512_ee.der"
};
let recipient_cert = Certificate::from_file(
rc_filename,
).unwrap();
let sk_filename = if quantcrypt::is_ipd_mode_enabled() {
"test/data_ipd/cms_cw/1.3.6.1.4.1.22554.5.6.1_ML-KEM-512-ipd_priv.der"
} else {
"test/data/cms/2.16.840.1.101.3.4.4.1_MlKem512_priv.der"
};
let private_key = PrivateKey::from_file(
sk_filename
).unwrap();
let ukm = UserKeyingMaterial::new("test".as_bytes()).unwrap();
let data = b"abc";
let attribute_oid = ObjectIdentifier::new("1.3.6.1.4.1.22554.5.6").unwrap();
let mut attribute_vals: SetOfVec<AttributeValue> = SetOfVec::<AttributeValue>::new();
let attr_val = AttributeValue::new(Tag::OctetString, data.to_vec()).unwrap();
attribute_vals.insert(attr_val).unwrap();
let attribute = Attribute {
oid: attribute_oid,
values: attribute_vals,
};
let mut builder = EnvelopedDataContent::get_builder(ContentEncryptionAlgorithm::Aes128Cbc).unwrap();
builder
.kem_recipient(
&recipient_cert,
&KdfType::HkdfWithSha256,
&WrapType::Aes256,
Some(ukm),
)
.unwrap()
.content(data)
.unwrap()
.unprotected_attribute(&attribute)
.unwrap();
let content = builder.build().unwrap();
// Now use this content to create a new EnvelopedDataContent
let edc = EnvelopedDataContent::from_bytes_for_kem_recipient(
&content,
&recipient_cert,
&private_key,
).unwrap();
assert_eq!(edc.get_content(), data);
Generating Auth Enveloped Data CMS Message
Auth Enveloped Data is much like the above snippet but using AuthEnvelopedDataContent
instead of EnvelopedDataContent
.
use quantcrypt::content::AuthEnvelopedDataContent;
use quantcrypt::content::ContentEncryptionAlgorithmAead;
use quantcrypt::certificates::Certificate;
use quantcrypt::keys::PrivateKey;
use quantcrypt::kdfs::KdfType;
use quantcrypt::wraps::WrapType;
use quantcrypt::content::UserKeyingMaterial;
use quantcrypt::content::ObjectIdentifier;
use quantcrypt::content::Attribute;
use quantcrypt::content::Tag;
use quantcrypt::content::AttributeValue;
use quantcrypt::content::SetOfVec;
let rc_filename = if quantcrypt::is_ipd_mode_enabled() {
"test/data_ipd/cms_cw/1.3.6.1.4.1.22554.5.6.1_ML-KEM-512-ipd_ee.der"
} else {
"test/data/cms/2.16.840.1.101.3.4.4.1_MlKem512_ee.der"
};
let recipient_cert = Certificate::from_file(
rc_filename,
).unwrap();
let sk_filename = if quantcrypt::is_ipd_mode_enabled() {
"test/data_ipd/cms_cw/1.3.6.1.4.1.22554.5.6.1_ML-KEM-512-ipd_priv.der"
} else {
"test/data/cms/2.16.840.1.101.3.4.4.1_MlKem512_priv.der"
};
let private_key = PrivateKey::from_file(
sk_filename
).unwrap();
let ukm = UserKeyingMaterial::new("test".as_bytes()).unwrap();
let data = b"abc";
let attribute_oid = ObjectIdentifier::new("1.3.6.1.4.1.22554.5.6").unwrap();
let mut attribute_vals: SetOfVec<AttributeValue> = SetOfVec::<AttributeValue>::new();
let attr_val = AttributeValue::new(Tag::OctetString, data.to_vec()).unwrap();
attribute_vals.insert(attr_val).unwrap();
let attribute = Attribute {
oid: attribute_oid,
values: attribute_vals,
};
let mut builder = AuthEnvelopedDataContent::get_builder(ContentEncryptionAlgorithmAead::Aes256Gcm).unwrap();
builder
.kem_recipient(
&recipient_cert,
&KdfType::HkdfWithSha256,
&WrapType::Aes256,
Some(ukm),
)
.unwrap()
.content(data)
.unwrap()
.auth_attribute(&attribute)
.unwrap();
let content = builder.build().unwrap();
// Now use this content to create a new AuthEnvelopedDataContent
let edc = AuthEnvelopedDataContent::from_bytes_for_kem_recipient(
&content,
&recipient_cert,
&private_key,
).unwrap();
assert_eq!(edc.get_content(), data);
Minimum Supported Rust Version (MSRV)
The minimum supported Rust version for this library is 1.81.0
License
All crates licensed under either of
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~23MB
~314K SLoC