use byteorder::{LittleEndian, ReadBytesExt};
use rsa::{BigUint, RSAPublicKey};
use std::{
convert::TryFrom,
io::{Cursor, Read},
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("Key blob length is to small: {0}")]
KeyBlobLength(usize),
#[error("Bad digest padding value: {0}")]
DigestPadding(u32),
#[error("Modulus read failed")]
Modulus,
#[error("Public exponent read failed")]
PublicExponent,
#[error("Private exponent read failed")]
PrivateExponent,
#[error("Failed to create RSAPublicKey")]
RSAPublicKey(#[from] rsa::errors::Error),
}
pub enum DigestPadAlgo {
RsaDigestPaddingNone = 0,
RsaPkcs115Sha2_256 = 1,
RsaPssSha2_256 = 2,
}
impl TryFrom<u32> for DigestPadAlgo {
type Error = Error;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(DigestPadAlgo::RsaDigestPaddingNone),
1 => Ok(DigestPadAlgo::RsaPkcs115Sha2_256),
2 => Ok(DigestPadAlgo::RsaPssSha2_256),
_ => Err(Error::DigestPadding(value)),
}
}
}
// Note (iegor.s): values are copied from qualcomm qseecom module
const RSA_KEY_SIZE_MAX: usize = 512 + 16;
const RSA_IV_LENGTH: usize = 16;
const RSA_HMAC_LENGTH: usize = 32;
const RSA_KEY_BLOB_LENGHT: usize = 1656;
pub fn parse_key_blob(buf: &[u8]) -> Result<RSAPublicKey, Error> {
// Key blobs are always exactly RSA_KEY_BLOB_LENGHT long, but
// let's tolerate extra.
if buf.len() < RSA_KEY_BLOB_LENGHT {
return Err(Error::KeyBlobLength(buf.len()));
}
let mut data = Cursor::new(buf);
let _ = data
.read_u32::<LittleEndian>()
.expect("expected magic number");
let _ = data
.read_u32::<LittleEndian>()
.expect("expected version number");
let digest_padding = data
.read_u32::<LittleEndian>()
.expect("expected digest padding");
let _ = DigestPadAlgo::try_from(digest_padding)?;
let mut modulus = vec![0u8; RSA_KEY_SIZE_MAX];
data.read_exact(modulus.as_mut_slice())
.expect("expected modulus");
let modulus_len = data
.read_u32::<LittleEndian>()
.expect("expected modulus length");
if modulus_len > RSA_KEY_SIZE_MAX as u32 {
return Err(Error::Modulus);
}
modulus.truncate(modulus_len as usize);
let mut public_exponent = vec![0u8; RSA_KEY_SIZE_MAX];
data.read_exact(public_exponent.as_mut_slice())
.expect("expected public exponent");
let public_exponent_len = data
.read_u32::<LittleEndian>()
.expect("expected public exponent length");
if public_exponent_len > RSA_KEY_SIZE_MAX as u32 {
return Err(Error::PublicExponent);
}
public_exponent.truncate(public_exponent_len as usize);
let mut iv = vec![0u8; RSA_IV_LENGTH];
data.read_exact(iv.as_mut_slice())
.expect("expected initial vector");
let mut private_exponent = vec![0u8; RSA_KEY_SIZE_MAX];
data.read_exact(private_exponent.as_mut_slice())
.expect("expected private exponent");
let private_exponent_len = data
.read_u32::<LittleEndian>()
.expect("expected private exponent length");
if private_exponent_len > RSA_KEY_SIZE_MAX as u32 {
return Err(Error::PrivateExponent);
}
private_exponent.truncate(private_exponent_len as usize);
let mut hmac_length = vec![0u8; RSA_HMAC_LENGTH];
data.read_exact(hmac_length.as_mut_slice())
.expect("expected hmac length");
RSAPublicKey::new(
BigUint::from_bytes_be(modulus.as_slice()),
BigUint::from_bytes_be(public_exponent.as_slice()),
)
.map_err(Error::RSAPublicKey)
}
#[cfg(test)]
mod tests {
use hex_literal::hex;
#[test]
fn verify_parse() {
const BLOB: &[u8] =
&hex!("424B4D4B0000000001000000C12D21F0297EC0E5AE3EB8FC01B0AE5B0723AEBECD6E9DEB9EC3996D6EEA504DC39DE85A58D74B8A3554F0A52AF1F7F7888F806E9CD1C610FB51BB45A7BC3795C5AD9AC439A706A0DFF0B54A5A3A3CEBF8387EC7485849308A954A55A50EEA14D0A71AA046C38D0E7925F5499F5CDFB798B47889FE215690C6C41F7FD0521579C25D258206D2B93D83F4AD307F14D13D77CC36D759BD63A1DF33AADC4AF73062675BC6E63127722C6D60C2C11226D1CBAFFF4E7B5C58460FF58B50A20B78D59BDB270F867CA157A67E388F5FBB8991EFE937EB1C29043D5A10CE7FB5481AFCBC7E5B07B92470C69B9F97446B9F2268A52FBA033EE3615B08B9476D9C2FB210C9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000008B9C0BB28187EF4F195FD1F060FBE8EE3AE16C2FF6D3EFE52BB2A68814E1150F40348B7F13B02097068356E6FC661EC3D1208EA51D7EF3424F2324B71A76179F107976680752EA5050042F778A678C5C20E8250FF872CBBF9D804EA95CEDB7A95DF633B854E908568863C45987F0D95C818D21AB02BFE72F66C74599BB28073D78DF92A24004A95481FCBA4BF82017DD67294BB6922916D1DD73FF73D5928DC065E75C3C25B0E775D517829B5A1914312ADD7BB52CD43CABF74DC0A8696C83C96746F177872E6CA3687CAC1A877E115BAB421FC6DF13B627F8DB57957ADEBE4218E9D36C672C5F895CCD2CC8F558CFCF07D8B2D7AC23DC21A31FDC2E77B02CD1FA8AB3002E30F03F8E3C2FEB227B157D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100002CE90652D0E86E40FAFCDC1D6CD40DC058659F612DF74195CDA26DCC21655281");
super::parse_key_blob(BLOB).expect("pre-generated keyblob should parse");
}
}