/// <summary> /// Read from a stream and get a CIA header, if possible /// </summary> /// <param name="reader">BinaryReader representing the input stream</param> /// <returns>CIA header object, null on error</returns> public static CIAHeader Read(BinaryReader reader) { CIAHeader header = new CIAHeader(); try { header.HeaderSize = reader.ReadInt32(); header.Type = reader.ReadUInt16(); header.Version = reader.ReadUInt16(); header.CertificateChainSize = reader.ReadInt32(); header.TicketSize = reader.ReadInt32(); header.TMDFileSize = reader.ReadInt32(); header.MetaSize = reader.ReadInt32(); header.ContentSize = reader.ReadInt64(); header.ContentIndex = reader.ReadBytes(0x2000); if (reader.BaseStream.Position % 64 != 0) { reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current); } header.CertificateChain = new Certificate[3]; header.CertificateChain[0] = Certificate.Read(reader); // CA header.CertificateChain[1] = Certificate.Read(reader); // Ticket header.CertificateChain[2] = Certificate.Read(reader); // TMD if (reader.BaseStream.Position % 64 != 0) { reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current); } header.Ticket = Ticket.Read(reader, header.TicketSize); if (reader.BaseStream.Position % 64 != 0) { reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current); } header.TMDFileData = TitleMetadata.Read(reader, header.TMDFileSize); if (reader.BaseStream.Position % 64 != 0) { reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current); } long startingPosition = reader.BaseStream.Position; List <NCCHHeader> headers = new List <NCCHHeader>(); while (reader.BaseStream.Position < startingPosition + header.ContentSize) { long initPosition = reader.BaseStream.Position; NCCHHeader ncchHeader = NCCHHeader.Read(reader, readSignature: true); if (ncchHeader == null) { break; } headers.Add(ncchHeader); reader.BaseStream.Seek(initPosition + ncchHeader.ContentSizeInMediaUnits * 0x200, SeekOrigin.Begin); } header.Partitions = headers.ToArray(); if (header.MetaSize > 0) { header.MetaFileData = MetaFile.Read(reader); } return(header); } catch { return(null); } }
/// <summary> /// Read from a stream and get ticket metadata, if possible /// </summary> /// <param name="reader">BinaryReader representing the input stream</param> /// <param name="metadataSize">Metadata size from the header</param> /// <returns>Title metadata object, null on error</returns> public static TitleMetadata Read(BinaryReader reader, int metadataSize) { TitleMetadata tm = new TitleMetadata(); try { long startingPosition = reader.BaseStream.Position; tm.SignatureType = (SignatureType)reader.ReadUInt32(); switch (tm.SignatureType) { case SignatureType.RSA_4096_SHA1: case SignatureType.RSA_4096_SHA256: tm.SignatureSize = 0x200; tm.PaddingSize = 0x3C; break; case SignatureType.RSA_2048_SHA1: case SignatureType.RSA_2048_SHA256: tm.SignatureSize = 0x100; tm.PaddingSize = 0x3C; break; case SignatureType.ECDSA_SHA1: case SignatureType.ECDSA_SHA256: tm.SignatureSize = 0x03C; tm.PaddingSize = 0x40; break; } tm.Signature = reader.ReadBytes(tm.SignatureSize); reader.ReadBytes(tm.PaddingSize); // Padding tm.SignatureIssuer = reader.ReadBytes(0x40); tm.Version = reader.ReadByte(); tm.CaCrlVersion = reader.ReadByte(); tm.SignerCrlVersion = reader.ReadByte(); tm.Reserved1 = reader.ReadByte(); tm.SystemVersion = reader.ReadUInt64(); tm.TitleID = reader.ReadUInt64(); tm.TitleType = reader.ReadUInt32(); tm.GroupID = reader.ReadUInt16(); tm.SaveDataSize = reader.ReadUInt32(); tm.SRLPrivateSaveDataSize = reader.ReadUInt32(); tm.Reserved2 = reader.ReadUInt32(); tm.SRLFlag = reader.ReadByte(); tm.Reserved3 = reader.ReadBytes(0x31); tm.AccessRights = reader.ReadUInt32(); tm.TitleVersion = reader.ReadUInt16(); tm.ContentCount = BitConverter.ToUInt16(reader.ReadBytes(2).Reverse().ToArray(), 0); tm.BootContent = reader.ReadUInt16(); tm.Padding = reader.ReadUInt16(); tm.SHA256HashContentInfoRecords = reader.ReadBytes(0x20); tm.ContentInfoRecords = new ContentInfoRecord[64]; for (int i = 0; i < 64; i++) { tm.ContentInfoRecords[i] = ContentInfoRecord.Read(reader); } tm.ContentChunkRecords = new ContentChunkRecord[tm.ContentCount]; for (int i = 0; i < tm.ContentCount; i++) { tm.ContentChunkRecords[i] = ContentChunkRecord.Read(reader); } if (metadataSize > (reader.BaseStream.Position - startingPosition) + (2 * 0x200)) { tm.CertificateChain = new Certificate[2]; tm.CertificateChain[0] = Certificate.Read(reader); // TMD tm.CertificateChain[1] = Certificate.Read(reader); // CA } return(tm); } catch { return(null); } }