Add CIA header (nw)

This commit is contained in:
Matt Nadareski
2021-07-22 22:36:05 -07:00
parent 012787a5b1
commit ef5a01edf7
4 changed files with 258 additions and 0 deletions

80
NDecrypt/N3DS/CIATool.cs Normal file
View File

@@ -0,0 +1,80 @@
using System;
using System.IO;
using NDecrypt.N3DS.Headers;
namespace NDecrypt.N3DS
{
// https://www.3dbrew.org/wiki/CIA
internal class CIATool : ITool
{
/// <summary>
/// Name of the input CIA file
/// </summary>
private readonly string filename;
/// <summary>
/// Flag to detrmine if development keys should be used
/// </summary>
private readonly bool development;
/// <summary>
/// Flag to determine if encrypting or decrypting
/// </summary>
private readonly bool encrypt;
/// <summary>
/// Flag to determine if forcing operations
/// </summary>
private readonly bool force;
public CIATool(string filename, bool development, bool encrypt, bool force)
{
this.filename = filename;
this.development = development;
this.encrypt = encrypt;
this.force = force;
}
#region Common Methods
/// <summary>
/// Process an input file given the input values
/// </summary>
public bool ProcessFile()
{
// Ensure the constants are all set
Constants.Init();
if (Constants.IsReady != true)
{
Console.WriteLine("Could not read keys from keys.bin. Please make sure the file exists and try again.");
return false;
}
try
{
// Open the read and write on the same file for inplace processing
using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
using (BinaryWriter writer = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)))
{
CIAHeader header = CIAHeader.Read(reader);
if (header == null)
{
Console.WriteLine("Error: Not a 3DS Rom!");
return false;
}
// TODO: Implement CIA encrypt/decrypt
return false;
}
}
catch
{
Console.WriteLine($"An error has occurred. {filename} may be corrupted if it was partially processed.");
Console.WriteLine("Please check that the file was a valid 3DS or New 3DS file and try again.");
return false;
}
}
#endregion
}
}

View File

@@ -0,0 +1,114 @@
using System.IO;
namespace NDecrypt.N3DS.Headers
{
internal class CIAHeader
{
/// <summary>
/// Archive header size, usually 0x2020 bytes
/// </summary>
public uint HeaderSize { get; private set; }
/// <summary>
/// Type
/// </summary>
public ushort Type { get; private set; }
/// <summary>
/// Version
/// </summary>
public ushort Version { get; private set; }
/// <summary>
/// Certificate chain size
/// </summary>
public int CertificateChainSize { get; private set; }
/// <summary>
/// Ticket size
/// </summary>
public int TicketSize { get; private set; }
/// <summary>
/// TMD file size
/// </summary>
public int TMDFileSize { get; private set; }
/// <summary>
/// Meta size (0 if no Meta data is present)
/// </summary>
public int MetaSize { get; private set; }
/// <summary>
/// Content size
/// </summary>
public long ContentSize { get; private set; }
/// <summary>
/// Content Index
/// </summary>
public byte[] ContentIndex { get; private set; }
/// <summary>
/// Certificate chain
/// </summary>
public byte[] CertificateChain { get; set; }
/// <summary>
/// Ticket
/// </summary>
public byte[] Ticket { get; set; }
/// <summary>
/// TMD file data
/// </summary>
public byte[] TMDFileData { get; set; }
/// <summary>
/// Content file data
/// </summary>
public byte[] ContentFileData { get; set; }
/// <summary>
/// Meta file data (Not a necessary component)
/// </summary>
public MetaFile MetaFileData { get; set; }
/// <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.ReadUInt32();
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);
header.CertificateChain = reader.ReadBytes(header.CertificateChainSize);
header.Ticket = reader.ReadBytes(header.TicketSize);
header.TMDFileData = reader.ReadBytes(header.TMDFileSize);
header.ContentFileData = reader.ReadBytes((int)header.ContentSize);
if (header.MetaSize > 0)
header.MetaFileData = MetaFile.Read(reader);
return header;
}
catch
{
return null;
}
}
}
}

View File

@@ -0,0 +1,57 @@
using System.IO;
namespace NDecrypt.N3DS.Headers
{
internal class MetaFile
{
/// <summary>
/// Title ID dependency list - Taken from the application's ExHeader
/// </summary>
public byte[] TitleIDDependencyList { get; private set; }
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1 { get; private set; }
/// <summary>
/// Core Version
/// </summary>
public uint CoreVersion { get; private set; }
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved2 { get; private set; }
/// <summary>
/// Icon Data(.ICN) - Taken from the application's ExeFS
/// </summary>
public byte[] IconData { get; private set; }
/// <summary>
/// Read from a stream and get the Metafile data, if possible
/// </summary>
/// <param name="reader">BinaryReader representing the input stream</param>
/// <returns>Metafile data object, null on error</returns>
public static MetaFile Read(BinaryReader reader)
{
MetaFile metaFile = new MetaFile();
try
{
metaFile.TitleIDDependencyList = reader.ReadBytes(0x180);
metaFile.Reserved1 = reader.ReadBytes(0x180);
metaFile.CoreVersion = reader.ReadUInt32();
metaFile.Reserved2 = reader.ReadBytes(0xFC);
metaFile.IconData = reader.ReadBytes(0x36C0);
return metaFile;
}
catch
{
return null;
}
}
}
}

View File

@@ -18,6 +18,7 @@ namespace NDecrypt
iQueDS,
N3DS,
iQue3DS,
N3DSCIA,
}
public static void Main(string[] args)
@@ -139,6 +140,9 @@ More than one path can be specified at a time.");
case FileType.N3DS:
Console.WriteLine("File recognized as Nintendo 3DS");
return new ThreeDSTool(filename, development, encrypt, force);
// case FileType.N3DSCIA:
// Console.WriteLine("File recognized as Nintendo 3DS");
// return new CIATool(filename, development, encrypt, force);
case FileType.NULL:
default:
Console.WriteLine($"Unrecognized file format for {filename}. Expected *.nds, *.srl, *.dsi, *.3ds");
@@ -165,6 +169,9 @@ More than one path can be specified at a time.");
else if (filename.EndsWith(".3ds", StringComparison.OrdinalIgnoreCase))
return FileType.N3DS;
else if (filename.EndsWith(".cia", StringComparison.OrdinalIgnoreCase))
return FileType.N3DSCIA;
return FileType.NULL;
}