use error::Error;
use raw;
use std::fmt;
use std::time::{SystemTime, Duration, UNIX_EPOCH};
#[derive(Debug)]
pub struct Certificate {
size: u32,
time_date: SystemTime,
title_id: u32,
title_name: String,
alt_title_ids: [u32; 16],
allowed_media: MediaTypes,
game_region: GameRegion,
game_ratings: u32, disk_number: u32,
version: u32,
lan_key: Key,
signature_key: Key,
alt_signature_keys: [Key; 16],
}
impl Certificate {
pub(crate) fn from_raw(raw: &raw::Certificate) -> Result<Self, Error> {
Ok(Self {
size: raw.size,
time_date: UNIX_EPOCH + Duration::from_secs(raw.time_date.into()),
title_id: raw.title_id,
title_name: {
let s = String::from_utf16_lossy(&raw.title_name.0);
s.trim_right_matches('\0').to_string()
},
alt_title_ids: raw.alt_title_ids,
allowed_media: {
let flags = MediaTypes::from_bits_truncate(raw.allowed_media);
if flags.bits() != raw.allowed_media {
warn!("unknown media type flags: known flags: {:#X}, raw flags: {:#X}", flags.bits(), raw.allowed_media);
}
flags
},
game_region: {
let flags = GameRegion::from_bits_truncate(raw.game_region);
if flags.bits() != raw.game_region {
warn!("unknown game region flags: known flags: {:#X}, raw flags: {:#X}", flags.bits(), raw.game_region);
}
flags
},
game_ratings: raw.game_ratings,
disk_number: raw.disk_number,
version: raw.version,
lan_key: Key(raw.lan_key),
signature_key: Key(raw.signature_key),
alt_signature_keys: {
let mut keys = [Key([0; 16]); 16];
for (dest, src) in keys.iter_mut().zip(raw.alt_signature_keys.iter()) {
*dest = Key(*src);
}
keys
}
})
}
pub fn creation_time(&self) -> &SystemTime {
&self.time_date
}
pub fn title_name(&self) -> &str {
&self.title_name
}
pub fn title_id(&self) -> u32 {
self.title_id
}
pub fn alt_title_ids(&self) -> &[u32; 16] {
&self.alt_title_ids
}
pub fn allowed_media(&self) -> &MediaTypes {
&self.allowed_media
}
pub fn game_region(&self) -> &GameRegion {
&self.game_region
}
pub fn disk_number(&self) -> u32 {
self.disk_number
}
pub fn version(&self) -> u32 {
self.version
}
pub fn lan_key(&self) -> &Key {
&self.lan_key
}
pub fn signature_key(&self) -> &Key {
&self.signature_key
}
pub fn alt_signature_keys(&self) -> &[Key; 16] {
&self.alt_signature_keys
}
}
bitflags! {
pub struct MediaTypes: u32 {
const HARD_DISK = 0x00000001;
const DVD_X2 = 0x00000002;
const DVD_CD = 0x00000004;
const CD = 0x00000008;
const DVD_5_RO = 0x00000010;
const DVD_9_RO = 0x00000020;
const DVD_5_RW = 0x00000040;
const DVD_9_RW = 0x00000080;
const DONGLE = 0x00000100;
const MEDIA_BOARD = 0x00000200;
const NONSECURE_HARD_DISK = 0x40000000;
const NONSECURE_MODE = 0x80000000;
}
}
bitflags! {
pub struct GameRegion: u32 {
const NA = 0x00000001;
const JAPAN = 0x00000002;
const REST_OF_WORLD = 0x00000004;
const MANUFACTURING = 0x80000000;
}
}
#[derive(Copy, Clone)]
pub struct Key(pub [u8; 16]);
impl fmt::Debug for Key {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x")?;
for b in &self.0 {
write!(f, "{:02X}", b)?;
}
Ok(())
}
}