wiiqt6/WiiQt/tiktmd.h
giantpune@gmail.com 92f2500c08 * sort titles in nandBinChecker
* use unsigned int since HBC's TID wont fit in a signed 32 bit int
* add key index fixing in the ticket class

git-svn-id: http://wiiqt.googlecode.com/svn/trunk@50 389f4c8b-5dfe-645f-db0e-df882bc27289
2011-01-13 16:43:49 +00:00

255 lines
6.1 KiB
C++

#ifndef TIKTMD_H
#define TIKTMD_H
#include "includes.h"
#define ES_SIG_RSA4096 0x10000
#define ES_SIG_RSA2048 0x10001
#define ES_SIG_ECDSA 0x10002
typedef quint32 sigtype;
typedef sigtype sig_header;
typedef sig_header signed_blob;
typedef quint8 sha1[20];
typedef quint8 aeskey[16];
typedef struct _sig_rsa2048 {
sigtype type;
quint8 sig[256];
quint8 fill[60];
} __attribute__((packed)) sig_rsa2048;
typedef struct _sig_rsa4096 {
sigtype type;
quint8 sig[512];
quint8 fill[60];
} __attribute__((packed)) sig_rsa4096;
typedef struct _sig_ecdsa {
sigtype type;
quint8 sig[60];
quint8 fill[64];
} __attribute__((packed)) sig_ecdsa;
typedef char sig_issuer[0x40];
typedef struct _tiklimit {
quint32 tag;
quint32 value;
} __attribute__((packed)) tiklimit;
typedef struct _tik {
sig_issuer issuer;
quint8 fill[63]; //TODO: not really fill
aeskey cipher_title_key;
quint8 fill2;
quint64 ticketid;
quint32 devicetype;
quint64 titleid;
quint16 access_mask;
quint8 reserved[0x3c];
quint8 cidx_mask[0x40];
quint16 padding;
tiklimit limits[8];
} __attribute__((packed)) tik;
typedef struct _tmd_content {
quint32 cid;
quint16 index;
quint16 type;
quint64 size;
sha1 hash;
} __attribute__((packed)) tmd_content;
typedef struct _tmd {
sig_issuer issuer; //0x140
quint8 version; //0x180
quint8 ca_crl_version; //0x181
quint8 signer_crl_version; //0x182
quint8 fill2; //0x183
quint64 sys_version; //0x184
quint64 title_id; //0x18c
quint32 title_type; //0x194
quint16 group_id; //0x198
quint16 zero; //0x19a
quint16 region; //0x19c
quint8 ratings[16]; //0x19e
quint8 reserved[12]; //0x1ae
quint8 ipc_mask[12];
quint8 reserved2[18];
quint32 access_rights;
quint16 title_version;
quint16 num_contents;
quint16 boot_index;
quint16 fill3;
// content records follow
// C99 flexible array
tmd_content contents[];
} __attribute__((packed)) tmd;
/*
typedef struct _tmd_view_content
{
quint32 cid;
quint16 index;
quint16 type;
quint64 size;
} __attribute__((packed)) tmd_view_content;
typedef struct _cert_header {
sig_issuer issuer;
quint32 cert_type;
char cert_name[64];
quint32 cert_id; //???
} __attribute__((packed)) cert_header;
typedef struct _cert_rsa2048 {
sig_issuer issuer;
quint32 cert_type;
char cert_name[64];
quint32 cert_id;
quint8 modulus[256];
quint32 exponent;
quint8 pad[0x34];
} __attribute__((packed)) cert_rsa2048;
typedef struct _cert_rsa4096 {
sig_issuer issuer;
quint32 cert_type;
char cert_name[64];
quint32 cert_id;
quint8 modulus[512];
quint32 exponent;
quint8 pad[0x34];
} __attribute__((packed)) cert_rsa4096;
typedef struct _cert_ecdsa {
sig_issuer issuer;
quint32 cert_type;
char cert_name[64];
quint32 cert_id; // ng key id
quint8 r[30];
quint8 s[30];
quint8 pad[0x3c];
} __attribute__((packed)) cert_ecdsa;
*/
//just a quick class to try to keep the rest of the code from getting full of the same shit over and over
class Ticket
{
public:
Ticket( const QByteArray &stuff = QByteArray(), bool fixKeyIndex = true );
//expose the tik data to the rest of the code so it cas read directly from the p_tmd instead of having to add a function to access all the data
//the pointer should be good until "data" is changed
const tik *payload(){ return p_tik; }
quint64 Tid();
bool SetTid( quint64 tid );
QByteArray DecryptedKey();
quint32 SignedSize();
bool FakeSign();
//get the ticket data
const QByteArray Data(){ return data; }
private:
quint32 payLoadOffset;
//let data hold the entire tik data
QByteArray data;
QByteArray decKey;
//point the p_tik to the spot in "data" we want
void SetPointer();
//this is just a pointer to the actual good stuff in "data".
//whenever data is changes, this pointer will become invalid and needs to be reset
tik *p_tik;
};
class Tmd
{
public:
Tmd( const QByteArray &stuff = QByteArray() );
//expose the tmd data to the rest of the code so it cas read directly from the p_tmd instead of having to add a function to access all the data
//the pointer should be good until "data" is changed
const tmd *payload(){ return p_tmd; }
//get a string containing the u32 of cid i
QString Cid( quint16 i );
//get a btyearray with the hosh of the given conten
QByteArray Hash( quint16 i );
//returned in host endian
quint64 Size( quint16 i );
quint16 Type( quint16 i );
quint16 BootIndex( quint16 i );
quint64 Tid();
quint64 IOS();
quint16 Gid();
quint32 AccessFlags();
//gets the number of contents
quint16 Count();
//title version
quint16 Version();
//functions to edit the TMD
//you probably want to call FakeSign() after using these
bool SetTid( quint64 tid );
bool SetVersion( quint16 v );
bool SetType( quint16 i, quint16 type );
bool SetSize( quint16 i, quint32 size );
bool SetHash( quint16 i, const QByteArray &hash );
bool SetIOS( quint64 ios );
bool SetAhb( bool remove = true );
bool SetDiskAccess( bool allow = true );
bool FakeSign();
//returns a qbytearray containing the tmd, from the rsa signature through the last content
const QByteArray Data(){ return data; }
//print some tmd info to qDebug()
void Dbg();
quint32 SignedSize();
private:
quint32 payLoadOffset;
//let data hold the entire tmd data
QByteArray data;
//point the p_tmd to the spot in "data" we want
void SetPointer();
//this is just a pointer to the actual good stuff in "data".
//whenever data is changed, this pointer will become invalid and needs to be reset
tmd *p_tmd;
};
enum
{
ERROR_SUCCESS = 0,
ERROR_SIG_TYPE,
ERROR_SUB_TYPE,
ERROR_RSA_FAKESIGNED,
ERROR_RSA_HASH,
ERROR_RSA_TYPE_UNKNOWN,
ERROR_RSA_TYPE_MISMATCH,
ERROR_CERT_NOT_FOUND,
ERROR_COUNT
};
//checks the signatures in a tmd/ticket
//returns 1 of the above enums
int check_cert_chain( const QByteArray &data );
#endif // TIKTMD_H