Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NCA extraction #34

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open

NCA extraction #34

wants to merge 10 commits into from

Conversation

roblabla
Copy link
Member

Parse and extract nca sections.

@todo
Copy link

todo bot commented Dec 27, 2018

Better format

linkle/src/format/nca.rs

Lines 141 to 151 in 935fed2

sdk_version: u32, // TODO: Better format
xts_key: AesXtsKey,
ctr_key: Aes128Key,
rights_id: Option<[u8; 0x10]>,
sections: [Option<SectionJson>; 4]
}
#[derive(Debug)]
pub struct Nca<R> {
stream: R,
json: NcaJson


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

Check if NCA is already decrypted

linkle/src/format/nca.rs

Lines 170 to 180 in 935fed2

// TODO: Check if NCA is already decrypted
let header_key = pki.header_key().as_ref().ok_or(Error::MissingKey("header_key", Backtrace::new()))?;
header_key.decrypt(&header[..0x400], &mut decrypted_header[..0x400], 0, 0x200)?;
let raw_nca = *RawNca::from_bytes(&decrypted_header).expect("RawNca to be of the right size");
match &raw_nca.magic {
b"NCA3" => {
header_key.decrypt(&header, &mut decrypted_header, 0, 0x200)?;
},
b"NCA2" => {


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

NCA: Verify header with RSA2048 PSS

We want to make sure the NCAs have a valid signature before decrypting. Maybe put it behind a flag that accepts invalidly signed NCAs?


linkle/src/format/nca.rs

Lines 206 to 216 in 935fed2

// TODO: NCA: Verify header with RSA2048 PSS
// BODY: We want to make sure the NCAs have a valid signature before
// BODY: decrypting. Maybe put it behind a flag that accepts invalidly
// BODY: signed NCAs?
// Crypto is stupid. First, we need to get the max of crypto_type and crypto_type2.
// Then, nintendo uses both 0 and 1 as master key 0, and then everything is shifted by one.
// So we sub by 1.
let master_key_revision = max(header.crypto_type2, header.crypto_type).saturating_sub(1);
// Handle Rights ID.


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

NCA0 => return

linkle/src/format/nca.rs

Lines 222 to 232 in 935fed2

// TODO: NCA0 => return
(
key_area_key.derive_xts_key(&header.encrypted_xts_key)?,
key_area_key.derive_key(&header.encrypted_ctr_key)?,
)
} else {
// TODO: Implement RightsID crypto.
unimplemented!("Rights ID");
};
// Parse sections


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

Implement RightsID crypto.

linkle/src/format/nca.rs

Lines 228 to 238 in 935fed2

// TODO: Implement RightsID crypto.
unimplemented!("Rights ID");
};
// Parse sections
let mut sections = [None, None, None, None];
for (idx, (section, fs)) in header.section_entries.iter().zip(header.fs_headers.iter()).enumerate() {
// Check if section is present
if section.media_start_offset != 0 {
if has_rights_id {
unimplemented!("Rights ID");


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

Store the SDK version in a more human readable format.

linkle/src/format/nca.rs

Lines 277 to 287 in 935fed2

// TODO: Store the SDK version in a more human readable format.
sdk_version: header.sdk_version,
xts_key: decrypted_keys.0,
ctr_key: decrypted_keys.1,
// TODO: Implement rights id.
rights_id: None,
sections: sections,
}
};
Ok(nca)


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

Implement rights id.

linkle/src/format/nca.rs

Lines 281 to 291 in 935fed2

// TODO: Implement rights id.
rights_id: None,
sections: sections,
}
};
Ok(nca)
}
}
impl<R: Read + TryClone + Seek> Nca<R> {


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

Nca::raw_section should reopen the file, not dup2 the handle.

linkle/src/format/nca.rs

Lines 294 to 304 in 935fed2

// TODO: Nca::raw_section should reopen the file, not dup2 the handle.
let mut stream = self.stream.try_clone()?;
stream.seek(std::io::SeekFrom::Start(section.start_offset()))?;
Ok(CryptoStream {
stream: ReadRange::new(stream, section.start_offset(), section.size()),
// Keep a 1-block large buffer of data in case of partial reads.
buffer: [0; 0x10],
state: CryptoStreamState {
ctr_key: self.json.ctr_key,
xts_key: self.json.xts_key,


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

Make VerificationStream actually verify the data it reads.

based on the hash table located with the help of the superblock. It will need a different implementation for PFS0 and RomFs (and maybe Bktr?).


linkle/src/format/nca.rs

Lines 457 to 467 in 935fed2

// TODO: Make VerificationStream actually verify the data it reads.
// BODY: VerificationStream should verify the body based on the hash table
// BODY: located with the help of the superblock. It will need a different
// BODY: implementation for PFS0 and RomFs (and maybe Bktr?).
pub struct VerificationStream<R> {
stream: R,
start_at: u64,
}
impl<R: Read + Seek> Read for VerificationStream<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

Figure out why this is necessary.

linkle/src/lib.rs

Lines 1 to 4 in 935fed2

// TODO: Figure out why this is necessary.
#[macro_use]
extern crate static_assertions;


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Dec 27, 2018

Document

linkle/src/utils.rs

Lines 5 to 15 in 935fed2

// TODO: Document
#[macro_export]
macro_rules! enum_with_val {
($(#[$meta:meta])* $vis:vis struct $ident:ident($ty:ty) {
$($variant:ident = $num:expr),* $(,)*
}) => {
$(#[$meta])*
#[derive(PartialEq, Eq)]
$vis struct $ident($ty);
impl $ident {
$(#[allow(non_upper_case_globals)] $vis const $variant: $ident = $ident($num);)*


This comment was generated by todo based on a TODO comment in 935fed2 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Jan 24, 2019

NCA0 => return

linkle/src/format/nca.rs

Lines 222 to 232 in 9ba46f8

// TODO: NCA0 => return
(
key_area_key.derive_xts_key(&header.encrypted_xts_key)?,
key_area_key.derive_key(&header.encrypted_ctr_key)?,
)
} else {
// TODO: Implement RightsID crypto.
unimplemented!("Rights ID");
};
// Parse sections


This comment was generated by todo based on a TODO comment in 9ba46f8 in #34. cc @roblabla.

@todo
Copy link

todo bot commented Jan 27, 2019

NCA0 => return

linkle/src/format/nca.rs

Lines 264 to 274 in 2d2206b

// TODO: NCA0 => return
(
key_area_key.derive_xts_key(&header.encrypted_xts_key)?,
key_area_key.derive_key(&header.encrypted_ctr_key)?,
)
} else {
// TODO: Implement RightsID crypto.
unimplemented!("Rights ID");
};
// Parse sections


This comment was generated by todo based on a TODO comment in 2d2206b in #34. cc @roblabla.

@todo
Copy link

todo bot commented Jan 27, 2019

Bubble up the error.

linkle/src/format/nca.rs

Lines 627 to 637 in 2d2206b

// TODO: Bubble up the error.
self.state.decrypt(&mut self.buffer).unwrap();
buf[from..].copy_from_slice(&self.buffer[..leftovers]);
self.state.offset += leftovers as u64;
}
Ok(previous_leftovers_written + read)
}
}
impl<W: Write + Seek> Write for CryptoStream<W> {


This comment was generated by todo based on a TODO comment in 2d2206b in #34. cc @roblabla.

@todo
Copy link

todo bot commented Jan 27, 2019

Bubble up the error.

linkle/src/format/nca.rs

Lines 649 to 659 in 2d2206b

// TODO: Bubble up the error.
self.state.encrypt(&mut self.buffer).unwrap();
self.stream.write_all(&self.buffer)?;
self.state.decrypt(&mut self.buffer).unwrap();
if to != 16 {
self.stream.seek(io::SeekFrom::Current(-16))?;
} else {
self.buffer = [0; 16];
}


This comment was generated by todo based on a TODO comment in 2d2206b in #34. cc @roblabla.

@todo
Copy link

todo bot commented Jan 27, 2019

Now, verify the buffer.

linkle/src/format/nca.rs

Lines 741 to 751 in 2d2206b

// TODO: Now, verify the buffer.
}
}
fn write_hash<W: Write + Seek>(section: &SectionJson, cur_off: u64, stream: &mut ReadRange<W>, block: &[u8]) -> io::Result<()> {
match section.fstype {
FsType::Pfs0 { hash_table_offset, .. } => {
let hash = Sha256::digest(block);
let hash_pos = hash_table_offset + 0x20 * (cur_off / 4096);
stream.as_inner_mut().seek(io::SeekFrom::Start(hash_pos)).unwrap();
stream.as_inner_mut().write_all(hash.as_slice()).unwrap();


This comment was generated by todo based on a TODO comment in 2d2206b in #34. cc @roblabla.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant