use asn1_der::{Asn1Der, Asn1DerError, DerObject, DerTag, DerValue, FromDerObject, IntoDerObject};
use lazy_static::lazy_static;
use ring::rand::SystemRandom;
use ring::signature::KeyPair;
use ring::signature::{RsaKeyPair, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_SHA256};
use zeroize::Zeroize;
use std::{
fmt::{self, Write},
result,
sync::Arc,
};
use crate::{Error, Result};
#[derive(Clone)]
pub struct Keypair {
key_pair: Arc<RsaKeyPair>,
}
impl Keypair {
pub fn from_pkcs8(der: &mut [u8]) -> Result<Keypair> {
let key_pair = match RsaKeyPair::from_pkcs8(&der) {
Ok(val) => Ok(val),
Err(err) => {
let msg = format!("RSA PKCS#8 PrivateKeyInfo");
err_at!(DecodeError, Err(err), msg)
}
}?;
der.zeroize();
Ok(Keypair {
key_pair: Arc::new(key_pair),
})
}
pub fn to_public_key(&self) -> PublicKey {
PublicKey {
bin: self.key_pair.public_key().as_ref().to_vec(),
}
}
pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
let mut sig = vec![0; self.key_pair.public_modulus_len()];
let rng = SystemRandom::new();
match self.key_pair.sign(&RSA_PKCS1_SHA256, &rng, &data, &mut sig) {
Ok(()) => Ok(sig),
Err(err) => {
let msg = format!("RSA PublicKey Signing");
err_at!(SigningError, Err(err), msg)
}
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct PublicKey {
bin: Vec<u8>,
}
impl PublicKey {
pub fn verify(&self, msg: &[u8], signature: &[u8]) -> bool {
use ring::signature::UnparsedPublicKey;
let key = UnparsedPublicKey::new(&RSA_PKCS1_2048_8192_SHA256, &self.bin);
key.verify(msg, signature).is_ok()
}
pub fn encode_pkcs1(&self) -> Vec<u8> {
self.bin.clone()
}
pub fn encode_x509(&self) -> Result<Vec<u8>> {
let spki = Asn1SubjectPublicKeyInfo {
algo: Asn1RsaEncryption {
algorithm: Asn1OidRsaEncryption(),
parameters: (),
},
subject_public_key: Asn1SubjectPublicKey(self.clone()),
};
let mut buf = vec![0u8; spki.serialized_len()];
match spki.serialize(buf.iter_mut()) {
Ok(_) => Ok(buf),
Err(err) => {
let msg = format!("RSA X.509 public key encoding failed");
err_at!(EncodeError, Err(err), msg)
}
}
}
pub fn decode_x509(data: &[u8]) -> Result<PublicKey> {
match Asn1SubjectPublicKeyInfo::deserialize(data.iter()) {
Ok(val) => Ok(val.subject_public_key.0),
Err(err) => {
let msg = format!("RSA X.509");
err_at!(DecodeError, Err(err), msg)
}
}
}
}
impl fmt::Debug for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bytes = &self.bin;
let mut hex = String::with_capacity(bytes.len() * 2);
for byte in bytes {
write!(hex, "{:02x}", byte).expect("Can't fail on writing to string");
}
f.debug_struct("PublicKey").field("pkcs1", &hex).finish()
}
}
lazy_static! {
static ref OID_RSA_ENCRYPTION_DER: DerObject =
DerObject {
tag: DerTag::x06,
value: DerValue {
data: vec![ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 ]
}
};
}
#[derive(Clone)]
struct Asn1OidRsaEncryption();
impl IntoDerObject for Asn1OidRsaEncryption {
fn into_der_object(self) -> DerObject {
OID_RSA_ENCRYPTION_DER.clone()
}
fn serialized_len(&self) -> usize {
OID_RSA_ENCRYPTION_DER.serialized_len()
}
}
impl FromDerObject for Asn1OidRsaEncryption {
fn from_der_object(o: DerObject) -> result::Result<Self, Asn1DerError> {
if o.tag != DerTag::x06 {
return Err(Asn1DerError::InvalidTag);
}
if o.value != OID_RSA_ENCRYPTION_DER.value {
return Err(Asn1DerError::InvalidEncoding);
}
Ok(Asn1OidRsaEncryption())
}
}
#[derive(Asn1Der)]
struct Asn1RsaEncryption {
algorithm: Asn1OidRsaEncryption,
parameters: (),
}
struct Asn1SubjectPublicKey(PublicKey);
impl IntoDerObject for Asn1SubjectPublicKey {
fn into_der_object(self) -> DerObject {
let pk_der = (self.0).bin;
let mut bit_string = Vec::with_capacity(pk_der.len() + 1);
bit_string.push(0u8);
bit_string.extend(pk_der);
DerObject::new(DerTag::x03, bit_string.into())
}
fn serialized_len(&self) -> usize {
DerObject::compute_serialized_len((self.0).bin.len() + 1)
}
}
impl FromDerObject for Asn1SubjectPublicKey {
fn from_der_object(o: DerObject) -> result::Result<Self, Asn1DerError> {
if o.tag != DerTag::x03 {
return Err(Asn1DerError::InvalidTag);
}
let pk_der: Vec<u8> = o.value.data.into_iter().skip(1).collect();
Ok(Asn1SubjectPublicKey(PublicKey { bin: pk_der }))
}
}
#[derive(Asn1Der)]
#[allow(non_snake_case)]
struct Asn1SubjectPublicKeyInfo {
algo: Asn1RsaEncryption,
subject_public_key: Asn1SubjectPublicKey,
}
#[cfg(test)]
#[path = "rsa_test.rs"]
mod rsa_test;