// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use modinv::modinv::inv_mod_u32;
use num::bigint::BigUint;
use num::traits::Pow;
use ring::signature::KeyPair;
use thiserror::Error;
use zerocopy::{byteorder::big_endian::U32, AsBytes};

/// Number of bytes of a Signature.
pub const SIGNATURE_SIZE: u64 = 0x200;

/// Signature bytes returned by Key::sign().
pub type Signature = Vec<u8>;

fn calculate_rr(m: &BigUint, num_bits: u32) -> BigUint {
    let two_power_num_bits = BigUint::from(2u32).pow(num_bits);
    let rr: BigUint = two_power_num_bits.pow(2u8) % m;
    rr
}

fn calculate_n0inv(m: &BigUint) -> u32 {
    assert!(m.to_bytes_le().len() >= 4);
    let mut num_bytes = [0u8; 4];
    num_bytes[..].copy_from_slice(&m.to_bytes_le()[..4]);
    let num = u32::from_le_bytes(num_bytes);
    let n0inv = 0u32.wrapping_sub(inv_mod_u32(num));
    n0inv
}

#[derive(Debug)]
/// An AVB key used for creating signatures.
pub struct Key {
    /// The AVB key metadata raw bytes, which are written directly into the VBMeta blob.
    pub metadata_bytes: Vec<u8>,
    rsa: ring::signature::RsaKeyPair,
}

/// Errors that can occur during construction of a Key when parsing the PEM file.
#[derive(Error, Debug)]
pub enum KeyError {
    /// The PEM cannot be converted to a DER.
    #[error("cannot parse the pem")]
    ParsePem(#[from] pem::PemError),
    /// The DER cannot be converted to a RSA key pair.
    #[error("cannot parse the der")]
    ParseDer,
}

#[derive(Error, Debug)]
#[error("failed to sign")]
/// Signing with the key failed.
pub struct SignFailure;

impl From<ring::error::Unspecified> for SignFailure {
    fn from(_err: ring::error::Unspecified) -> Self {
        SignFailure
    }
}

impl Key {
    /// Construct a new Key using the provided PEM string and metadata bytes.
    /// This method can fail if the PEM or contained DER cannot be parsed.
    pub fn try_new<M: Into<Vec<u8>>>(pem_str: &str, metadata: M) -> Result<Key, KeyError> {
        let pem = pem::parse(pem_str)?;
        let rsa_result = ring::signature::RsaKeyPair::from_pkcs8(&pem.contents);
        if rsa_result.is_err() {
            return Err(KeyError::ParseDer);
        }
        let rsa = rsa_result.unwrap();
        Ok(Key { rsa, metadata_bytes: metadata.into() })
    }

    /// Sign `data` with the owned RSA key pair and return the Signature.
    pub fn sign(&self, data: &[u8]) -> Result<Signature, SignFailure> {
        let mut out = vec![0u8; SIGNATURE_SIZE as usize];
        let rng = ring::rand::SystemRandom::new();
        self.rsa.sign(&ring::signature::RSA_PKCS1_SHA512, &rng, data, &mut out)?;
        Ok(out)
    }

    /// Generate the AVB key header to be written directly into the VBMeta blob.
    pub fn generate_key_header(&self) -> Vec<u8> {
        let num_bits: u32 = (self.rsa.public_modulus_len() * 8usize) as u32;
        let num_bits_big_endian = U32::new(num_bits);
        let modulus = BigUint::from_bytes_be(
            self.rsa.public_key().modulus().big_endian_without_leading_zero(),
        );

        let rr = calculate_rr(&modulus, num_bits);
        let n0inv = calculate_n0inv(&modulus);

        // Assemble the bytes.
        let mut bytes: Vec<u8> = Vec::new();
        bytes.extend_from_slice(num_bits_big_endian.as_bytes());
        bytes.extend_from_slice(U32::new(n0inv).as_bytes());
        bytes.extend_from_slice(&modulus.to_bytes_be());
        bytes.extend_from_slice(&rr.to_bytes_be());
        bytes
    }

    /// Returns a reference to the public portion of the key.
    pub fn public_key(&self) -> &ring::signature::RsaSubjectPublicKey {
        self.rsa.public_key()
    }
}

#[cfg(test)]
mod tests {
    use crate::key::Key;
    use crate::test;

    #[test]
    fn invalid_key() {
        let key = Key::try_new("Real Fake Doors", test::TEST_METADATA);
        assert!(key.is_err());
    }

    #[test]
    fn sign() {
        let key = Key::try_new(&test::TEST_PEM, test::TEST_METADATA).expect("new key");
        let signature = key.sign(&[0xBB; 32]).unwrap();
        test::hash_data_and_expect(
            &signature,
            "ded81c057368b9a27a54505b38c09b3278ab9630da5fcb88e810f5433001427a",
        );
    }

    #[test]
    fn generated_header_and_metadata() {
        let key = Key::try_new(&test::TEST_PEM, test::TEST_METADATA).expect("new key");
        assert_eq!(key.metadata_bytes, test::TEST_METADATA);
        test::hash_data_and_expect(
            &key.generate_key_header(),
            "aac7f1dea707ee029aa5f6d29337399454aa37d1d403a5dd743c1e4c4f6efae2",
        );
    }
}
