diff --git a/file.go b/file.go index 6c27ee7..9fcacd4 100644 --- a/file.go +++ b/file.go @@ -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[:]) @@ -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 { diff --git a/wad.go b/wad.go index c8e29d9..2b944d5 100644 --- a/wad.go +++ b/wad.go @@ -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 { @@ -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)