Skip to content

Commit

Permalink
feat: add dsa support
Browse files Browse the repository at this point in the history
Using the `dsa` crate, implement basic DSA support

---------

Co-authored-by: Ronald Volgers <rvolgers@users.noreply.github.com>
Co-authored-by: Heiko Schaefer <59601023+hko-s@users.noreply.github.com>
  • Loading branch information
3 people committed Feb 8, 2024
1 parent 414250a commit 4ed459b
Show file tree
Hide file tree
Showing 12 changed files with 538 additions and 37 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ categories = ["cryptography", "email"]
exclude = ["tests/tests/*"]

edition = "2021"
rust-version = "1.67"
rust-version = "1.69"

[dependencies]
aes = "^0.8"
Expand All @@ -33,6 +33,7 @@ crc24 = "^0.1"
derive_builder = "^0.12.0"
des = "^0.8"
digest = "^0.10"
dsa = "^0.6.3"
elliptic-curve = "^0.13"
generic-array = "^0.14"
hex = "^0.4"
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![crates.io][crate-image]][crate-link]
[![Documentation][doc-image]][doc-link]
[![Build Status][build-image]][build-link]
![minimum rustc 1.65][msrv-image]
![minimum rustc 1.69][msrv-image]
[![dependency status][deps-image]][deps-link]
[![License][license-image]][license-link]

Expand All @@ -21,13 +21,13 @@ For ECC crypto support we are using [Curve25519-dalek](https://crates.io/crates/
## Status (Last updated: October 2019)

rPGP and its RSA dependency got an independent security audit mid 2019,
see here for the [full report from IncludeSecurity](https://delta.chat/assets/blog/2019-first-security-review.pdf).
No critical flaws were found and we have fixed most high, medium and low risk ones.
rPGP and its RSA dependency got an independent security audit mid 2019,
see here for the [full report from IncludeSecurity](https://delta.chat/assets/blog/2019-first-security-review.pdf).
No critical flaws were found and we have fixed most high, medium and low risk ones.

rPGP is used in production by [Delta Chat, the e-mail based messenger app suite](https://delta.chat), successfully running on Windows, Linux, macOS, Android and iOS in 32bit (only Windows and Android) and 64 bit builds (for the other platforms).

More details on platform and OpenPGP implementation status:
More details on platform and OpenPGP implementation status:

- [OpenPGP Status document](STATUS.md) which describes what of OpenPGP is supported
- [Platform status document](PLATFORMS.md) which describes current platform support.
Expand Down Expand Up @@ -69,7 +69,7 @@ Some key differences:

## Minimum Supported Rust Version (MSRV)

All crates in this repository support Rust 1.65 or higher. In future minimally supported version of Rust can be changed, but it will be done with a minor version bump.
All crates in this repository support Rust 1.69 or higher. In future minimally supported version of Rust can be changed, but it will be done with a minor version bump.

## LICENSE

Expand Down
7 changes: 4 additions & 3 deletions STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Symbols:
- [x] Old Format (v3)
- [x] New Format (v4)
- [ ] 🚧 New New Format (v5)
- [ ] v6
- [x] ASCII Armor
- [x] Reading
- [x] Writing
Expand All @@ -26,12 +27,12 @@ Symbols:
- [x] Generation
- [x] Export
- [x] Import
- [ ] Public-Key Algorithms
- [x] Public-Key Algorithms
- [x] RSA
- [ ] 🚫 Elgamal (Encrypt only)
- [ ] DSA
- [x] DSA
- [x] ECDH
- [ ] ECDSA
- [x] ECDSA
- [x] EdDSA
- [ ] Supported Elliptic Curves
- [X] NIST P256
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.67.0
1.69.0
122 changes: 120 additions & 2 deletions src/composed/key/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::crypto::ecc_curve::ECCCurve;
use crate::crypto::hash::HashAlgorithm;
use crate::crypto::public_key::PublicKeyAlgorithm;
use crate::crypto::sym::SymmetricKeyAlgorithm;
use crate::crypto::{ecdh, ecdsa, eddsa, rsa};
use crate::crypto::{dsa, ecdh, ecdsa, eddsa, rsa};
use crate::errors::Result;
use crate::packet::{self, KeyFlags, UserAttribute, UserId};
use crate::types::{self, CompressionAlgorithm, PublicParams, RevocationKey};
Expand Down Expand Up @@ -124,6 +124,13 @@ impl SecretKeyParamsBuilder {
}
}
}
Some(KeyType::Dsa(_)) => {
if let Some(can_encrypt) = self.can_encrypt {
if can_encrypt {
return Err("DSA can only be used for signing keys".into());
}
}
}
_ => {}
}

Expand Down Expand Up @@ -226,14 +233,38 @@ impl SecretKeyParams {

#[derive(Clone, Debug, Copy, PartialEq, Eq)]
pub enum KeyType {
/// Encryption & Signing with RSA an the given bitsize.
/// Encryption & Signing with RSA and the given bitsize.
Rsa(u32),
/// Encrypting with Curve25519
ECDH,
/// Signing with Curve25519
EdDSA,
/// Signing with ECDSA
ECDSA(ECCCurve),
/// Signing with DSA for the given bitsize.
Dsa(DsaKeySize),
}

#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum DsaKeySize {
/// DSA parameter size constant: L = 1024, N = 160
B1024 = 1024,
/// DSA parameter size constant: L = 2048, N = 256
B2048 = 2048,
/// DSA parameter size constant: L = 3072, N = 256
B3072 = 3072,
}

impl From<DsaKeySize> for dsa::KeySize {
fn from(value: DsaKeySize) -> Self {
match value {
#[allow(deprecated)]
DsaKeySize::B1024 => dsa::KeySize::DSA_1024_160,
DsaKeySize::B2048 => dsa::KeySize::DSA_2048_256,
DsaKeySize::B3072 => dsa::KeySize::DSA_3072_256,
}
}
}

impl KeyType {
Expand All @@ -243,6 +274,7 @@ impl KeyType {
KeyType::ECDH => PublicKeyAlgorithm::ECDH,
KeyType::EdDSA => PublicKeyAlgorithm::EdDSA,
KeyType::ECDSA(_) => PublicKeyAlgorithm::ECDSA,
KeyType::Dsa(_) => PublicKeyAlgorithm::DSA,
}
}

Expand All @@ -264,6 +296,7 @@ impl KeyType {
KeyType::ECDH => ecdh::generate_key(rng),
KeyType::EdDSA => eddsa::generate_key(rng),
KeyType::ECDSA(curve) => ecdsa::generate_key(rng, curve)?,
KeyType::Dsa(key_size) => dsa::generate_key(rng, key_size.into())?,
};

let secret = match passphrase {
Expand Down Expand Up @@ -611,4 +644,89 @@ mod tests {
gen_ecdsa(rng, ECCCurve::Secp256k1);
}
}

fn gen_dsa<R: Rng + CryptoRng>(rng: &mut R, key_size: DsaKeySize) {
let _ = pretty_env_logger::try_init();

let key_params = SecretKeyParamsBuilder::default()
.key_type(KeyType::Dsa(key_size))
.can_create_certificates(true)
.can_sign(true)
.primary_user_id("Me-X <me-dsa@mail.com>".into())
.passphrase(None)
.preferred_symmetric_algorithms(smallvec![
SymmetricKeyAlgorithm::AES256,
SymmetricKeyAlgorithm::AES192,
SymmetricKeyAlgorithm::AES128,
])
.preferred_hash_algorithms(smallvec![
HashAlgorithm::SHA2_256,
HashAlgorithm::SHA2_384,
HashAlgorithm::SHA2_512,
HashAlgorithm::SHA2_224,
HashAlgorithm::SHA1,
])
.preferred_compression_algorithms(smallvec![
CompressionAlgorithm::ZLIB,
CompressionAlgorithm::ZIP,
])
.subkey(
SubkeyParamsBuilder::default()
.key_type(KeyType::ECDH)
.can_encrypt(true)
.passphrase(None)
.build()
.unwrap(),
)
.build()
.unwrap();

let key = key_params
.generate_with_rng(rng)
.expect("failed to generate secret key");

let signed_key = key.sign(|| "".into()).expect("failed to sign key");

let armor = signed_key
.to_armored_string(None)
.expect("failed to serialize key");

std::fs::write("sample-dsa.sec.asc", &armor).unwrap();

let (signed_key2, _headers) =
SignedSecretKey::from_string(&armor).expect("failed to parse key");
signed_key2.verify().expect("invalid key");

assert_eq!(signed_key, signed_key2);

let public_key = signed_key.public_key();

let public_signed_key = public_key
.sign(&signed_key, || "".into())
.expect("failed to sign public key");

public_signed_key.verify().expect("invalid public key");

let armor = public_signed_key
.to_armored_string(None)
.expect("failed to serialize public key");

std::fs::write(format!("sample-dsa-{key_size:?}.pub.asc"), &armor).unwrap();

let (signed_key2, _headers) =
SignedPublicKey::from_string(&armor).expect("failed to parse public key");
signed_key2.verify().expect("invalid public key");
}

// Test is slow in debug mode
#[test]
#[ignore]
fn key_gen_dsa() {
let rng = &mut ChaCha8Rng::seed_from_u64(0);
for _ in 0..10 {
gen_dsa(rng, DsaKeySize::B1024);
gen_dsa(rng, DsaKeySize::B2048);
gen_dsa(rng, DsaKeySize::B3072);
}
}
}
Loading

0 comments on commit 4ed459b

Please sign in to comment.