Skip to content

Commit

Permalink
Properly align decrypted contents
Browse files Browse the repository at this point in the history
We previously did not properly account for the needed length to read. Nintendo supplies encrypted contents aligned to 16. We read that much, decrypt, and then remove the additional padding.
  • Loading branch information
spotlightishere committed Sep 21, 2020
1 parent d3970c3 commit 5bb575c
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 5 deletions.
16 changes: 14 additions & 2 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,16 @@ func readData(data []byte, contents []ContentRecord, titleKey [16]byte) ([]WADFi
for _, content := range contents {
// It's okay to cast this from a uint64 as the WAD file format
// cannot exceed the maximum uint32 value within the data section.
encryptedData := r.getRange(uint32(content.Size))
// We read aligned to 16 bytes as the encrypted data is stored with padding.
// Not all contents meet the expected 16-byte boundary.
paddedSize := uint32(content.Size)
leftover := paddedSize % 16
if leftover != 0 {
paddedSize += 16 - leftover
}

// Read the padded amount as aligned to 64 bytes.
encryptedData := r.getRange(paddedSize)

// The title's decrypted key will be what we'll decrypt with.
block, err := aes.NewCipher(titleKey[:])
Expand All @@ -51,11 +60,14 @@ func readData(data []byte, contents []ContentRecord, titleKey [16]byte) ([]WADFi
blockMode := cipher.NewCBCDecrypter(block, iv)

// The resulting decrypted contents is the same size as the input, including padding.
decryptedData := make([]byte, content.Size)
decryptedData := make([]byte, paddedSize)

// ...and we're off!
blockMode.CryptBlocks(decryptedData, encryptedData)

// Trim off the excess padding once decrypted.
decryptedData = decryptedData[:content.Size]

// Ensure that the decrypted data matches the SHA-1 hash given in the contents list.
sha := sha1.Sum(decryptedData)
if bytes.Compare(sha[:], content.Hash[:]) != 0 {
Expand Down
5 changes: 2 additions & 3 deletions wad.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type WADHeader struct {
}

// getPadding returns the given size, padded to the nearest 0x40/64-byte boundary.
// This is useful as all WAD contents are padded to such.
// This is useful as many types of contents are padded to such.
func getPadding(size uint32) uint32 {
// Empty things aren't padded.
if size == 0 {
Expand Down Expand Up @@ -112,8 +112,7 @@ func LoadWAD(contents []byte) (*WAD, error) {
certificate := r.getRange(header.CertificateSize)
crl := r.getRange(header.CRLSize)

// We'll next
// Load a ticket from our contents into the struct.
// We'll next load a ticket from our contents into the struct.
var ticket Ticket
loadingBuf = r.getBuffer(header.TicketSize)
err = binary.Read(loadingBuf, binary.BigEndian, &ticket)
Expand Down

0 comments on commit 5bb575c

Please sign in to comment.