//
// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Software-only trait implementations using fake keys.

use kmr_common::{
    crypto,
    crypto::{Hkdf, Rng},
    Error,
};
use kmr_crypto_boring::{hmac::BoringHmac, rng::BoringRng};
use kmr_ta::device::RetrieveKeyMaterial;

/// Root key retrieval using hard-coded fake keys.
pub struct Keys;

impl RetrieveKeyMaterial for Keys {
    fn root_kek(&self, _context: &[u8]) -> Result<crypto::OpaqueOr<crypto::hmac::Key>, Error> {
        // Matches `MASTER_KEY` in system/keymaster/key_blob_utils/software_keyblobs.cpp
        Ok(crypto::hmac::Key::new([0; 16].to_vec()).into())
    }
    fn kak(&self) -> Result<crypto::OpaqueOr<crypto::aes::Key>, Error> {
        // Matches `kFakeKeyAgreementKey` in
        // system/keymaster/km_openssl/soft_keymaster_enforcement.cpp.
        Ok(crypto::aes::Key::Aes256([0; 32]).into())
    }
    fn unique_id_hbk(&self, _ckdf: &dyn crypto::Ckdf) -> Result<crypto::hmac::Key, Error> {
        // Matches value used in system/keymaster/contexts/pure_soft_keymaster_context.cpp.
        crypto::hmac::Key::new_from(b"MustBeRandomBits")
    }
}

/// Implementation of key derivation using a random fake key.
pub struct Derive {
    hbk: Vec<u8>,
}

impl Default for Derive {
    fn default() -> Self {
        // Use random data as an emulation of a hardware-backed key.
        let mut hbk = vec![0; 32];
        let mut rng = BoringRng;
        rng.fill_bytes(&mut hbk);
        Self { hbk }
    }
}

impl crate::rpc::DeriveBytes for Derive {
    fn derive_bytes(&self, context: &[u8], output_len: usize) -> Result<Vec<u8>, Error> {
        BoringHmac.hkdf(&[], &self.hbk, context, output_len)
    }
}

/// RPC artifact retrieval using software fake key.
pub type RpcArtifacts = crate::rpc::Artifacts<Derive>;
