Skip to content

Commit

Permalink
dsa: Add signature tests
Browse files Browse the repository at this point in the history
  • Loading branch information
aumetra committed May 13, 2022
1 parent 68714fe commit 40e7fd2
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 16 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dsa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ default = []
[dev-dependencies]
pkcs8 = { version = "0.9.0", default-features = false, features = ["pem"] }
rand = "0.8.5"
rand_chacha = "0.3.1"
sha1 = "0.10.1"
sha2 = "0.10.2"
24 changes: 8 additions & 16 deletions dsa/src/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use alloc::vec::Vec;
use num_bigint::BigUint;
use pkcs8::der::{self, asn1::UIntRef, Decode, Encode, Reader, Sequence, SliceReader};
use pkcs8::der::{self, asn1::UIntRef, Decode, Encode, Reader, Sequence};

/// Container of the DSA signature
#[derive(Clone)]
Expand Down Expand Up @@ -35,16 +35,6 @@ impl Signature {
signature
}

/// Decode a Signature from its DER representation
///
/// # Errors
///
/// See the [`der` errors](::pkcs8::der::Error)
pub fn from_der(data: &[u8]) -> der::Result<Self> {
let mut reader = SliceReader::new(data)?;
reader.decode()
}

/// Signature part r
#[must_use]
pub fn r(&self) -> &BigUint {
Expand All @@ -66,13 +56,15 @@ impl AsRef<[u8]> for Signature {

impl<'a> Decode<'a> for Signature {
fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> {
let r = reader.decode::<UIntRef<'_>>()?;
let s = reader.decode::<UIntRef<'_>>()?;
reader.sequence(|sequence| {
let r = sequence.decode::<UIntRef<'_>>()?;
let s = sequence.decode::<UIntRef<'_>>()?;

let r = BigUint::from_bytes_be(r.as_bytes());
let s = BigUint::from_bytes_be(s.as_bytes());
let r = BigUint::from_bytes_be(r.as_bytes());
let s = BigUint::from_bytes_be(s.as_bytes());

Ok(Self::from_components(r, s))
Ok(Self::from_components(r, s))
})
}
}

Expand Down
89 changes: 89 additions & 0 deletions dsa/tests/signature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#![allow(deprecated)]

use digest::Digest;
use dsa::{consts::DSA_1024_160, Components, PrivateKey, Signature};
use pkcs8::der::{Decode, Encode};
use rand::{CryptoRng, RngCore, SeedableRng};
use rand_chacha::ChaCha8Rng;
use sha2::Sha256;
use signature::{DigestVerifier, RandomizedDigestSigner};

/// Seed used for the ChaCha8 RNG
const SEED: u64 = 0x2103_1949;

/// Message to be signed/verified
const MESSAGE: &[u8] = b"test";

/// Message signed by this crate using the keys generated by this CSPRNG
///
/// This signature was generated using the keys generated by this CSPRNG (the per-message `k` component was also generated using the CSPRNG)
const MESSAGE_SIGNATURE_CRATE_ASN1: &[u8] = &[
0x30, 0x2C, 0x02, 0x14, 0x45, 0x1D, 0xE5, 0x76, 0x21, 0xD8, 0xFD, 0x76, 0xC1, 0x6F, 0x45, 0x4E,
0xDE, 0x5F, 0x09, 0x79, 0x76, 0x52, 0xF3, 0xA5, 0x02, 0x14, 0x53, 0x60, 0xE6, 0xB7, 0xF0, 0xCF,
0xAE, 0x49, 0xB1, 0x58, 0x5C, 0xCF, 0x5F, 0x3F, 0x94, 0x49, 0x21, 0xA0, 0xBF, 0xD2,
];

/// Message signed by OpenSSL using the keys generated by this CSPRNG
///
/// This signature was generated using the SHA-256 digest
const MESSAGE_SIGNATURE_OPENSSL_ASN1: &[u8] = &[
0x30, 0x2C, 0x02, 0x14, 0x6D, 0xB3, 0x8E, 0xAF, 0x97, 0x13, 0x7E, 0x07, 0xFF, 0x24, 0xB8, 0x66,
0x97, 0x18, 0xE1, 0x6F, 0xD7, 0x9A, 0x28, 0x2D, 0x02, 0x14, 0x47, 0x8C, 0x0B, 0x96, 0x51, 0x08,
0x08, 0xC8, 0x34, 0x9D, 0x0D, 0x41, 0xC7, 0x73, 0x0F, 0xB5, 0x9C, 0xBB, 0x00, 0x34,
];

/// Get the seeded CSPRNG
fn seeded_csprng() -> impl CryptoRng + RngCore {
ChaCha8Rng::seed_from_u64(SEED)
}

/// Generate a DSA keypair using a seeded CSPRNG
fn generate_deterministic_keypair() -> PrivateKey {
let mut rng = seeded_csprng();
let components = Components::generate(&mut rng, DSA_1024_160);
PrivateKey::generate(&mut rng, components)
}

#[test]
fn decode_encode_signature() {
let signature_openssl =
Signature::from_der(MESSAGE_SIGNATURE_OPENSSL_ASN1).expect("Failed to decode signature");
let encoded_signature_openssl = signature_openssl
.to_vec()
.expect("Failed to encode signature");

assert_eq!(MESSAGE_SIGNATURE_OPENSSL_ASN1, encoded_signature_openssl);

let signature_crate =
Signature::from_der(MESSAGE_SIGNATURE_CRATE_ASN1).expect("Failed to decode signature");
let encoded_signature_crate = signature_crate
.to_vec()
.expect("Failed to encode signature");

assert_eq!(MESSAGE_SIGNATURE_CRATE_ASN1, encoded_signature_crate);
}

#[test]
fn sign_message() {
let private_key = generate_deterministic_keypair();
let generated_signature =
private_key.sign_digest_with_rng(seeded_csprng(), Sha256::new().chain_update(MESSAGE));

let expected_signature =
Signature::from_der(MESSAGE_SIGNATURE_CRATE_ASN1).expect("Failed to decode signature");

assert_eq!(generated_signature, expected_signature);
}

#[test]
fn verify_signature() {
let private_key = generate_deterministic_keypair();
let public_key = private_key.public_key();

let signature = Signature::from_der(MESSAGE_SIGNATURE_OPENSSL_ASN1)
.expect("Failed to parse ASN.1 representation of the test signature");

assert!(public_key
.verify_digest(Sha256::new().chain_update(MESSAGE), &signature)
.is_ok());
}

0 comments on commit 40e7fd2

Please sign in to comment.