Skip to content

Commit

Permalink
feat: initial setup for key gen and signature generation
Browse files Browse the repository at this point in the history
Former-commit-id: 4092c7d
  • Loading branch information
dignifiedquire committed Feb 20, 2019
1 parent 170a98c commit 7e1ab66
Show file tree
Hide file tree
Showing 31 changed files with 1,096 additions and 233 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repository = "https://github.com/dignifiedquire/rpgp"
keywords = ["pgp", "gpg", "pretty good privacy", "email", "encryption", "privacy"]

[dependencies]
rsa = "^0.1"
rsa = { git = "https://github.com/RustCrypto/rsa" }
num-bigint-dig = { version = "0.2", features = ["rand", "i128", "u64_digit"] }
crc24 = "^0.1"
base64 = { git = "https://github.com/dignifiedquire/rust-base64", branch = "fix/slow-writer" }
Expand Down Expand Up @@ -46,6 +46,7 @@ pretty_env_logger = "0.2.5"
buf_redux = { version = "0.8.1", default-features = false }
try_from = "^0.3"
rand = "0.5.5"
derive_builder = "0.7.0"

[dependencies.nom]
version = "^4.0"
Expand Down
6 changes: 3 additions & 3 deletions benches/key/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use std::fs::{self, File};
use test::{black_box, Bencher};

use pgp::composed::{Deserializable, PrivateKey};
use pgp::composed::{Deserializable, SignedSecretKey};

#[bench]
fn bench_private_key_rsa_parse(b: &mut Bencher) {
fn bench_secret_key_rsa_parse(b: &mut Bencher) {
let p = "./tests/opengpg-interop/testcases/messages/gnupg-v1-001-decrypt.asc";
b.iter(|| {
let mut decrypt_key_file = File::open(p).unwrap();
black_box(PrivateKey::from_armor_single(&mut decrypt_key_file).unwrap())
black_box(SignedSecretKey::from_armor_single(&mut decrypt_key_file).unwrap())
});

b.bytes = fs::metadata(p).unwrap().len();
Expand Down
4 changes: 2 additions & 2 deletions benches/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use test::{black_box, Bencher};
#[cfg(feature = "profile")]
use gperftools::profiler::PROFILER;

use pgp::composed::{Deserializable, Message, PrivateKey};
use pgp::composed::{Deserializable, Message, SignedSecretKey};

#[cfg(feature = "profile")]
#[inline(always)]
Expand Down Expand Up @@ -52,7 +52,7 @@ fn bench_message_parse(b: &mut Bencher) {
fn bench_message_decryption_rsa(b: &mut Bencher) {
let mut decrypt_key_file =
File::open("./tests/opengpg-interop/testcases/messages/gnupg-v1-001-decrypt.asc").unwrap();
let decrypt_key = PrivateKey::from_armor_single(&mut decrypt_key_file).unwrap();
let decrypt_key = SignedSecretKey::from_armor_single(&mut decrypt_key_file).unwrap();
let message_file_path = "./tests/opengpg-interop/testcases/messages/gnupg-v1-001.asc";
let mut message_file = File::open(message_file_path).unwrap();
let message = Message::from_armor_single(&mut message_file).unwrap();
Expand Down
15 changes: 12 additions & 3 deletions src/composed/key/public.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::io;

use composed::key::SignedKeyDetails;
use crypto::public_key::PublicKeyAlgorithm;
use errors::Result;
use generic_array::typenum::U64;
use line_writer::{LineBreak, LineWriter};
Expand Down Expand Up @@ -108,6 +109,10 @@ impl KeyTrait for SignedPublicKey {
fn key_id(&self) -> Option<KeyId> {
self.primary_key.key_id()
}

fn algorithm(&self) -> PublicKeyAlgorithm {
self.primary_key.algorithm()
}
}

impl Serialize for SignedPublicKey {
Expand All @@ -134,12 +139,12 @@ impl SignedPublicSubKey {
let signatures = signatures
.into_iter()
.filter(|sig| {
if sig.typ != SignatureType::SubkeyBinding
&& sig.typ != SignatureType::SubkeyRevocation
if sig.typ() != SignatureType::SubkeyBinding
&& sig.typ() != SignatureType::SubkeyRevocation
{
warn!(
"ignoring unexpected signature {:?} after Subkey packet",
sig.typ
sig.typ()
);
false
} else {
Expand Down Expand Up @@ -171,6 +176,10 @@ impl KeyTrait for SignedPublicSubKey {
fn key_id(&self) -> Option<KeyId> {
self.key.key_id()
}

fn algorithm(&self) -> PublicKeyAlgorithm {
self.key.algorithm()
}
}

impl Serialize for SignedPublicSubKey {
Expand Down
61 changes: 58 additions & 3 deletions src/composed/key/secret.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::io;

use composed::key::{SignedKeyDetails, SignedPublicSubKey};
use crypto::hash::HashAlgorithm;
use crypto::public_key::PublicKeyAlgorithm;
use errors::Result;
use generic_array::typenum::U64;
use line_writer::{LineBreak, LineWriter};
Expand Down Expand Up @@ -103,6 +105,7 @@ impl SignedSecretKey {
writer.write_all(&b"-----BEGIN PGP PRIVATE KEY BLOCK-----\n"[..])?;

// TODO: headers
writer.write_all(&b"\n"[..])?;

// write the base64 encoded content
{
Expand Down Expand Up @@ -140,6 +143,10 @@ impl KeyTrait for SignedSecretKey {
fn key_id(&self) -> Option<KeyId> {
self.primary_key.key_id()
}

fn algorithm(&self) -> PublicKeyAlgorithm {
self.primary_key.algorithm()
}
}

impl Serialize for SignedSecretKey {
Expand All @@ -166,6 +173,28 @@ impl SecretKeyTrait for SignedSecretKey {
{
self.primary_key.unlock(pw, work)
}

fn create_signature<F>(
&self,
key_pw: F,
hash: HashAlgorithm,
data: &[u8],
) -> Result<Vec<Vec<u8>>>
where
F: FnOnce() -> String,
{
self.primary_key.create_signature(key_pw, hash, data)
}
}

impl PublicKeyTrait for SignedSecretKey {
fn verify_signature(&self, hash: HashAlgorithm, data: &[u8], sig: &[Vec<u8>]) -> Result<()> {
self.primary_key.verify_signature(hash, data, sig)
}

fn to_writer_old(&self, _writer: &mut impl io::Write) -> Result<()> {
unimplemented!("")
}
}

/// Represents a composed secret PGP SubKey.
Expand All @@ -180,12 +209,12 @@ impl SignedSecretSubKey {
let signatures = signatures
.into_iter()
.filter(|sig| {
if sig.typ != SignatureType::SubkeyBinding
&& sig.typ != SignatureType::SubkeyRevocation
if sig.typ() != SignatureType::SubkeyBinding
&& sig.typ() != SignatureType::SubkeyRevocation
{
warn!(
"ignoring unexpected signature {:?} after Subkey packet",
sig.typ
sig.typ()
);
false
} else {
Expand Down Expand Up @@ -218,6 +247,10 @@ impl KeyTrait for SignedSecretSubKey {
fn key_id(&self) -> Option<KeyId> {
self.key.key_id()
}

fn algorithm(&self) -> PublicKeyAlgorithm {
self.key.algorithm()
}
}

impl Serialize for SignedSecretSubKey {
Expand All @@ -239,4 +272,26 @@ impl SecretKeyTrait for SignedSecretSubKey {
{
self.key.unlock(pw, work)
}

fn create_signature<F>(
&self,
key_pw: F,
hash: HashAlgorithm,
data: &[u8],
) -> Result<Vec<Vec<u8>>>
where
F: FnOnce() -> String,
{
self.key.create_signature(key_pw, hash, data)
}
}

impl PublicKeyTrait for SignedSecretSubKey {
fn verify_signature(&self, hash: HashAlgorithm, data: &[u8], sig: &[Vec<u8>]) -> Result<()> {
self.key.verify_signature(hash, data, sig)
}

fn to_writer_old(&self, _writer: &mut impl io::Write) -> Result<()> {
unimplemented!("")
}
}
8 changes: 8 additions & 0 deletions src/composed/key/shared.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::io;

use composed::key::{SignedPublicKey, SignedSecretKey};
use crypto::public_key::PublicKeyAlgorithm;
use errors::Result;
use packet;
use ser::Serialize;
Expand Down Expand Up @@ -178,4 +179,11 @@ impl KeyTrait for PublicOrSecret {
PublicOrSecret::Secret(k) => k.key_id(),
}
}

fn algorithm(&self) -> PublicKeyAlgorithm {
match self {
PublicOrSecret::Public(k) => k.algorithm(),
PublicOrSecret::Secret(k) => k.algorithm(),
}
}
}
3 changes: 2 additions & 1 deletion src/composed/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ mod tests {
)
.expect("failed to decrypt message")
.next()
.expect("no mesage")
.expect("no message")
.expect("message decryption failed");

if let Some(verify_key) = verify_key {
Expand Down Expand Up @@ -611,6 +611,7 @@ mod tests {
}
_ => {
// TODO: some other checks?
panic!("this test should not have anything else?");
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/composed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub mod message;
mod message_parser;
mod shared;

pub use self::key::{SignedPublicKey, SignedPublicSubKey, SignedSecretKey, SignedSecretSubKey};
pub use self::key::{
SignedKeyDetails, SignedPublicKey, SignedPublicSubKey, SignedSecretKey, SignedSecretSubKey,
};
pub use self::message::Message;
pub use self::shared::Deserializable;
21 changes: 16 additions & 5 deletions src/crypto/checksum.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use byteorder::{BigEndian, ReadBytesExt};
use byteorder::{BigEndian, WriteBytesExt};
use sha1::{Digest, Sha1};

use errors::Result;
Expand All @@ -9,11 +9,13 @@ pub fn simple(actual: &[u8], data: &[u8]) -> Result<()> {
// Then a two-octet checksum is appended, which is equal to the
// sum of the preceding session key octets, not including the algorithm
// identifier, modulo 65536.
let mut actual = actual;
let checksum = u32::from(actual.read_u16::<BigEndian>()?);
let expected_checksum = data.iter().map(|v| u32::from(*v)).sum::<u32>() & 0xffff;
let expected_checksum = calculate_simple(data);

ensure_eq!(checksum, expected_checksum, "invalid simple checksum");
ensure_eq!(
&actual[..2],
&expected_checksum[..],
"invalid simple checksum"
);

Ok(())
}
Expand All @@ -25,3 +27,12 @@ pub fn sha1(hash: &[u8], data: &[u8]) -> Result<()> {

Ok(())
}

#[inline]
pub fn calculate_simple(data: &[u8]) -> Vec<u8> {
let val = (data.iter().map(|v| u32::from(*v)).sum::<u32>() & 0xffff) as u16;
let mut res = Vec::with_capacity(2);
res.write_u16::<BigEndian>(val).expect("pre allocated");

res
}
6 changes: 6 additions & 0 deletions src/crypto/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ pub enum HashAlgorithm {
Private10 = 110,
}

impl Default for HashAlgorithm {
fn default() -> Self {
HashAlgorithm::SHA512
}
}

impl TryInto<Hashes> for HashAlgorithm {
type Err = Error;

Expand Down
2 changes: 1 addition & 1 deletion src/crypto/public_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub enum PublicKeyAlgorithm {
}

/// Represent the public paramaters for the different algorithms.
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Clone)]
pub enum PublicParams {
RSA {
n: BigUint,
Expand Down
35 changes: 34 additions & 1 deletion src/crypto/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use try_from::TryInto;
use crypto::ecc_curve::ECCCurve;
use crypto::hash::HashAlgorithm;
use errors::Result;
use rsa::{self, padding, RSAPublicKey};
use rsa::{self, padding, RSAPrivateKey, RSAPublicKey};
use types::EdDSASecretKey;

/// Verify a RSA, PKCS1v15 padded signature.
pub fn verify_rsa(
Expand All @@ -29,6 +30,14 @@ pub fn verify_rsa(
.map_err(|err| err.into())
}

/// Sign using RSA, with PKCS1v15 padding.
pub fn sign_rsa(key: &RSAPrivateKey, hash: HashAlgorithm, digest: &[u8]) -> Result<Vec<Vec<u8>>> {
let rsa_hash: Option<rsa::hash::Hashes> = hash.try_into().ok();
let sig = key.sign(padding::PaddingScheme::PKCS1v15, rsa_hash.as_ref(), digest)?;

Ok(vec![sig])
}

/// Verify an EdDSA signature.
pub fn verify_eddsa(
curve: &ECCCurve,
Expand Down Expand Up @@ -64,3 +73,27 @@ pub fn verify_eddsa(
_ => unsupported_err!("curve {:?} for EdDSA", curve.to_string()),
}
}

/// Sign using RSA, with PKCS1v15 padding.
pub fn sign_eddsa(
q: &[u8],
secret_key: &EdDSASecretKey,
_hash: HashAlgorithm,
digest: &[u8],
) -> Result<Vec<Vec<u8>>> {
ensure_eq!(q.len(), 33, "invalid Q (len)");
ensure_eq!(q[0], 0x40, "invalid Q (prefix)");

let mut kp_bytes = vec![0u8; 64];
kp_bytes[..32].copy_from_slice(&secret_key.secret);
kp_bytes[32..].copy_from_slice(&q[1..]);
let kp = ed25519_dalek::Keypair::from_bytes(&kp_bytes)?;

let signature = kp.sign::<sha2::Sha512>(digest);
let bytes = signature.to_bytes();

let r = bytes[..32].to_vec();
let s = bytes[32..].to_vec();

Ok(vec![r, s])
}
6 changes: 6 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ impl From<SignatureError> for Error {
}
}

impl From<String> for Error {
fn from(err: String) -> Error {
Error::Message(err)
}
}

#[macro_export]
macro_rules! unimplemented_err {
($e:expr) => {
Expand Down
Loading

0 comments on commit 7e1ab66

Please sign in to comment.