Added neimod's ctrtool

Will be base code for improvments
This commit is contained in:
3DSGuy 2014-04-14 09:39:21 +08:00
commit 87681b8bc5
63 changed files with 22243 additions and 0 deletions

22
.gitattributes vendored Normal file
View File

@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

215
.gitignore vendored Normal file
View File

@ -0,0 +1,215 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
*.pubxml
# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist/
build/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg

15
ctrtool/Makefile Normal file
View File

@ -0,0 +1,15 @@
OBJS = keyset.o main.o ctr.o ncsd.o cia.o tik.o tmd.o filepath.o lzss.o exheader.o exefs.o ncch.o utils.o settings.o firm.o cwav.o stream.o romfs.o ivfc.o
POLAR_OBJS = polarssl/aes.o polarssl/bignum.o polarssl/rsa.o polarssl/sha2.o
TINYXML_OBJS = tinyxml/tinystr.o tinyxml/tinyxml.o tinyxml/tinyxmlerror.o tinyxml/tinyxmlparser.o
LIBS = -lstdc++
CXXFLAGS = -I.
CFLAGS = -Wall -I.
OUTPUT = ctrtool
CC = gcc
main: $(OBJS) $(POLAR_OBJS) $(TINYXML_OBJS)
g++ -o $(OUTPUT) $(LIBS) $(OBJS) $(POLAR_OBJS) $(TINYXML_OBJS)
clean:
rm -rf $(OUTPUT) $(OBJS) $(POLAR_OBJS) $(TINYXML_OBJS)

295
ctrtool/cia.c Normal file
View File

@ -0,0 +1,295 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "utils.h"
#include "cia.h"
void cia_init(cia_context* ctx)
{
memset(ctx, 0, sizeof(cia_context));
tik_init(&ctx->tik);
tmd_init(&ctx->tmd);
}
void cia_set_file(cia_context* ctx, FILE* file)
{
ctx->file = file;
}
void cia_set_offset(cia_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void cia_set_size(cia_context* ctx, u32 size)
{
ctx->size = size;
}
void cia_set_usersettings(cia_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void cia_save(cia_context* ctx, u32 type, u32 flags)
{
u32 offset;
u32 size;
filepath* path = 0;
ctr_tmd_body *body;
ctr_tmd_contentchunk *chunk;
int i;
char tmpname[255];
switch(type)
{
case CIATYPE_CERTS:
offset = ctx->offsetcerts;
size = ctx->sizecert;
path = settings_get_certs_path(ctx->usersettings);
break;
case CIATYPE_TIK:
offset = ctx->offsettik;
size = ctx->sizetik;
path = settings_get_tik_path(ctx->usersettings);
break;
case CIATYPE_TMD:
offset = ctx->offsettmd;
size = ctx->sizetmd;
path = settings_get_tmd_path(ctx->usersettings);
break;
case CIATYPE_CONTENT:
offset = ctx->offsetcontent;
size = ctx->sizecontent;
path = settings_get_content_path(ctx->usersettings);
break;
case CIATYPE_META:
offset = ctx->offsetmeta;
size = ctx->sizemeta;
path = settings_get_meta_path(ctx->usersettings);;
break;
default:
fprintf(stderr, "Error, unknown CIA type specified\n");
return;
break;
}
if (path == 0 || path->valid == 0)
return;
switch(type)
{
case CIATYPE_CERTS: fprintf(stdout, "Saving certs to %s\n", path->pathname); break;
case CIATYPE_TIK: fprintf(stdout, "Saving tik to %s\n", path->pathname); break;
case CIATYPE_TMD: fprintf(stdout, "Saving tmd to %s\n", path->pathname); break;
case CIATYPE_CONTENT:
body = tmd_get_body(&ctx->tmd);
chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS));
for(i = 0; i < getbe16(body->contentcount); i++) {
sprintf(tmpname, "%s.%04x.%08x", path->pathname, getbe16(chunk->index), getbe32(chunk->id));
fprintf(stdout, "Saving content #%04x to %s\n", getbe16(chunk->index), tmpname);
ctx->iv[0] = (getbe16(chunk->index) >> 8) & 0xff;
ctx->iv[1] = getbe16(chunk->index) & 0xff;
ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv);
cia_save_blob(ctx, tmpname, offset, getbe64(chunk->size) & 0xffffffff, 1);
offset += getbe64(chunk->size) & 0xffffffff;
chunk++;
}
memset(ctx->iv, 0, 16);
return;
break;
case CIATYPE_META: fprintf(stdout, "Saving meta to %s\n", path->pathname); break;
}
cia_save_blob(ctx, path->pathname, offset, size, 0);
}
void cia_save_blob(cia_context *ctx, char *out_path, u32 offset, u32 size, int do_cbc)
{
FILE *fout = 0;
u8 buffer[16*1024];
fseek(ctx->file, ctx->offset + offset, SEEK_SET);
fout = fopen(out_path, "wb");
if (fout == NULL)
{
fprintf(stdout, "Error opening out file %s\n", out_path);
goto clean;
}
while(size)
{
u32 max = sizeof(buffer);
if (max > size)
max = size;
if (max != fread(buffer, 1, max, ctx->file))
{
fprintf(stdout, "Error reading file\n");
goto clean;
}
if (do_cbc == 1)
ctr_decrypt_cbc(&ctx->aes, buffer, buffer, max);
if (max != fwrite(buffer, 1, max, fout))
{
fprintf(stdout, "Error writing file\n");
goto clean;
}
size -= max;
}
clean:
if (fout)
fclose(fout);
}
void cia_process(cia_context* ctx, u32 actions)
{
fseek(ctx->file, 0, SEEK_SET);
if (fread(&ctx->header, 1, sizeof(ctr_ciaheader), ctx->file) != sizeof(ctr_ciaheader))
{
fprintf(stderr, "Error reading CIA header\n");
goto clean;
}
ctx->sizeheader = getle32(ctx->header.headersize);
ctx->sizecert = getle32(ctx->header.certsize);
ctx->sizetik = getle32(ctx->header.ticketsize);
ctx->sizetmd = getle32(ctx->header.tmdsize);
ctx->sizecontent = (u32)getle64(ctx->header.contentsize);
ctx->sizemeta = getle32(ctx->header.metasize);
ctx->offsetcerts = align(ctx->sizeheader, 64);
ctx->offsettik = align(ctx->offsetcerts + ctx->sizecert, 64);
ctx->offsettmd = align(ctx->offsettik + ctx->sizetik, 64);
ctx->offsetcontent = align(ctx->offsettmd + ctx->sizetmd, 64);
ctx->offsetmeta = align(ctx->offsetcontent + ctx->sizecontent, 64);
if (actions & InfoFlag)
cia_print(ctx);
tik_set_file(&ctx->tik, ctx->file);
tik_set_offset(&ctx->tik, ctx->offsettik);
tik_set_size(&ctx->tik, ctx->sizetik);
tik_set_usersettings(&ctx->tik, ctx->usersettings);
tik_process(&ctx->tik, actions);
memset(ctx->iv, 0, 16);
if (settings_get_common_key(ctx->usersettings))
tik_get_decrypted_titlekey(&ctx->tik, ctx->titlekey);
tmd_set_file(&ctx->tmd, ctx->file);
tmd_set_offset(&ctx->tmd, ctx->offsettmd);
tmd_set_size(&ctx->tmd, ctx->sizetmd);
tmd_set_usersettings(&ctx->tmd, ctx->usersettings);
tmd_process(&ctx->tmd, actions);
if (actions & VerifyFlag)
{
cia_verify_contents(ctx);
}
if (actions & InfoFlag || actions & VerifyFlag)
tmd_print(&ctx->tmd);
if (actions & ExtractFlag)
{
cia_save(ctx, CIATYPE_CERTS, actions);
cia_save(ctx, CIATYPE_TMD, actions);
cia_save(ctx, CIATYPE_TIK, actions);
cia_save(ctx, CIATYPE_META, actions);
cia_save(ctx, CIATYPE_CONTENT, actions);
}
clean:
return;
}
void cia_verify_contents(cia_context *ctx)
{
ctr_tmd_body *body;
ctr_tmd_contentchunk *chunk;
u8 *verify_buf;
u32 content_size=0;
int i;
// verify TMD content hashes, requires decryption ..
body = tmd_get_body(&ctx->tmd);
chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS));
fseek(ctx->file, ctx->offset + ctx->offsetcontent, SEEK_SET);
for(i = 0; i < getbe16(body->contentcount); i++)
{
content_size = getbe64(chunk->size) & 0xffffffff;
ctx->iv[0] = (getbe16(chunk->index) >> 8) & 0xff;
ctx->iv[1] = getbe16(chunk->index) & 0xff;
ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv);
verify_buf = malloc(content_size);
fread(verify_buf, content_size, 1, ctx->file);
ctr_decrypt_cbc(&ctx->aes, verify_buf, verify_buf, content_size);
if (ctr_sha_256_verify(verify_buf, content_size, chunk->hash) == Good)
ctx->tmd.content_hash_stat[i] = 1;
else
ctx->tmd.content_hash_stat[i] = 2;
free(verify_buf);
chunk++;
}
}
void cia_print(cia_context* ctx)
{
ctr_ciaheader* header = &ctx->header;
fprintf(stdout, "Header size 0x%08x\n", getle32(header->headersize));
fprintf(stdout, "Type %04x\n", getle16(header->type));
fprintf(stdout, "Version %04x\n", getle16(header->version));
fprintf(stdout, "Certificates offset: 0x%08x\n", ctx->offsetcerts);
fprintf(stdout, "Certificates size: 0x%04x\n", ctx->sizecert);
fprintf(stdout, "Ticket offset: 0x%08x\n", ctx->offsettik);
fprintf(stdout, "Ticket size 0x%04x\n", ctx->sizetik);
fprintf(stdout, "TMD offset: 0x%08x\n", ctx->offsettmd);
fprintf(stdout, "TMD size: 0x%04x\n", ctx->sizetmd);
fprintf(stdout, "Meta offset: 0x%04x\n", ctx->offsetmeta);
fprintf(stdout, "Meta size: 0x%04x\n", ctx->sizemeta);
fprintf(stdout, "Content offset: 0x%08x\n", ctx->offsetcontent);
fprintf(stdout, "Content size: 0x%016llx\n", getle64(header->contentsize));
}

72
ctrtool/cia.h Normal file
View File

@ -0,0 +1,72 @@
#ifndef _CIA_H_
#define _CIA_H_
#include "types.h"
#include "filepath.h"
#include "tik.h"
#include "tmd.h"
#include "ctr.h"
#include "settings.h"
typedef enum
{
CIATYPE_CERTS,
CIATYPE_TMD,
CIATYPE_TIK,
CIATYPE_CONTENT,
CIATYPE_META,
} cia_types;
typedef struct
{
u8 headersize[4];
u8 type[2];
u8 version[2];
u8 certsize[4];
u8 ticketsize[4];
u8 tmdsize[4];
u8 metasize[4];
u8 contentsize[8];
u8 contentindex[0x2000];
} ctr_ciaheader;
typedef struct
{
FILE* file;
u32 offset;
u32 size;
u8 titlekey[16];
u8 iv[16];
ctr_ciaheader header;
ctr_aes_context aes;
settings* usersettings;
tik_context tik;
tmd_context tmd;
u32 sizeheader;
u32 sizecert;
u32 sizetik;
u32 sizetmd;
u32 sizecontent;
u32 sizemeta;
u32 offsetcerts;
u32 offsettik;
u32 offsettmd;
u32 offsetcontent;
u32 offsetmeta;
} cia_context;
void cia_init(cia_context* ctx);
void cia_set_file(cia_context* ctx, FILE* file);
void cia_set_offset(cia_context* ctx, u32 offset);
void cia_set_size(cia_context* ctx, u32 size);
void cia_set_usersettings(cia_context* ctx, settings* usersettings);
void cia_print(cia_context* ctx);
void cia_save(cia_context* ctx, u32 type, u32 flags);
void cia_process(cia_context* ctx, u32 actions);
void cia_save_blob(cia_context *ctx, char *out_path, u32 offset, u32 size, int do_cbc);
void cia_verify_contents(cia_context *ctx);
#endif // _CIA_H_

354
ctrtool/ctr.c Normal file
View File

@ -0,0 +1,354 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "ctr.h"
void ctr_set_iv( ctr_aes_context* ctx,
u8 iv[16] )
{
memcpy(ctx->iv, iv, 16);
}
void ctr_add_counter( ctr_aes_context* ctx,
u32 carry )
{
u32 counter[4];
u32 sum;
int i;
for(i=0; i<4; i++)
counter[i] = (ctx->ctr[i*4+0]<<24) | (ctx->ctr[i*4+1]<<16) | (ctx->ctr[i*4+2]<<8) | (ctx->ctr[i*4+3]<<0);
for(i=3; i>=0; i--)
{
sum = counter[i] + carry;
if (sum < counter[i])
carry = 1;
else
carry = 0;
counter[i] = sum;
}
for(i=0; i<4; i++)
{
ctx->ctr[i*4+0] = counter[i]>>24;
ctx->ctr[i*4+1] = counter[i]>>16;
ctx->ctr[i*4+2] = counter[i]>>8;
ctx->ctr[i*4+3] = counter[i]>>0;
}
}
void ctr_set_counter( ctr_aes_context* ctx,
u8 ctr[16] )
{
memcpy(ctx->ctr, ctr, 16);
}
void ctr_init_counter( ctr_aes_context* ctx,
u8 key[16],
u8 ctr[16] )
{
aes_setkey_enc(&ctx->aes, key, 128);
ctr_set_counter(ctx, ctr);
}
void ctr_crypt_counter_block( ctr_aes_context* ctx,
u8 input[16],
u8 output[16] )
{
int i;
u8 stream[16];
aes_crypt_ecb(&ctx->aes, AES_ENCRYPT, ctx->ctr, stream);
if (input)
{
for(i=0; i<16; i++)
{
output[i] = stream[i] ^ input[i];
}
}
else
{
for(i=0; i<16; i++)
output[i] = stream[i];
}
ctr_add_counter(ctx, 1);
}
void ctr_crypt_counter( ctr_aes_context* ctx,
u8* input,
u8* output,
u32 size )
{
u8 stream[16];
u32 i;
while(size >= 16)
{
ctr_crypt_counter_block(ctx, input, output);
if (input)
input += 16;
if (output)
output += 16;
size -= 16;
}
if (size)
{
memset(stream, 0, 16);
ctr_crypt_counter_block(ctx, stream, stream);
if (input)
{
for(i=0; i<size; i++)
output[i] = input[i] ^ stream[i];
}
else
{
memcpy(output, stream, size);
}
}
}
void ctr_init_cbc_encrypt( ctr_aes_context* ctx,
u8 key[16],
u8 iv[16] )
{
aes_setkey_enc(&ctx->aes, key, 128);
ctr_set_iv(ctx, iv);
}
void ctr_init_cbc_decrypt( ctr_aes_context* ctx,
u8 key[16],
u8 iv[16] )
{
aes_setkey_dec(&ctx->aes, key, 128);
ctr_set_iv(ctx, iv);
}
void ctr_encrypt_cbc( ctr_aes_context* ctx,
u8* input,
u8* output,
u32 size )
{
aes_crypt_cbc(&ctx->aes, AES_ENCRYPT, size, ctx->iv, input, output);
}
void ctr_decrypt_cbc( ctr_aes_context* ctx,
u8* input,
u8* output,
u32 size )
{
aes_crypt_cbc(&ctx->aes, AES_DECRYPT, size, ctx->iv, input, output);
}
void ctr_sha_256( const u8* data,
u32 size,
u8 hash[0x20] )
{
sha2(data, size, hash, 0);
}
int ctr_sha_256_verify( const u8* data,
u32 size,
const u8 checkhash[0x20] )
{
u8 hash[0x20];
sha2(data, size, hash, 0);
if (memcmp(hash, checkhash, 0x20) == 0)
return Good;
else
return Fail;
}
void ctr_sha_256_init( ctr_sha256_context* ctx )
{
sha2_starts(&ctx->sha, 0);
}
void ctr_sha_256_update( ctr_sha256_context* ctx,
const u8* data,
u32 size )
{
sha2_update(&ctx->sha, data, size);
}
void ctr_sha_256_finish( ctr_sha256_context* ctx,
u8 hash[0x20] )
{
sha2_finish(&ctx->sha, hash);
}
void ctr_rsa_init_key_pubmodulus(rsakey2048* key, u8 modulus[0x100])
{
u8 exponent[3] = {0x01, 0x00, 0x01};
ctr_rsa_init_key_pub(key, modulus, exponent);
}
void ctr_rsa_init_key_pub(rsakey2048* key, u8 modulus[0x100], u8 exponent[3])
{
key->keytype = RSAKEY_PUB;
memcpy(key->n, modulus, 0x100);
memcpy(key->e, exponent, 3);
}
int ctr_rsa_init(ctr_rsa_context* ctx, rsakey2048* key)
{
rsa_init(&ctx->rsa, RSA_PKCS_V15, 0);
ctx->rsa.len = 0x100;
if (key->keytype == RSAKEY_INVALID)
goto clean;
if (mpi_read_binary(&ctx->rsa.N, key->n, sizeof(key->n)))
goto clean;
if (mpi_read_binary(&ctx->rsa.E, key->e, sizeof(key->e)))
goto clean;
if (rsa_check_pubkey(&ctx->rsa))
goto clean;
if (key->keytype == RSAKEY_PRIV)
{
if (mpi_read_binary(&ctx->rsa.D, key->d, sizeof(key->d)))
goto clean;
if (mpi_read_binary(&ctx->rsa.P, key->p, sizeof(key->p)))
goto clean;
if (mpi_read_binary(&ctx->rsa.Q, key->q, sizeof(key->q)))
goto clean;
if (mpi_read_binary(&ctx->rsa.DP, key->dp, sizeof(key->dp)))
goto clean;
if (mpi_read_binary(&ctx->rsa.DQ, key->dq, sizeof(key->dq)))
goto clean;
if (mpi_read_binary(&ctx->rsa.QP, key->qp, sizeof(key->qp)))
goto clean;
if (rsa_check_privkey(&ctx->rsa))
goto clean;
}
return 1;
clean:
return 0;
}
int ctr_rsa_verify_hash(const u8 signature[0x100], const u8 hash[0x20], rsakey2048* key)
{
ctr_rsa_context ctx;
u32 result;
u8 output[0x100];
if (key->keytype == RSAKEY_INVALID)
return Fail;
ctr_rsa_init(&ctx, key);
// memset(output, 0, 0x100);
// result = ctr_rsa_public(signature, output, key);
// printf("Result = %d\n", result);
// memdump(stdout, "output: ", output, 0x100);
result = rsa_pkcs1_verify(&ctx.rsa, RSA_PUBLIC, SIG_RSA_SHA256, 0x20, hash, (u8*)signature);
ctr_rsa_free(&ctx);
if (result == 0)
return Good;
else
return Fail;
}
int ctr_rsa_sign_hash(const u8 hash[0x20], u8 signature[0x100], rsakey2048* key)
{
ctr_rsa_context ctx;
u32 result;
ctr_rsa_init(&ctx, key);
result = rsa_pkcs1_verify(&ctx.rsa, RSA_PUBLIC, SIG_RSA_SHA256, 0x20, hash, (u8*)signature);
result = rsa_pkcs1_sign(&ctx.rsa, RSA_PRIVATE, SIG_RSA_SHA256, 0x20, hash, signature);
ctr_rsa_free(&ctx);
if (result == 0)
return 1;
else
return 0;
}
int ctr_rsa_public(const u8 signature[0x100], u8 output[0x100], rsakey2048* key)
{
ctr_rsa_context ctx;
u32 result;
ctr_rsa_init(&ctx, key);
result = rsa_public(&ctx.rsa, signature, output);
ctr_rsa_free(&ctx);
if (result == 0)
return 1;
else
return 0;
}
void ctr_rsa_free(ctr_rsa_context* ctx)
{
rsa_free(&ctx->rsa);
}
/*
* Generate DP, DQ, QP based on private key
*/
#if 0
static int ctr_rsa_key_init(ctr_rsa_context* ctx )
{
int ret;
mpi P1, Q1;
mpi_init( &P1, &Q1, NULL );
MPI_CHK( mpi_sub_int( &P1, &ctx->rsa.P, 1 ) );
MPI_CHK( mpi_sub_int( &Q1, &ctx->rsa.Q, 1 ) );
/*
* DP = D mod (P - 1)
* DQ = D mod (Q - 1)
* QP = Q^-1 mod P
*/
MPI_CHK( mpi_mod_mpi( &ctx->rsa.DP, &ctx->rsa.D, &P1 ) );
MPI_CHK( mpi_mod_mpi( &ctx->rsa.DQ, &ctx->rsa.D, &Q1 ) );
MPI_CHK( mpi_inv_mod( &ctx->rsa.QP, &ctx->rsa.Q, &ctx->rsa.P ) );
cleanup:
mpi_free(&Q1, &P1, NULL );
if( ret != 0 )
{
rsa_free( &ctx->rsa );
return( POLARSSL_ERR_RSA_KEY_GEN_FAILED | ret );
}
return( 0 );
}
#endif

146
ctrtool/ctr.h Normal file
View File

@ -0,0 +1,146 @@
#ifndef _CTR_H_
#define _CTR_H_
#include "polarssl/aes.h"
#include "polarssl/rsa.h"
#include "polarssl/sha2.h"
#include "types.h"
#include "keyset.h"
#define MAGIC_NCCH 0x4843434E
#define MAGIC_NCSD 0x4453434E
#define MAGIC_FIRM 0x4D524946
#define MAGIC_CWAV 0x56415743
#define MAGIC_IVFC 0x43465649
#define SIZE_128MB (128 * 1024 * 1024)
typedef enum
{
FILETYPE_UNKNOWN = 0,
FILETYPE_CCI,
FILETYPE_CXI,
FILETYPE_CIA,
FILETYPE_EXHEADER,
FILETYPE_TMD,
FILETYPE_LZSS,
FILETYPE_FIRM,
FILETYPE_CWAV,
FILETYPE_ROMFS
} ctr_filetypes;
typedef struct
{
u8 ctr[16];
u8 iv[16];
aes_context aes;
} ctr_aes_context;
typedef struct
{
rsa_context rsa;
} ctr_rsa_context;
typedef struct
{
sha2_context sha;
} ctr_sha256_context;
#ifdef __cplusplus
extern "C" {
#endif
void ctr_set_iv( ctr_aes_context* ctx,
u8 iv[16] );
void ctr_add_counter( ctr_aes_context* ctx,
u32 carry );
void ctr_set_counter( ctr_aes_context* ctx,
u8 ctr[16] );
void ctr_init_counter( ctr_aes_context* ctx,
u8 key[16],
u8 ctr[16] );
void ctr_crypt_counter_block( ctr_aes_context* ctx,
u8 input[16],
u8 output[16] );
void ctr_crypt_counter( ctr_aes_context* ctx,
u8* input,
u8* output,
u32 size );
void ctr_init_cbc_encrypt( ctr_aes_context* ctx,
u8 key[16],
u8 iv[16] );
void ctr_init_cbc_decrypt( ctr_aes_context* ctx,
u8 key[16],
u8 iv[16] );
void ctr_encrypt_cbc( ctr_aes_context* ctx,
u8* input,
u8* output,
u32 size );
void ctr_decrypt_cbc( ctr_aes_context* ctx,
u8* input,
u8* output,
u32 size );
void ctr_rsa_init_key_pubmodulus( rsakey2048* key,
u8 modulus[0x100] );
void ctr_rsa_init_key_pub( rsakey2048* key,
u8 modulus[0x100],
u8 exponent[3] );
int ctr_rsa_init( ctr_rsa_context* ctx,
rsakey2048* key );
void ctr_rsa_free( ctr_rsa_context* ctx );
int ctr_rsa_verify_hash( const u8 signature[0x100],
const u8 hash[0x20],
rsakey2048* key);
int ctr_rsa_sign_hash( const u8 hash[0x20],
u8 signature[0x100],
rsakey2048* key );
int ctr_rsa_public( const u8 signature[0x100],
u8 output[0x100],
rsakey2048* key );
void ctr_sha_256( const u8* data,
u32 size,
u8 hash[0x20] );
int ctr_sha_256_verify( const u8* data,
u32 size,
const u8 checkhash[0x20] );
void ctr_sha_256_init( ctr_sha256_context* ctx );
void ctr_sha_256_update( ctr_sha256_context* ctx,
const u8* data,
u32 size );
void ctr_sha_256_finish( ctr_sha256_context* ctx,
u8 hash[0x20] );
#ifdef __cplusplus
}
#endif
#endif // _CTR_H_

442
ctrtool/ctrtool.vcproj Normal file
View File

@ -0,0 +1,442 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="ctrtool"
ProjectGUID="{96F5CA15-30DA-4DF5-9DFF-523D58D38001}"
RootNamespace="ctrtooltje"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="windows;."
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
DisableSpecificWarnings="4996"
UseFullPaths="false"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="windows;."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="c:\dev\tools\bin\ctrtool.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\cia.c"
>
</File>
<File
RelativePath=".\ctr.c"
>
</File>
<File
RelativePath=".\cwav.c"
>
</File>
<File
RelativePath=".\exefs.c"
>
</File>
<File
RelativePath=".\exheader.c"
>
</File>
<File
RelativePath=".\filepath.c"
>
</File>
<File
RelativePath=".\firm.c"
>
</File>
<File
RelativePath=".\windows\getopt.c"
>
</File>
<File
RelativePath=".\windows\getopt1.c"
>
</File>
<File
RelativePath=".\ivfc.c"
>
</File>
<File
RelativePath=".\keyset.cpp"
>
</File>
<File
RelativePath=".\lzss.c"
>
</File>
<File
RelativePath=".\main.c"
>
</File>
<File
RelativePath=".\ncch.c"
>
</File>
<File
RelativePath=".\ncsd.c"
>
</File>
<File
RelativePath=".\romfs.c"
>
</File>
<File
RelativePath=".\settings.c"
>
</File>
<File
RelativePath=".\stream.c"
>
</File>
<File
RelativePath=".\tik.c"
>
</File>
<File
RelativePath=".\tmd.c"
>
</File>
<File
RelativePath=".\utils.c"
>
</File>
<Filter
Name="polarssl"
>
<File
RelativePath=".\polarssl\aes.c"
>
</File>
<File
RelativePath=".\polarssl\bignum.c"
>
</File>
<File
RelativePath=".\polarssl\rsa.c"
>
</File>
<File
RelativePath=".\polarssl\sha2.c"
>
</File>
</Filter>
<Filter
Name="tinyxml"
>
<File
RelativePath=".\tinyxml\tinystr.cpp"
>
</File>
<File
RelativePath=".\tinyxml\tinyxml.cpp"
>
</File>
<File
RelativePath=".\tinyxml\tinyxmlerror.cpp"
>
</File>
<File
RelativePath=".\tinyxml\tinyxmlparser.cpp"
>
</File>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\cia.h"
>
</File>
<File
RelativePath=".\ctr.h"
>
</File>
<File
RelativePath=".\cwav.h"
>
</File>
<File
RelativePath=".\exefs.h"
>
</File>
<File
RelativePath=".\exheader.h"
>
</File>
<File
RelativePath=".\filepath.h"
>
</File>
<File
RelativePath=".\firm.h"
>
</File>
<File
RelativePath=".\windows\getopt.h"
>
</File>
<File
RelativePath=".\info.h"
>
</File>
<File
RelativePath=".\ivfc.h"
>
</File>
<File
RelativePath=".\keyset.h"
>
</File>
<File
RelativePath=".\lzss.h"
>
</File>
<File
RelativePath=".\ncch.h"
>
</File>
<File
RelativePath=".\ncsd.h"
>
</File>
<File
RelativePath=".\romfs.h"
>
</File>
<File
RelativePath=".\settings.h"
>
</File>
<File
RelativePath=".\stream.h"
>
</File>
<File
RelativePath=".\tik.h"
>
</File>
<File
RelativePath=".\tmd.h"
>
</File>
<File
RelativePath=".\types.h"
>
</File>
<File
RelativePath=".\utils.h"
>
</File>
<Filter
Name="polarssl"
>
<File
RelativePath=".\polarssl\aes.h"
>
</File>
<File
RelativePath=".\polarssl\bignum.h"
>
</File>
<File
RelativePath=".\polarssl\bn_mul.h"
>
</File>
<File
RelativePath=".\polarssl\config.h"
>
</File>
<File
RelativePath=".\polarssl\rsa.h"
>
</File>
<File
RelativePath=".\polarssl\sha2.h"
>
</File>
</Filter>
<Filter
Name="tinyxml"
>
<File
RelativePath=".\tinyxml\tinystr.h"
>
</File>
<File
RelativePath=".\tinyxml\tinyxml.h"
>
</File>
</Filter>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

1001
ctrtool/cwav.c Normal file

File diff suppressed because it is too large Load Diff

205
ctrtool/cwav.h Normal file
View File

@ -0,0 +1,205 @@
#ifndef _CWAV_H_
#define _CWAV_H_
#include <stdio.h>
#include "types.h"
#include "settings.h"
#include "stream.h"
#define CWAV_ENCODING_PCM8 0
#define CWAV_ENCODING_PCM16 1
#define CWAV_ENCODING_DSPADPCM 2
#define CWAV_ENCODING_IMAADPCM 3
typedef struct
{
u8 idtype[2];
u8 padding[2];
u8 offset[4];
} cwav_reference;
typedef struct
{
u8 idtype[2];
u8 padding[2];
u8 offset[4];
u8 size[4];
} cwav_sizedreference;
typedef struct
{
u8 magic[4];
u8 byteordermark[2];
u8 headersize[2];
u8 version[4];
u8 totalsize[4];
u8 datablocks[2];
u8 reserved[2];
cwav_sizedreference infoblockref;
cwav_sizedreference datablockref;
} cwav_header;
typedef struct
{
u8 magic[4];
u8 size[4];
u8 encoding;
u8 looped;
u8 padding[2];
u8 samplerate[4];
u8 loopstart[4];
u8 loopend[4];
u8 reserved[4];
u8 channelcount[4];
} cwav_infoheader;
typedef struct
{
cwav_reference sampleref;
cwav_reference codecref;
u8 reserved[4];
} cwav_channelinfo;
typedef struct
{
u8 coef[16][2];
u8 scale[2];
u8 yn1[2];
u8 yn2[2];
u8 loopscale[2];
u8 loopyn1[2];
u8 loopyn2[2];
} cwav_dspadpcminfo;
typedef struct
{
u8 data[2];
u8 tableindex;
u8 padding;
u8 loopdata[2];
u8 looptableindex;
u8 looppadding;
} cwav_imaadpcminfo;
typedef struct
{
s16 yn1;
s16 yn2;
u32 sampleoffset;
s16* samplebuffer;
stream_in_context instreamctx;
} cwav_dspadpcmchannelstate;
typedef struct
{
cwav_dspadpcmchannelstate* channelstate;
s16* samplebuffer;
u32 samplecountavailable;
u32 samplecountcapacity;
u32 samplecountremaining;
} cwav_dspadpcmstate;
typedef struct
{
s16 data;
u8 tableindex;
u32 sampleoffset;
s16* samplebuffer;
stream_in_context instreamctx;
} cwav_imaadpcmchannelstate;
typedef struct
{
cwav_imaadpcmchannelstate* channelstate;
s16* samplebuffer;
u32 samplecountavailable;
u32 samplecountcapacity;
u32 samplecountremaining;
} cwav_imaadpcmstate;
typedef struct
{
u32 sampleoffset;
s16* samplebuffer;
stream_in_context instreamctx;
} cwav_pcmchannelstate;
typedef struct
{
cwav_pcmchannelstate* channelstate;
s16* samplebuffer;
u32 samplecountavailable;
u32 samplecountcapacity;
u32 samplecountremaining;
} cwav_pcmstate;
typedef struct
{
cwav_reference inforef;
cwav_channelinfo info;
cwav_dspadpcminfo infodspadpcm;
cwav_imaadpcminfo infoimaadpcm;
} cwav_channel;
typedef struct
{
u8 chunkid[4];
u8 chunksize[4];
u8 format[4];
u8 subchunk1id[4];
u8 subchunk1size[4];
u8 audioformat[2];
u8 numchannels[2];
u8 samplerate[4];
u8 byterate[4];
u8 blockalign[2];
u8 bitspersample[2];
u8 subchunk2id[4];
u8 subchunk2size[4];
} wav_pcm_header;
typedef struct
{
FILE* file;
settings* usersettings;
u32 offset;
u32 size;
u32 channelcount;
cwav_header header;
cwav_infoheader infoheader;
cwav_channel* channel;
} cwav_context;
void cwav_init(cwav_context* ctx);
void cwav_set_file(cwav_context* ctx, FILE* file);
void cwav_set_offset(cwav_context* ctx, u32 offset);
void cwav_set_size(cwav_context* ctx, u32 size);
void cwav_set_usersettings(cwav_context* ctx, settings* usersettings);
void cwav_process(cwav_context* ctx, u32 actions);
void cwav_dspadpcm_init(cwav_dspadpcmstate* state);
int cwav_dspadpcm_allocate(cwav_dspadpcmstate* state, cwav_context* ctx);
int cwav_dspadpcm_setup(cwav_dspadpcmstate* state, cwav_context* ctx, int isloop);
int cwav_dspadpcm_decode(cwav_dspadpcmstate* state, cwav_context* ctx);
int cwav_dspadpcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx);
void cwav_dspadpcm_destroy(cwav_dspadpcmstate* state);
void cwav_imaadpcm_init(cwav_imaadpcmstate* state);
int cwav_imaadpcm_allocate(cwav_imaadpcmstate* state, cwav_context* ctx);
int cwav_imaadpcm_setup(cwav_imaadpcmstate* state, cwav_context* ctx, int isloop);
int cwav_imaadpcm_decode(cwav_imaadpcmstate* state, cwav_context* ctx);
int cwav_imaadpcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx);
u8 cwav_imaadpcm_clamp_tableindex(u8 tableindex, int inc);
void cwav_imaadpcm_destroy(cwav_imaadpcmstate* state);
void cwav_pcm_init(cwav_pcmstate* state);
int cwav_pcm_allocate(cwav_pcmstate* state, cwav_context* ctx);
int cwav_pcm_setup(cwav_pcmstate* state, cwav_context* ctx, int isloop);
int cwav_pcm_decode(cwav_pcmstate* state, cwav_context* ctx);
int cwav_pcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx);
void cwav_pcm_destroy(cwav_pcmstate* state);
void cwav_write_wav_header(cwav_context* ctx, stream_out_context* outstreamctx, u32 size);
int cwav_save_to_wav(cwav_context* ctx, const char* filepath);
void cwav_print(cwav_context* ctx);
#endif // _CWAV_H_

337
ctrtool/exefs.c Normal file
View File

@ -0,0 +1,337 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "exefs.h"
#include "utils.h"
#include "ncch.h"
#include "lzss.h"
void exefs_init(exefs_context* ctx)
{
memset(ctx, 0, sizeof(exefs_context));
}
void exefs_set_file(exefs_context* ctx, FILE* file)
{
ctx->file = file;
}
void exefs_set_offset(exefs_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void exefs_set_size(exefs_context* ctx, u32 size)
{
ctx->size = size;
}
void exefs_set_usersettings(exefs_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void exefs_set_partitionid(exefs_context* ctx, u8 partitionid[8])
{
memcpy(ctx->partitionid, partitionid, 8);
}
void exefs_set_compressedflag(exefs_context* ctx, int compressedflag)
{
ctx->compressedflag = compressedflag;
}
void exefs_set_encrypted(exefs_context* ctx, u32 encrypted)
{
ctx->encrypted = encrypted;
}
void exefs_set_key(exefs_context* ctx, u8 key[16])
{
memcpy(ctx->key, key, 16);
}
void exefs_set_counter(exefs_context* ctx, u8 counter[16])
{
memcpy(ctx->counter, counter, 16);
}
void exefs_determine_key(exefs_context* ctx, u32 actions)
{
u8* key = settings_get_ncch_key(ctx->usersettings);
if (actions & PlainFlag)
ctx->encrypted = 0;
else
{
if (key)
{
ctx->encrypted = 1;
memcpy(ctx->key, key, 0x10);
}
}
}
void exefs_save(exefs_context* ctx, u32 index, u32 flags)
{
exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + index);
char outfname[MAX_PATH];
char name[64];
u32 offset;
u32 size;
FILE* fout;
u32 compressedsize = 0;
u32 decompressedsize = 0;
u8* compressedbuffer = 0;
u8* decompressedbuffer = 0;
filepath* dirpath = 0;
offset = getle32(section->offset) + sizeof(exefs_header);
size = getle32(section->size);
dirpath = settings_get_exefs_dir_path(ctx->usersettings);
if (size == 0 || dirpath == 0 || dirpath->valid == 0)
return;
if (size >= ctx->size)
{
fprintf(stderr, "Error, ExeFS section %d size invalid\n", index);
return;
}
memset(name, 0, sizeof(name));
memcpy(name, section->name, 8);
memcpy(outfname, dirpath->pathname, MAX_PATH);
strcat(outfname, "/");
if (name[0] == '.')
strcat(outfname, name+1);
else
strcat(outfname, name);
strcat(outfname, ".bin");
fout = fopen(outfname, "wb");
if (fout == 0)
{
fprintf(stderr, "Error, failed to create file %s\n", outfname);
goto clean;
}
fseek(ctx->file, ctx->offset + offset, SEEK_SET);
ctr_init_counter(&ctx->aes, ctx->key, ctx->counter);
ctr_add_counter(&ctx->aes, offset / 0x10);
if (index == 0 && ctx->compressedflag && ((flags & RawFlag) == 0))
{
fprintf(stdout, "Decompressing section %s to %s...\n", name, outfname);
compressedsize = size;
compressedbuffer = malloc(compressedsize);
if (compressedbuffer == 0)
{
fprintf(stdout, "Error allocating memory\n");
goto clean;
}
if (compressedsize != fread(compressedbuffer, 1, compressedsize, ctx->file))
{
fprintf(stdout, "Error reading input file\n");
goto clean;
}
if (ctx->encrypted)
ctr_crypt_counter(&ctx->aes, compressedbuffer, compressedbuffer, compressedsize);
decompressedsize = lzss_get_decompressed_size(compressedbuffer, compressedsize);
decompressedbuffer = malloc(decompressedsize);
if (decompressedbuffer == 0)
{
fprintf(stdout, "Error allocating memory\n");
goto clean;
}
if (0 == lzss_decompress(compressedbuffer, compressedsize, decompressedbuffer, decompressedsize))
goto clean;
if (decompressedsize != fwrite(decompressedbuffer, 1, decompressedsize, fout))
{
fprintf(stdout, "Error writing output file\n");
goto clean;
}
}
else
{
u8 buffer[16 * 1024];
fprintf(stdout, "Saving section %s to %s...\n", name, outfname);
while(size)
{
u32 max = sizeof(buffer);
if (max > size)
max = size;
if (max != fread(buffer, 1, max, ctx->file))
{
fprintf(stdout, "Error reading input file\n");
goto clean;
}
if (ctx->encrypted)
ctr_crypt_counter(&ctx->aes, buffer, buffer, max);
if (max != fwrite(buffer, 1, max, fout))
{
fprintf(stdout, "Error writing output file\n");
goto clean;
}
size -= max;
}
}
clean:
free(compressedbuffer);
free(decompressedbuffer);
return;
}
void exefs_read_header(exefs_context* ctx, u32 flags)
{
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(&ctx->header, 1, sizeof(exefs_header), ctx->file);
ctr_init_counter(&ctx->aes, ctx->key, ctx->counter);
if (ctx->encrypted)
ctr_crypt_counter(&ctx->aes, (u8*)&ctx->header, (u8*)&ctx->header, sizeof(exefs_header));
}
void exefs_calculate_hash(exefs_context* ctx, u8 hash[32])
{
ctr_sha_256((const u8*)&ctx->header, sizeof(exefs_header), hash);
}
void exefs_process(exefs_context* ctx, u32 actions)
{
u32 i;
exefs_determine_key(ctx, actions);
exefs_read_header(ctx, actions);
if (actions & VerifyFlag)
{
for(i=0; i<8; i++)
ctx->hashcheck[i] = exefs_verify(ctx, i, actions)? Good : Fail;
}
if (actions & InfoFlag)
{
exefs_print(ctx);
}
if (actions & ExtractFlag)
{
filepath* dirpath = settings_get_exefs_dir_path(ctx->usersettings);
if (dirpath && dirpath->valid)
{
makedir(dirpath->pathname);
for(i=0; i<8; i++)
exefs_save(ctx, i, actions);
}
}
}
int exefs_verify(exefs_context* ctx, u32 index, u32 flags)
{
exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + index);
u32 offset;
u32 size;
u8 buffer[16 * 1024];
u8 hash[0x20];
offset = getle32(section->offset) + sizeof(exefs_header);
size = getle32(section->size);
if (size == 0)
return 0;
fseek(ctx->file, ctx->offset + offset, SEEK_SET);
ctr_init_counter(&ctx->aes, ctx->key, ctx->counter);
ctr_add_counter(&ctx->aes, offset / 0x10);
ctr_sha_256_init(&ctx->sha);
while(size)
{
u32 max = sizeof(buffer);
if (max > size)
max = size;
if (max != fread(buffer, 1, max, ctx->file))
{
fprintf(stdout, "Error reading input file\n");
goto clean;
}
if (ctx->encrypted)
ctr_crypt_counter(&ctx->aes, buffer, buffer, max);
ctr_sha_256_update(&ctx->sha, buffer, max);
size -= max;
}
ctr_sha_256_finish(&ctx->sha, hash);
if (memcmp(hash, ctx->header.hashes[7-index], 0x20) == 0)
return 1;
clean:
return 0;
}
void exefs_print(exefs_context* ctx)
{
u32 i;
char sectname[9];
u32 sectoffset;
u32 sectsize;
fprintf(stdout, "\nExeFS:\n");
for(i=0; i<8; i++)
{
exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + i);
memset(sectname, 0, sizeof(sectname));
memcpy(sectname, section->name, 8);
sectoffset = getle32(section->offset);
sectsize = getle32(section->size);
if (sectsize)
{
fprintf(stdout, "Section name: %s\n", sectname);
fprintf(stdout, "Section offset: 0x%08x\n", sectoffset + 0x200);
fprintf(stdout, "Section size: 0x%08x\n", sectsize);
if (ctx->hashcheck[i] == Good)
memdump(stdout, "Section hash (GOOD): ", ctx->header.hashes[7-i], 0x20);
else if (ctx->hashcheck[i] == Fail)
memdump(stdout, "Section hash (FAIL): ", ctx->header.hashes[7-i], 0x20);
else
memdump(stdout, "Section hash: ", ctx->header.hashes[7-i], 0x20);
}
}
}

60
ctrtool/exefs.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef _EXEFS_H_
#define _EXEFS_H_
#include "types.h"
#include "info.h"
#include "ctr.h"
#include "filepath.h"
#include "settings.h"
typedef struct
{
u8 name[8];
u8 offset[4];
u8 size[4];
} exefs_sectionheader;
typedef struct
{
exefs_sectionheader section[8];
u8 reserved[0x80];
u8 hashes[8][0x20];
} exefs_header;
typedef struct
{
FILE* file;
settings* usersettings;
u8 partitionid[8];
u8 counter[16];
u8 key[16];
u32 offset;
u32 size;
exefs_header header;
ctr_aes_context aes;
ctr_sha256_context sha;
int hashcheck[8];
int compressedflag;
int encrypted;
} exefs_context;
void exefs_init(exefs_context* ctx);
void exefs_set_file(exefs_context* ctx, FILE* file);
void exefs_set_offset(exefs_context* ctx, u32 offset);
void exefs_set_size(exefs_context* ctx, u32 size);
void exefs_set_usersettings(exefs_context* ctx, settings* usersettings);
void exefs_set_partitionid(exefs_context* ctx, u8 partitionid[8]);
void exefs_set_counter(exefs_context* ctx, u8 counter[16]);
void exefs_set_compressedflag(exefs_context* ctx, int compressedflag);
void exefs_set_key(exefs_context* ctx, u8 key[16]);
void exefs_set_encrypted(exefs_context* ctx, u32 encrypted);
void exefs_read_header(exefs_context* ctx, u32 flags);
void exefs_calculate_hash(exefs_context* ctx, u8 hash[32]);
void exefs_process(exefs_context* ctx, u32 actions);
void exefs_print(exefs_context* ctx);
void exefs_save(exefs_context* ctx, u32 index, u32 flags);
int exefs_verify(exefs_context* ctx, u32 index, u32 flags);
void exefs_determine_key(exefs_context* ctx, u32 actions);
#endif // _EXEFS_H_

423
ctrtool/exheader.c Normal file
View File

@ -0,0 +1,423 @@
#include <stdio.h>
#include <string.h>
#include "types.h"
#include "exheader.h"
#include "utils.h"
#include "ncch.h"
void exheader_init(exheader_context* ctx)
{
memset(ctx, 0, sizeof(exheader_context));
}
void exheader_set_file(exheader_context* ctx, FILE* file)
{
ctx->file = file;
}
void exheader_set_offset(exheader_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void exheader_set_size(exheader_context* ctx, u32 size)
{
ctx->size = size;
}
void exheader_set_usersettings(exheader_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void exheader_set_partitionid(exheader_context* ctx, u8 partitionid[8])
{
memcpy(ctx->partitionid, partitionid, 8);
}
void exheader_set_programid(exheader_context* ctx, u8 programid[8])
{
memcpy(ctx->programid, programid, 8);
}
void exheader_set_counter(exheader_context* ctx, u8 counter[16])
{
memcpy(ctx->counter, counter, 16);
}
int exheader_get_compressedflag(exheader_context* ctx)
{
return ctx->compressedflag;
}
void exheader_set_encrypted(exheader_context* ctx, u32 encrypted)
{
ctx->encrypted = encrypted;
}
void exheader_set_key(exheader_context* ctx, u8 key[16])
{
memcpy(ctx->key, key, 16);
}
void exheader_determine_key(exheader_context* ctx, u32 actions)
{
u8* key = settings_get_ncch_key(ctx->usersettings);
if (actions & PlainFlag)
ctx->encrypted = 0;
else
{
if (key)
{
ctx->encrypted = 1;
memcpy(ctx->key, key, 0x10);
}
}
}
void exheader_read(exheader_context* ctx, u32 actions)
{
if (ctx->haveread == 0)
{
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(&ctx->header, 1, sizeof(exheader_header), ctx->file);
ctr_init_counter(&ctx->aes, ctx->key, ctx->counter);
if (ctx->encrypted)
ctr_crypt_counter(&ctx->aes, (u8*)&ctx->header, (u8*)&ctx->header, sizeof(exheader_header));
ctx->haveread = 1;
}
}
int exheader_programid_valid(exheader_context* ctx)
{
if (!settings_get_ignore_programid(ctx->usersettings))
{
if (memcmp(ctx->header.arm11systemlocalcaps.programid, ctx->programid, 8))
{
fprintf(stderr, "Error, program id mismatch. Wrong key?\n");
return 0;
}
}
return 1;
}
int exheader_process(exheader_context* ctx, u32 actions)
{
exheader_determine_key(ctx, actions);
exheader_read(ctx, actions);
if (ctx->header.codesetinfo.flags.flag & 1)
ctx->compressedflag = 1;
if (actions & VerifyFlag)
exheader_verify(ctx);
if (actions & InfoFlag)
{
exheader_print(ctx);
}
return 1;
}
void exheader_print_arm9accesscontrol(exheader_context* ctx)
{
unsigned int i;
unsigned int flags[15*8];
fprintf(stdout, "ARM9 Desc. version: 0x%X\n", ctx->header.arm9accesscontrol.descversion);
for(i=0; i<15*8; i++)
{
if (ctx->header.arm9accesscontrol.descriptors[i/8] & (1<<(i&7)))
flags[i] = 1;
else
flags[i] = 0;
}
fprintf(stdout, "Mount NAND fs: %s\n", flags[0]? "YES" : "NO");
fprintf(stdout, "Mount NAND RO write fs: %s\n", flags[1]? "YES" : "NO");
fprintf(stdout, "Mount NAND TWL fs: %s\n", flags[2]? "YES" : "NO");
fprintf(stdout, "Mount NAND W fs: %s\n", flags[3]? "YES" : "NO");
fprintf(stdout, "Mount CARD SPI fs: %s\n", flags[4]? "YES" : "NO");
fprintf(stdout, "Use SDIF3: %s\n", flags[5]? "YES" : "NO");
fprintf(stdout, "Create seed: %s\n", flags[6]? "YES" : "NO");
fprintf(stdout, "Use CARD SPI: %s\n", flags[7]? "YES" : "NO");
fprintf(stdout, "SD Application: %s\n", flags[8]? "YES" : "NO");
fprintf(stdout, "Use Direct SDMC: %s\n", flags[9]? "YES" : "NO");
for(i=10; i<15*8; i++)
{
if (flags[i])
fprintf(stdout, "Unknown flag: %d\n", i);
}
}
void exheader_print_arm11kernelcapabilities(exheader_context* ctx)
{
unsigned int i, j;
unsigned int systemcallmask[8];
unsigned int unknowndescriptor[28];
unsigned int svccount = 0;
unsigned int svcmask = 0;
unsigned int interrupt[0x80];
unsigned int interruptcount = 0;
memset(systemcallmask, 0, sizeof(systemcallmask));
memset(interrupt, 0, sizeof(interrupt));
for(i=0; i<28; i++)
{
unsigned int descriptor = getle32(ctx->header.arm11kernelcaps.descriptors[i]);
unknowndescriptor[i] = 0;
if ((descriptor & (0x1f<<27)) == (0x1e<<27))
systemcallmask[(descriptor>>24) & 7] = descriptor & 0x00FFFFFF;
else if ((descriptor & (0x7f<<25)) == (0x7e<<25))
fprintf(stdout, "Kernel release version: %d.%d\n", (descriptor>>8)&0xFF, (descriptor>>0)&0xFF);
else if ((descriptor & (0xf<<28)) == (0xe<<28))
{
for(j=0; j<4; j++)
interrupt[(descriptor >> (j*7)) & 0x7F] = 1;
}
else if ((descriptor & (0xff<<24)) == (0xfe<<24))
fprintf(stdout, "Handle table size: 0x%X\n", descriptor & 0x3FF);
else if ((descriptor & (0xfff<<20)) == (0xffe<<20))
fprintf(stdout, "Mapping IO address: 0x%X (%s)\n", (descriptor & 0xFFFFF)<<12, (descriptor&(1<<20))?"RO":"RW");
else if ((descriptor & (0x7ff<<21)) == (0x7fc<<21))
fprintf(stdout, "Mapping static address: 0x%X (%s)\n", (descriptor & 0x1FFFFF)<<12, (descriptor&(1<<20))?"RO":"RW");
else if ((descriptor & (0x1ff<<23)) == (0x1fe<<23))
{
unsigned int memorytype = (descriptor>>8)&15;
fprintf(stdout, "Kernel flags: \n");
fprintf(stdout, " > Allow debug: %s\n", (descriptor&(1<<0))?"YES":"NO");
fprintf(stdout, " > Force debug: %s\n", (descriptor&(1<<1))?"YES":"NO");
fprintf(stdout, " > Allow non-alphanum: %s\n", (descriptor&(1<<2))?"YES":"NO");
fprintf(stdout, " > Shared page writing: %s\n", (descriptor&(1<<3))?"YES":"NO");
fprintf(stdout, " > Privilege priority: %s\n", (descriptor&(1<<4))?"YES":"NO");
fprintf(stdout, " > Allow main() args: %s\n", (descriptor&(1<<5))?"YES":"NO");
fprintf(stdout, " > Shared device mem: %s\n", (descriptor&(1<<6))?"YES":"NO");
fprintf(stdout, " > Runnable on sleep: %s\n", (descriptor&(1<<7))?"YES":"NO");
fprintf(stdout, " > Special memory: %s\n", (descriptor&(1<<12))?"YES":"NO");
switch(memorytype)
{
case 1: fprintf(stdout, " > Memory type: APPLICATION\n"); break;
case 2: fprintf(stdout, " > Memory type: SYSTEM\n"); break;
case 3: fprintf(stdout, " > Memory type: BASE\n"); break;
default: fprintf(stdout, " > Memory type: Unknown (%d)\n", memorytype); break;
}
}
else if (descriptor != 0xFFFFFFFF)
unknowndescriptor[i] = 1;
}
fprintf(stdout, "Allowed systemcalls: ");
for(i=0; i<8; i++)
{
for(j=0; j<24; j++)
{
svcmask = systemcallmask[i];
if (svcmask & (1<<j))
{
unsigned int svcid = i*24+j;
if (svccount == 0)
{
fprintf(stdout, "0x%02X", svcid);
}
else if ( (svccount & 7) == 0)
{
fprintf(stdout, " ");
fprintf(stdout, "0x%02X", svcid);
}
else
{
fprintf(stdout, ", 0x%02X", svcid);
}
svccount++;
if ( (svccount & 7) == 0)
{
fprintf(stdout, "\n");
}
}
}
}
if (svccount & 7)
fprintf(stdout, "\n");
if (svccount == 0)
fprintf(stdout, "none\n");
fprintf(stdout, "Allowed interrupts: ");
for(i=0; i<0x7F; i++)
{
if (interrupt[i])
{
if (interruptcount == 0)
{
fprintf(stdout, "0x%02X", i);
}
else if ( (interruptcount & 7) == 0)
{
fprintf(stdout, " ");
fprintf(stdout, "0x%02X", i);
}
else
{
fprintf(stdout, ", 0x%02X", i);
}
interruptcount++;
if ( (interruptcount & 7) == 0)
{
fprintf(stdout, "\n");
}
}
}
if (interruptcount & 7)
fprintf(stdout, "\n");
if (interruptcount == 0)
fprintf(stdout, "none\n");
for(i=0; i<28; i++)
{
unsigned int descriptor = getle32(ctx->header.arm11kernelcaps.descriptors[i]);
if (unknowndescriptor[i])
fprintf(stdout, "Unknown descriptor: %08X\n", descriptor);
}
}
int exheader_signature_verify(exheader_context* ctx, rsakey2048* key)
{
u8 hash[0x20];
ctr_sha_256(ctx->header.accessdesc.ncchpubkeymodulus, 0x300, hash);
return ctr_rsa_verify_hash(ctx->header.accessdesc.signature, hash, key);
}
void exheader_verify(exheader_context* ctx)
{
unsigned int i;
ctx->validprogramid = Good;
ctx->validpriority = Good;
ctx->validaffinitymask = Good;
for(i=0; i<8; i++)
{
if (ctx->header.accessdesc.arm11systemlocalcaps.programid[i] == 0xFF)
continue;
if (ctx->header.accessdesc.arm11systemlocalcaps.programid[i] == ctx->header.arm11systemlocalcaps.programid[i])
continue;
ctx->validprogramid = Fail;
break;
}
if (ctx->header.accessdesc.arm11systemlocalcaps.flags[7] > ctx->header.arm11systemlocalcaps.flags[7])
ctx->validpriority = Fail;
if (ctx->header.arm11systemlocalcaps.flags[5] & ~ctx->header.accessdesc.arm11systemlocalcaps.flags[5])
ctx->validaffinitymask = Fail;
if (ctx->usersettings)
ctx->validsignature = exheader_signature_verify(ctx, &ctx->usersettings->keys.ncchdescrsakey);
}
const char* exheader_getvalidstring(int valid)
{
if (valid == 0)
return "";
else if (valid == 1)
return "(GOOD)";
else
return "(FAIL)";
}
void exheader_print(exheader_context* ctx)
{
u32 i;
char name[9];
char service[9];
exheader_codesetinfo* codesetinfo = &ctx->header.codesetinfo;
memset(name, 0, sizeof(name));
memcpy(name, codesetinfo->name, 8);
fprintf(stdout, "\nExtended header:\n");
if (ctx->validsignature == Unchecked)
memdump(stdout, "Signature: ", ctx->header.accessdesc.signature, 0x100);
else if (ctx->validsignature == Good)
memdump(stdout, "Signature (GOOD): ", ctx->header.accessdesc.signature, 0x100);
else if (ctx->validsignature == Fail)
memdump(stdout, "Signature (FAIL): ", ctx->header.accessdesc.signature, 0x100);
fprintf(stdout, "Name: %s\n", name);
fprintf(stdout, "Flag: %02X ", codesetinfo->flags.flag);
if (codesetinfo->flags.flag & 1)
fprintf(stdout, "[compressed]");
fprintf(stdout, "\n");
fprintf(stdout, "Remaster version: %04X\n", getle16(codesetinfo->flags.remasterversion));
fprintf(stdout, "Code text address: 0x%08X\n", getle32(codesetinfo->text.address));
fprintf(stdout, "Code text size: 0x%08X\n", getle32(codesetinfo->text.codesize));
fprintf(stdout, "Code text max pages: 0x%08X (0x%08X)\n", getle32(codesetinfo->text.nummaxpages), getle32(codesetinfo->text.nummaxpages)*0x1000);
fprintf(stdout, "Code ro address: 0x%08X\n", getle32(codesetinfo->ro.address));
fprintf(stdout, "Code ro size: 0x%08X\n", getle32(codesetinfo->ro.codesize));
fprintf(stdout, "Code ro max pages: 0x%08X (0x%08X)\n", getle32(codesetinfo->ro.nummaxpages), getle32(codesetinfo->ro.nummaxpages)*0x1000);
fprintf(stdout, "Code data address: 0x%08X\n", getle32(codesetinfo->data.address));
fprintf(stdout, "Code data size: 0x%08X\n", getle32(codesetinfo->data.codesize));
fprintf(stdout, "Code data max pages: 0x%08X (0x%08X)\n", getle32(codesetinfo->data.nummaxpages), getle32(codesetinfo->data.nummaxpages)*0x1000);
fprintf(stdout, "Code bss size: 0x%08X\n", getle32(codesetinfo->bsssize));
fprintf(stdout, "Code stack size: 0x%08X\n", getle32(codesetinfo->stacksize));
for(i=0; i<0x30; i++)
{
if (getle64(ctx->header.deplist.programid[i]) != 0x0000000000000000UL)
fprintf(stdout, "Dependency: %016llX\n", getle64(ctx->header.deplist.programid[i]));
}
fprintf(stdout, "Savedata size: 0x%08X\n", getle32(ctx->header.systeminfo.savedatasize));
fprintf(stdout, "Jump id: %016llX\n", getle64(ctx->header.systeminfo.jumpid));
fprintf(stdout, "Program id: %016llX %s\n", getle64(ctx->header.arm11systemlocalcaps.programid), exheader_getvalidstring(ctx->validprogramid));
memdump(stdout, "Flags: ", ctx->header.arm11systemlocalcaps.flags, 8);
fprintf(stdout, "Core version: 0x%X\n", getle32(ctx->header.arm11systemlocalcaps.flags));
fprintf(stdout, "System mode: 0x%X\n", (ctx->header.arm11systemlocalcaps.flags[6]>>4)&0xF);
fprintf(stdout, "Ideal processor: %d\n", (ctx->header.arm11systemlocalcaps.flags[6]>>0)&0x3);
fprintf(stdout, "Affinity mask: %d %s\n", (ctx->header.arm11systemlocalcaps.flags[6]>>2)&0x3, exheader_getvalidstring(ctx->validaffinitymask));
fprintf(stdout, "Main thread priority: %d %s\n", ctx->header.arm11systemlocalcaps.flags[7], exheader_getvalidstring(ctx->validpriority));
// print resource limit descriptor too? currently mostly zeroes...
fprintf(stdout, "Ext savedata id: %016llX\n", getle64(ctx->header.arm11systemlocalcaps.storageinfo.extsavedataid));
fprintf(stdout, "System savedata id: %016llX\n", getle64(ctx->header.arm11systemlocalcaps.storageinfo.systemsavedataid));
memdump(stdout, "Access info: ", ctx->header.arm11systemlocalcaps.storageinfo.accessinfo, 7);
fprintf(stdout, "Other attributes: %02X\n", ctx->header.arm11systemlocalcaps.storageinfo.otherattributes);
exheader_print_arm11kernelcapabilities(ctx);
exheader_print_arm9accesscontrol(ctx);
for(i=0; i<0x20; i++)
{
if (getle64(ctx->header.arm11systemlocalcaps.serviceaccesscontrol[i]) != 0x0000000000000000UL)
{
memset(service, 0, sizeof(service));
memcpy(service, ctx->header.arm11systemlocalcaps.serviceaccesscontrol[i], 8);
fprintf(stdout, "Service access: %s\n", service);
}
}
fprintf(stdout, "Reslimit category: %02X\n", ctx->header.arm11systemlocalcaps.resourcelimitcategory);
}

143
ctrtool/exheader.h Normal file
View File

@ -0,0 +1,143 @@
#ifndef _EXHEADER_H_
#define _EXHEADER_H_
#include <stdio.h>
#include "types.h"
#include "ctr.h"
#include "settings.h"
typedef struct
{
u8 reserved[5];
u8 flag;
u8 remasterversion[2];
} exheader_systeminfoflags;
typedef struct
{
u8 address[4];
u8 nummaxpages[4];
u8 codesize[4];
} exheader_codesegmentinfo;
typedef struct
{
u8 name[8];
exheader_systeminfoflags flags;
exheader_codesegmentinfo text;
u8 stacksize[4];
exheader_codesegmentinfo ro;
u8 reserved[4];
exheader_codesegmentinfo data;
u8 bsssize[4];
} exheader_codesetinfo;
typedef struct
{
u8 programid[0x30][8];
} exheader_dependencylist;
typedef struct
{
u8 savedatasize[4];
u8 reserved[4];
u8 jumpid[8];
u8 reserved2[0x30];
} exheader_systeminfo;
typedef struct
{
u8 extsavedataid[8];
u8 systemsavedataid[8];
u8 reserved[8];
u8 accessinfo[7];
u8 otherattributes;
} exheader_storageinfo;
typedef struct
{
u8 programid[8];
u8 flags[8];
u8 resourcelimitdescriptor[0x10][2];
exheader_storageinfo storageinfo;
u8 serviceaccesscontrol[0x20][8];
u8 reserved[0x1f];
u8 resourcelimitcategory;
} exheader_arm11systemlocalcaps;
typedef struct
{
u8 descriptors[28][4];
u8 reserved[0x10];
} exheader_arm11kernelcapabilities;
typedef struct
{
u8 descriptors[15];
u8 descversion;
} exheader_arm9accesscontrol;
typedef struct
{
// systemcontrol info {
// coreinfo {
exheader_codesetinfo codesetinfo;
exheader_dependencylist deplist;
// }
exheader_systeminfo systeminfo;
// }
// accesscontrolinfo {
exheader_arm11systemlocalcaps arm11systemlocalcaps;
exheader_arm11kernelcapabilities arm11kernelcaps;
exheader_arm9accesscontrol arm9accesscontrol;
// }
struct {
u8 signature[0x100];
u8 ncchpubkeymodulus[0x100];
exheader_arm11systemlocalcaps arm11systemlocalcaps;
exheader_arm11kernelcapabilities arm11kernelcaps;
exheader_arm9accesscontrol arm9accesscontrol;
} accessdesc;
} exheader_header;
typedef struct
{
int haveread;
FILE* file;
settings* usersettings;
u8 partitionid[8];
u8 programid[8];
u8 counter[16];
u8 key[16];
u32 offset;
u32 size;
exheader_header header;
ctr_aes_context aes;
ctr_rsa_context rsa;
int compressedflag;
int encrypted;
int validprogramid;
int validpriority;
int validaffinitymask;
int validsignature;
} exheader_context;
void exheader_init(exheader_context* ctx);
void exheader_set_file(exheader_context* ctx, FILE* file);
void exheader_set_offset(exheader_context* ctx, u32 offset);
void exheader_set_size(exheader_context* ctx, u32 size);
void exheader_set_partitionid(exheader_context* ctx, u8 partitionid[8]);
void exheader_set_counter(exheader_context* ctx, u8 counter[16]);
void exheader_set_programid(exheader_context* ctx, u8 programid[8]);
void exheader_set_encrypted(exheader_context* ctx, u32 encrypted);
void exheader_set_key(exheader_context* ctx, u8 key[16]);
void exheader_set_usersettings(exheader_context* ctx, settings* usersettings);
int exheader_get_compressedflag(exheader_context* ctx);
void exheader_read(exheader_context* ctx, u32 actions);
int exheader_process(exheader_context* ctx, u32 actions);
void exheader_print(exheader_context* ctx);
void exheader_verify(exheader_context* ctx);
int exheader_programid_valid(exheader_context* ctx);
void exheader_determine_key(exheader_context* ctx, u32 actions);
#endif // _EXHEADER_H_

90
ctrtool/filepath.c Normal file
View File

@ -0,0 +1,90 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "types.h"
#include "filepath.h"
void filepath_init(filepath* fpath)
{
fpath->valid = 0;
}
void filepath_copy(filepath* fpath, filepath* copy)
{
if (copy != 0 && copy->valid)
memcpy(fpath, copy, sizeof(filepath));
else
memset(fpath, 0, sizeof(filepath));
}
void filepath_append_utf16(filepath* fpath, const u8* name)
{
u32 size;
if (fpath->valid == 0)
return;
size = strlen(fpath->pathname);
if (size > 0 && size < (MAX_PATH-1))
{
if (fpath->pathname[size-1] != PATH_SEPERATOR)
fpath->pathname[size++] = PATH_SEPERATOR;
}
while(size < (MAX_PATH-1))
{
u8 lo = *name++;
u8 hi = *name++;
u16 code = (hi<<8) | lo;
if (code == 0)
break;
// convert non-ANSI to '#', because unicode support is too much work
if (code > 0x7F)
code = '#';
fpath->pathname[size++] = code;
}
fpath->pathname[size] = 0;
if (size >= (MAX_PATH-1))
fpath->valid = 0;
}
void filepath_append(filepath* fpath, const char* format, ...)
{
char tmppath[MAX_PATH];
va_list args;
if (fpath->valid == 0)
return;
memset(tmppath, 0, MAX_PATH);
va_start(args, format);
vsprintf(tmppath, format, args);
va_end(args);
strcat(fpath->pathname, "/");
strcat(fpath->pathname, tmppath);
}
void filepath_set(filepath* fpath, const char* path)
{
fpath->valid = 1;
memset(fpath->pathname, 0, MAX_PATH);
strncpy(fpath->pathname, path, MAX_PATH);
}
const char* filepath_get(filepath* fpath)
{
if (fpath->valid == 0)
return 0;
else
return fpath->pathname;
}

20
ctrtool/filepath.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _FILEPATH_H_
#define _FILEPATH_H_
#include "types.h"
#include "utils.h"
typedef struct
{
char pathname[MAX_PATH];
int valid;
} filepath;
void filepath_init(filepath* fpath);
void filepath_copy(filepath* fpath, filepath* copy);
void filepath_append_utf16(filepath* fpath, const u8* name);
void filepath_append(filepath* fpath, const char* format, ...);
void filepath_set(filepath* fpath, const char* path);
const char* filepath_get(filepath* fpath);
#endif // _FILEPATH_H_

254
ctrtool/firm.c Normal file
View File

@ -0,0 +1,254 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "firm.h"
#include "utils.h"
void firm_init(firm_context* ctx)
{
memset(ctx, 0, sizeof(firm_context));
}
void firm_set_file(firm_context* ctx, FILE* file)
{
ctx->file = file;
}
void firm_set_offset(firm_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void firm_set_size(firm_context* ctx, u32 size)
{
ctx->size = size;
}
void firm_set_usersettings(firm_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void firm_save(firm_context* ctx, u32 index, u32 flags)
{
firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + index);
u32 offset;
u32 size;
u32 address;
FILE* fout;
filepath outpath;
u8 buffer[16 * 1024];
offset = getle32(section->offset);
size = getle32(section->size);
address = getle32(section->address);
filepath_copy(&outpath, settings_get_firm_dir_path(ctx->usersettings));
filepath_append(&outpath, "firm_%d_%08X.bin", index, address);
if (size == 0 || outpath.valid == 0)
return;
if (size >= ctx->size)
{
fprintf(stderr, "Error, firm section %d size invalid\n", index);
return;
}
fout = fopen(outpath.pathname, "wb");
if (fout == 0)
{
fprintf(stderr, "Error, failed to create file %s\n", outpath.pathname);
goto clean;
}
fseek(ctx->file, ctx->offset + offset, SEEK_SET);
fprintf(stdout, "Saving section %d to %s...\n", index, outpath.pathname);
while(size)
{
u32 max = sizeof(buffer);
if (max > size)
max = size;
if (max != fread(buffer, 1, max, ctx->file))
{
fprintf(stdout, "Error reading input file\n");
goto clean;
}
if (max != fwrite(buffer, 1, max, fout))
{
fprintf(stdout, "Error writing output file\n");
goto clean;
}
size -= max;
}
clean:
return;
}
void firm_process(firm_context* ctx, u32 actions)
{
u32 i;
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(&ctx->header, 1, sizeof(firm_header), ctx->file);
if (getle32(ctx->header.magic) != MAGIC_FIRM)
{
fprintf(stdout, "Error, FIRM segment corrupted\n");
return;
}
if (actions & VerifyFlag)
{
firm_verify(ctx, actions);
firm_signature_verify(ctx);
}
if (actions & InfoFlag)
{
firm_print(ctx);
}
if (actions & ExtractFlag)
{
filepath* dirpath = settings_get_firm_dir_path(ctx->usersettings);
if (dirpath && dirpath->valid)
{
makedir(dirpath->pathname);
for(i=0; i<4; i++)
firm_save(ctx, i, actions);
}
}
}
int firm_verify(firm_context* ctx, u32 flags)
{
unsigned int i;
u32 offset;
u32 size;
u8 buffer[16 * 1024];
u8 hash[0x20];
for(i=0; i<4; i++)
{
firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + i);
offset = getle32(section->offset);
size = getle32(section->size);
if (size == 0)
return 0;
fseek(ctx->file, ctx->offset + offset, SEEK_SET);
ctr_sha_256_init(&ctx->sha);
while(size)
{
u32 max = sizeof(buffer);
if (max > size)
max = size;
if (max != fread(buffer, 1, max, ctx->file))
{
fprintf(stdout, "Error reading input file\n");
goto clean;
}
ctr_sha_256_update(&ctx->sha, buffer, max);
size -= max;
}
ctr_sha_256_finish(&ctx->sha, hash);
if (memcmp(hash, section->hash, 0x20) == 0)
ctx->hashcheck[i] = Good;
else
ctx->hashcheck[i] = Fail;
}
clean:
return 0;
}
void firm_signature_verify(firm_context* ctx)
{
u8 hash[0x20];
if (ctx->usersettings)
{
ctr_sha_256(ctx->header.magic, 0x100, hash);
ctx->headersigcheck = ctr_rsa_verify_hash(ctx->header.signature, hash, &ctx->usersettings->keys.firmrsakey);
}
}
void firm_print(firm_context* ctx)
{
u32 i;
u32 address;
u32 type;
u32 offset;
u32 size;
u32 entrypointarm11 = getle32(ctx->header.entrypointarm11);
u32 entrypointarm9 = getle32(ctx->header.entrypointarm9);
fprintf(stdout, "\nFIRM:\n");
if (ctx->headersigcheck == Unchecked)
memdump(stdout, "Signature: ", ctx->header.signature, 0x100);
else if (ctx->headersigcheck == Good)
memdump(stdout, "Signature (GOOD): ", ctx->header.signature, 0x100);
else
memdump(stdout, "Signature (FAIL): ", ctx->header.signature, 0x100);
fprintf(stdout, "\n");
fprintf(stdout, "Entrypoint ARM9: 0x%08X\n", entrypointarm9);
fprintf(stdout, "Entrypoint ARM11: 0x%08X\n", entrypointarm11);
fprintf(stdout, "\n");
for(i=0; i<4; i++)
{
firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + i);
offset = getle32(section->offset);
size = getle32(section->size);
address = getle32(section->address);
type = getle32(section->type);
if (size)
{
fprintf(stdout, "Section %d \n", i);
fprintf(stdout, " Type: %s\n", type==0? "ARM9" : type==1? "ARM11" : "UNKNOWN");
fprintf(stdout, " Address: 0x%08X\n", address);
fprintf(stdout, " Offset: 0x%08X\n", offset);
fprintf(stdout, " Size: 0x%08X\n", size);
if (ctx->hashcheck[i] == Good)
memdump(stdout, " Hash (GOOD): ", section->hash, 0x20);
else if (ctx->hashcheck[i] == Fail)
memdump(stdout, " Hash (FAIL): ", section->hash, 0x20);
else
memdump(stdout, " Hash: ", section->hash, 0x20);
}
}
}

57
ctrtool/firm.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef _FIRM_H_
#define _FIRM_H_
#include "types.h"
#include "info.h"
#include "ctr.h"
#include "filepath.h"
#include "settings.h"
typedef struct
{
u8 offset[4];
u8 address[4];
u8 size[4];
u8 type[4];
u8 hash[32];
} firm_sectionheader;
typedef struct
{
u8 magic[4];
u8 reserved1[4];
u8 entrypointarm11[4];
u8 entrypointarm9[4];
u8 reserved2[0x30];
firm_sectionheader section[4];
u8 signature[0x100];
} firm_header;
typedef struct
{
FILE* file;
settings* usersettings;
u32 offset;
u32 size;
firm_header header;
ctr_sha256_context sha;
int hashcheck[4];
int headersigcheck;
} firm_context;
void firm_init(firm_context* ctx);
void firm_set_file(firm_context* ctx, FILE* file);
void firm_set_offset(firm_context* ctx, u32 offset);
void firm_set_size(firm_context* ctx, u32 size);
void firm_set_usersettings(firm_context* ctx, settings* usersettings);
void firm_process(firm_context* ctx, u32 actions);
void firm_print(firm_context* ctx);
void firm_save(firm_context* ctx, u32 index, u32 flags);
int firm_verify(firm_context* ctx, u32 flags);
void firm_signature_verify(firm_context* ctx);
#endif // _FIRM_H_

16
ctrtool/info.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _INFO_H_
#define _INFO_H_
#include "types.h"
#include "keyset.h"
typedef struct
{
FILE* file;
keyset* keys;
u32 offset;
const u8* blob;
u32 blobsize;
} infocontext;
#endif // _INFO_H_

187
ctrtool/ivfc.c Normal file
View File

@ -0,0 +1,187 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "types.h"
#include "utils.h"
#include "ivfc.h"
#include "ctr.h"
void ivfc_init(ivfc_context* ctx)
{
memset(ctx, 0, sizeof(ivfc_context));
}
void ivfc_set_usersettings(ivfc_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void ivfc_set_offset(ivfc_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void ivfc_set_size(ivfc_context* ctx, u32 size)
{
ctx->size = size;
}
void ivfc_set_file(ivfc_context* ctx, FILE* file)
{
ctx->file = file;
}
void ivfc_process(ivfc_context* ctx, u32 actions)
{
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(&ctx->header, 1, sizeof(ivfc_header), ctx->file);
if (getle32(ctx->header.magic) != MAGIC_IVFC)
{
fprintf(stdout, "Error, IVFC segment corrupted\n");
return;
}
if (getle32(ctx->header.id) == 0x10000)
{
fread(&ctx->romfsheader, 1, sizeof(ivfc_header_romfs), ctx->file);
ctx->levelcount = 3;
ctx->level[2].hashblocksize = 1 << getle32(ctx->romfsheader.level3.blocksize);
ctx->level[1].hashblocksize = 1 << getle32(ctx->romfsheader.level2.blocksize);
ctx->level[0].hashblocksize = 1 << getle32(ctx->romfsheader.level1.blocksize);
ctx->level[0].hashoffset = 0x60;
ctx->bodyoffset = align64(ctx->level[0].hashoffset + getle32(ctx->romfsheader.masterhashsize), ctx->level[2].hashblocksize);
ctx->bodysize = getle64(ctx->romfsheader.level3.hashdatasize);
ctx->level[2].dataoffset = ctx->bodyoffset;
ctx->level[2].datasize = align64(ctx->bodysize, ctx->level[2].hashblocksize);
ctx->level[1].hashoffset = align64(ctx->bodyoffset + ctx->bodysize, ctx->level[2].hashblocksize);
ctx->level[2].hashoffset = ctx->level[1].hashoffset + getle64(ctx->romfsheader.level2.logicaloffset) - getle64(ctx->romfsheader.level1.logicaloffset);
ctx->level[1].dataoffset = ctx->level[2].hashoffset;
ctx->level[1].datasize = align64(getle64(ctx->romfsheader.level2.hashdatasize), ctx->level[1].hashblocksize);
ctx->level[0].dataoffset = ctx->level[1].hashoffset;
ctx->level[0].datasize = align64(getle64(ctx->romfsheader.level1.hashdatasize), ctx->level[0].hashblocksize);
}
if (actions & VerifyFlag)
ivfc_verify(ctx, actions);
if (actions & InfoFlag)
ivfc_print(ctx);
}
void ivfc_verify(ivfc_context* ctx, u32 flags)
{
u32 i, j;
u32 blockcount;
for(i=0; i<ctx->levelcount; i++)
{
ivfc_level* level = ctx->level + i;
level->hashcheck = Fail;
}
for(i=0; i<ctx->levelcount; i++)
{
ivfc_level* level = ctx->level + i;
blockcount = level->datasize / level->hashblocksize;
if (blockcount * level->hashblocksize != level->datasize)
{
fprintf(stderr, "Error, IVFC block size mismatch\n");
return;
}
level->hashcheck = Good;
for(j=0; j<blockcount; j++)
{
u8 calchash[32];
u8 testhash[32];
ivfc_hash(ctx, level->dataoffset + level->hashblocksize * j, level->hashblocksize, calchash);
ivfc_read(ctx, level->hashoffset + 0x20 * j, 0x20, testhash);
if (memcmp(calchash, testhash, 0x20) != 0)
level->hashcheck = Fail;
}
}
}
void ivfc_read(ivfc_context* ctx, u32 offset, u32 size, u8* buffer)
{
if ( (offset > ctx->size) || (offset+size > ctx->size) )
{
fprintf(stderr, "Error, IVFC offset out of range (offset=0x%08x, size=0x%08x)\n", offset, size);
return;
}
fseek(ctx->file, ctx->offset + offset, SEEK_SET);
if (size != fread(buffer, 1, size, ctx->file))
{
fprintf(stderr, "Error, IVFC could not read file\n");
return;
}
}
void ivfc_hash(ivfc_context* ctx, u32 offset, u32 size, u8* hash)
{
if (size > IVFC_MAX_BUFFERSIZE)
{
fprintf(stderr, "Error, IVFC hash block size too big.\n");
return;
}
ivfc_read(ctx, offset, size, ctx->buffer);
ctr_sha_256(ctx->buffer, size, hash);
}
void ivfc_print(ivfc_context* ctx)
{
u32 i;
ivfc_header* header = &ctx->header;
fprintf(stdout, "\nIVFC:\n");
fprintf(stdout, "Header: %c%c%c%c\n", header->magic[0], header->magic[1], header->magic[2], header->magic[3]);
fprintf(stdout, "Id: %08x\n", getle32(header->id));
for(i=0; i<ctx->levelcount; i++)
{
ivfc_level* level = ctx->level + i;
fprintf(stdout, "\n");
if (level->hashcheck == Unchecked)
fprintf(stdout, "Level %d: \n", i);
else
fprintf(stdout, "Level %d (%s): \n", i, level->hashcheck == Good? "GOOD" : "FAIL");
fprintf(stdout, " Data offset: 0x%016llx\n", ctx->offset + level->dataoffset);
fprintf(stdout, " Data size: 0x%016llx\n", level->datasize);
fprintf(stdout, " Hash offset: 0x%016llx\n", ctx->offset + level->hashoffset);
fprintf(stdout, " Hash block size: 0x%08x\n", level->hashblocksize);
}
}
u64 ivfc_get_body_offset(ivfc_context* ctx)
{
return ctx->bodyoffset;
}
u64 ivfc_get_body_size(ivfc_context* ctx)
{
return ctx->bodysize;
}

72
ctrtool/ivfc.h Normal file
View File

@ -0,0 +1,72 @@
#ifndef __IVFC_H__
#define __IVFC_H__
#include "types.h"
#include "settings.h"
#define IVFC_MAX_LEVEL 4
#define IVFC_MAX_BUFFERSIZE 0x4000
typedef struct
{
u8 magic[4];
u8 id[4];
} ivfc_header;
typedef struct
{
u8 logicaloffset[8];
u8 hashdatasize[8];
u8 blocksize[4];
u8 reserved[4];
} ivfc_levelheader;
typedef struct
{
u64 dataoffset;
u64 datasize;
u64 hashoffset;
u32 hashblocksize;
int hashcheck;
} ivfc_level;
typedef struct
{
u8 masterhashsize[4];
ivfc_levelheader level1;
ivfc_levelheader level2;
ivfc_levelheader level3;
u8 reserved[4];
u8 optionalsize[4];
} ivfc_header_romfs;
typedef struct
{
FILE* file;
u32 offset;
u32 size;
settings* usersettings;
ivfc_header header;
ivfc_header_romfs romfsheader;
u32 levelcount;
ivfc_level level[IVFC_MAX_LEVEL];
u64 bodyoffset;
u64 bodysize;
u8 buffer[IVFC_MAX_BUFFERSIZE];
} ivfc_context;
void ivfc_init(ivfc_context* ctx);
void ivfc_process(ivfc_context* ctx, u32 actions);
void ivfc_set_offset(ivfc_context* ctx, u32 offset);
void ivfc_set_size(ivfc_context* ctx, u32 size);
void ivfc_set_file(ivfc_context* ctx, FILE* file);
void ivfc_set_usersettings(ivfc_context* ctx, settings* usersettings);
void ivfc_verify(ivfc_context* ctx, u32 flags);
void ivfc_print(ivfc_context* ctx);
void ivfc_read(ivfc_context* ctx, u32 offset, u32 size, u8* buffer);
void ivfc_hash(ivfc_context* ctx, u32 offset, u32 size, u8* hash);
#endif // __IVFC_H__

262
ctrtool/keyset.cpp Normal file
View File

@ -0,0 +1,262 @@
#include <stdio.h>
#include "keyset.h"
#include "utils.h"
#include "tinyxml/tinyxml.h"
static void keyset_set_key128(key128* key, unsigned char* keydata);
static void keyset_parse_key128(key128* key, char* keytext, int keylen);
static int keyset_parse_key(const char* text, unsigned int textlen, unsigned char* key, unsigned int size, int* valid);
static int keyset_load_rsakey2048(TiXmlElement* elem, rsakey2048* key);
static int keyset_load_key128(TiXmlHandle node, key128* key);
static int keyset_load_key(TiXmlHandle node, unsigned char* key, unsigned int maxsize, int* valid);
static int ishex(char c)
{
if (c >= '0' && c <= '9')
return 1;
if (c >= 'A' && c <= 'F')
return 1;
if (c >= 'a' && c <= 'f')
return 1;
return 0;
}
static unsigned char hextobin(char c)
{
if (c >= '0' && c <= '9')
return c-'0';
if (c >= 'A' && c <= 'F')
return c-'A'+0xA;
if (c >= 'a' && c <= 'f')
return c-'a'+0xA;
return 0;
}
void keyset_init(keyset* keys)
{
memset(keys, 0, sizeof(keyset));
}
int keyset_load_key(TiXmlHandle node, unsigned char* key, unsigned int size, int* valid)
{
TiXmlElement* elem = node.ToElement();
if (valid)
*valid = 0;
if (!elem)
return 0;
const char* text = elem->GetText();
unsigned int textlen = strlen(text);
int status = keyset_parse_key(text, textlen, key, size, valid);
if (status == KEY_ERR_LEN_MISMATCH)
{
fprintf(stderr, "Error size mismatch for key \"%s/%s\"\n", elem->Parent()->Value(), elem->Value());
return 0;
}
return 1;
}
int keyset_parse_key(const char* text, unsigned int textlen, unsigned char* key, unsigned int size, int* valid)
{
unsigned int i, j;
unsigned int hexcount = 0;
if (valid)
*valid = 0;
for(i=0; i<textlen; i++)
{
if (ishex(text[i]))
hexcount++;
}
if (hexcount != size*2)
{
fprintf(stdout, "Error, expected %d hex characters when parsing text \"", size*2);
for(i=0; i<textlen; i++)
fprintf(stdout, "%c", text[i]);
fprintf(stdout, "\"\n");
return KEY_ERR_LEN_MISMATCH;
}
for(i=0, j=0; i<textlen; i++)
{
if (ishex(text[i]))
{
if ( (j&1) == 0 )
key[j/2] = hextobin(text[i])<<4;
else
key[j/2] |= hextobin(text[i]);
j++;
}
}
if (valid)
*valid = 1;
return KEY_OK;
}
int keyset_load_key128(TiXmlHandle node, key128* key)
{
return keyset_load_key(node, key->data, sizeof(key->data), &key->valid);
}
int keyset_load_rsakey2048(TiXmlHandle node, rsakey2048* key)
{
key->keytype = RSAKEY_INVALID;
if (!keyset_load_key(node.FirstChild("N"), key->n, sizeof(key->n), 0))
goto clean;
if (!keyset_load_key(node.FirstChild("E"), key->e, sizeof(key->e), 0))
goto clean;
key->keytype = RSAKEY_PUB;
if (!keyset_load_key(node.FirstChild("D"), key->d, sizeof(key->d), 0))
goto clean;
if (!keyset_load_key(node.FirstChild("P"), key->p, sizeof(key->p), 0))
goto clean;
if (!keyset_load_key(node.FirstChild("Q"), key->q, sizeof(key->q), 0))
goto clean;
if (!keyset_load_key(node.FirstChild("DP"), key->dp, sizeof(key->dp), 0))
goto clean;
if (!keyset_load_key(node.FirstChild("DQ"), key->dq, sizeof(key->dq), 0))
goto clean;
if (!keyset_load_key(node.FirstChild("QP"), key->qp, sizeof(key->qp), 0))
goto clean;
key->keytype = RSAKEY_PRIV;
clean:
return (key->keytype != RSAKEY_INVALID);
}
int keyset_load(keyset* keys, const char* fname, int verbose)
{
TiXmlDocument doc(fname);
bool loadOkay = doc.LoadFile();
if (!loadOkay)
{
if (verbose)
fprintf(stderr, "Could not load keyset file \"%s\", error: %s.\n", fname, doc.ErrorDesc() );
return 0;
}
TiXmlHandle root = doc.FirstChild("document");
keyset_load_rsakey2048(root.FirstChild("ncsdrsakey"), &keys->ncsdrsakey);
keyset_load_rsakey2048(root.FirstChild("ncchrsakey"), &keys->ncchrsakey);
keyset_load_rsakey2048(root.FirstChild("ncchdescrsakey"), &keys->ncchdescrsakey);
keyset_load_rsakey2048(root.FirstChild("firmrsakey"), &keys->firmrsakey);
keyset_load_key128(root.FirstChild("commonkey"), &keys->commonkey);
keyset_load_key128(root.FirstChild("ncchkey"), &keys->ncchkey);
keyset_load_key128(root.FirstChild("ncchfixedsystemkey"), &keys->ncchfixedsystemkey);
return 1;
}
void keyset_merge(keyset* keys, keyset* src)
{
if (src->ncchkey.valid)
keyset_set_key128(&keys->ncchkey, src->ncchkey.data);
if (src->ncchfixedsystemkey.valid)
keyset_set_key128(&keys->ncchfixedsystemkey, src->ncchfixedsystemkey.data);
if (src->commonkey.valid)
keyset_set_key128(&keys->commonkey, src->commonkey.data);
}
void keyset_set_key128(key128* key, unsigned char* keydata)
{
memcpy(key->data, keydata, 16);
key->valid = 1;
}
void keyset_parse_key128(key128* key, char* keytext, int keylen)
{
keyset_parse_key(keytext, keylen, key->data, 16, &key->valid);
}
void keyset_set_commonkey(keyset* keys, unsigned char* keydata)
{
keyset_set_key128(&keys->commonkey, keydata);
}
void keyset_parse_commonkey(keyset* keys, char* keytext, int keylen)
{
keyset_parse_key128(&keys->commonkey, keytext, keylen);
}
void keyset_set_ncchkey(keyset* keys, unsigned char* keydata)
{
keyset_set_key128(&keys->ncchkey, keydata);
}
void keyset_parse_ncchkey(keyset* keys, char* keytext, int keylen)
{
keyset_parse_key128(&keys->ncchkey, keytext, keylen);
}
void keyset_set_ncchfixedsystemkey(keyset* keys, unsigned char* keydata)
{
keyset_set_key128(&keys->ncchfixedsystemkey, keydata);
}
void keyset_parse_ncchfixedsystemkey(keyset* keys, char* keytext, int keylen)
{
keyset_parse_key128(&keys->ncchfixedsystemkey, keytext, keylen);
}
void keyset_dump_rsakey(rsakey2048* key, const char* keytitle)
{
if (key->keytype == RSAKEY_INVALID)
return;
fprintf(stdout, "%s\n", keytitle);
memdump(stdout, "Modulus: ", key->n, 256);
memdump(stdout, "Exponent: ", key->e, 3);
if (key->keytype == RSAKEY_PRIV)
{
memdump(stdout, "P: ", key->p, 128);
memdump(stdout, "Q: ", key->q, 128);
}
fprintf(stdout, "\n");
}
void keyset_dump_key128(key128* key, const char* keytitle)
{
if (key->valid)
{
fprintf(stdout, "%s\n", keytitle);
memdump(stdout, "", key->data, 16);
fprintf(stdout, "\n");
}
}
void keyset_dump(keyset* keys)
{
fprintf(stdout, "Current keyset: \n");
keyset_dump_key128(&keys->ncchkey, "NCCH KEY");
keyset_dump_key128(&keys->ncchfixedsystemkey, "NCCH FIXEDSYSTEMKEY");
keyset_dump_key128(&keys->commonkey, "COMMON KEY");
keyset_dump_rsakey(&keys->ncsdrsakey, "NCSD RSA KEY");
keyset_dump_rsakey(&keys->ncchdescrsakey, "NCCH DESC RSA KEY");
fprintf(stdout, "\n");
}

70
ctrtool/keyset.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef _KEYSET_H_
#define _KEYSET_H_
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
KEY_ERR_LEN_MISMATCH,
KEY_ERR_INVALID_NODE,
KEY_OK
} keystatus;
typedef enum
{
RSAKEY_INVALID,
RSAKEY_PRIV,
RSAKEY_PUB
} rsakeytype;
typedef struct
{
unsigned char n[256];
unsigned char e[3];
unsigned char d[256];
unsigned char p[128];
unsigned char q[128];
unsigned char dp[128];
unsigned char dq[128];
unsigned char qp[128];
rsakeytype keytype;
} rsakey2048;
typedef struct
{
unsigned char data[16];
int valid;
} key128;
typedef struct
{
key128 commonkey;
key128 ncchkey;
key128 ncchfixedsystemkey;
rsakey2048 ncsdrsakey;
rsakey2048 ncchrsakey;
rsakey2048 ncchdescrsakey;
rsakey2048 firmrsakey;
} keyset;
void keyset_init(keyset* keys);
int keyset_load(keyset* keys, const char* fname, int verbose);
void keyset_merge(keyset* keys, keyset* src);
void keyset_set_commonkey(keyset* keys, unsigned char* keydata);
void keyset_parse_commonkey(keyset* keys, char* keytext, int keylen);
void keyset_set_ncchkey(keyset* keys, unsigned char* keydata);
void keyset_parse_ncchkey(keyset* keys, char* keytext, int keylen);
void keyset_set_ncchfixedsystemkey(keyset* keys, unsigned char* keydata);
void keyset_parse_ncchfixedsystemkey(keyset* keys, char* keytext, int keylen);
void keyset_dump(keyset* keys);
#ifdef __cplusplus
}
#endif
#endif // _KEYSET_H_

195
ctrtool/lzss.c Normal file
View File

@ -0,0 +1,195 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "types.h"
#include "utils.h"
#include "lzss.h"
void lzss_init(lzss_context* ctx)
{
memset(ctx, 0, sizeof(lzss_context));
}
void lzss_set_usersettings(lzss_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void lzss_set_offset(lzss_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void lzss_set_size(lzss_context* ctx, u32 size)
{
ctx->size = size;
}
void lzss_set_file(lzss_context* ctx, FILE* file)
{
ctx->file = file;
}
void lzss_process(lzss_context* ctx, u32 actions)
{
unsigned int compressedsize;
unsigned char* compressedbuffer = 0;
unsigned int decompressedsize;
unsigned char* decompressedbuffer = 0;
FILE* fout = 0;
fseek(ctx->file, ctx->offset, SEEK_SET);
if (actions & ExtractFlag)
{
filepath* path = settings_get_lzss_path(ctx->usersettings);
if (path == 0 || path->valid == 0)
goto clean;
fout = fopen(path->pathname, "wb");
if (0 == fout)
{
fprintf(stdout, "Error opening out file %s\n", path->pathname);
goto clean;
}
compressedsize = ctx->size;
compressedbuffer = malloc(compressedsize);
if (1 != fread(compressedbuffer, compressedsize, 1, ctx->file))
{
fprintf(stdout, "Error read input file\n");
goto clean;
}
decompressedsize = lzss_get_decompressed_size(compressedbuffer, compressedsize);
decompressedbuffer = malloc(decompressedsize);
printf("Compressed: %d\n", compressedsize);
printf("Decompressed: %d\n", decompressedsize);
if (decompressedbuffer == 0)
{
fprintf(stdout, "Error allocating memory\n");
goto clean;
}
if (0 == lzss_decompress(compressedbuffer, compressedsize, decompressedbuffer, decompressedsize))
goto clean;
printf("Saving decompressed lzss blob to %s...\n", path->pathname);
if (decompressedsize != fwrite(decompressedbuffer, 1, decompressedsize, fout))
{
fprintf(stdout, "Error writing output file\n");
goto clean;
}
}
clean:
free(decompressedbuffer);
free(compressedbuffer);
if (fout)
fclose(fout);
}
u32 lzss_get_decompressed_size(u8* compressed, u32 compressedsize)
{
u8* footer = compressed + compressedsize - 8;
//u32 buffertopandbottom = getle32(footer+0);
u32 originalbottom = getle32(footer+4);
return originalbottom + compressedsize;
}
int lzss_decompress(u8* compressed, u32 compressedsize, u8* decompressed, u32 decompressedsize)
{
u8* footer = compressed + compressedsize - 8;
u32 buffertopandbottom = getle32(footer+0);
//u32 originalbottom = getle32(footer+4);
u32 i, j;
u32 out = decompressedsize;
u32 index = compressedsize - ((buffertopandbottom>>24)&0xFF);
u32 segmentoffset;
u32 segmentsize;
u8 control;
u32 stopindex = compressedsize - (buffertopandbottom&0xFFFFFF);
memset(decompressed, 0, decompressedsize);
memcpy(decompressed, compressed, compressedsize);
while(index > stopindex)
{
control = compressed[--index];
for(i=0; i<8; i++)
{
if (index <= stopindex)
break;
if (index <= 0)
break;
if (out <= 0)
break;
if (control & 0x80)
{
if (index < 2)
{
fprintf(stderr, "Error, compression out of bounds\n");
goto clean;
}
index -= 2;
segmentoffset = compressed[index] | (compressed[index+1]<<8);
segmentsize = ((segmentoffset >> 12)&15)+3;
segmentoffset &= 0x0FFF;
segmentoffset += 2;
if (out < segmentsize)
{
fprintf(stderr, "Error, compression out of bounds\n");
goto clean;
}
for(j=0; j<segmentsize; j++)
{
u8 data;
if (out+segmentoffset >= decompressedsize)
{
fprintf(stderr, "Error, compression out of bounds\n");
goto clean;
}
data = decompressed[out+segmentoffset];
decompressed[--out] = data;
}
}
else
{
if (out < 1)
{
fprintf(stderr, "Error, compression out of bounds\n");
goto clean;
}
decompressed[--out] = compressed[--index];
}
control <<= 1;
}
}
return 1;
clean:
return 0;
}

26
ctrtool/lzss.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _LZSS_H_
#define _LZSS_H_
#include "types.h"
#include "settings.h"
typedef struct
{
FILE* file;
u32 offset;
u32 size;
settings* usersettings;
} lzss_context;
void lzss_init(lzss_context* ctx);
void lzss_process(lzss_context* ctx, u32 actions);
void lzss_set_offset(lzss_context* ctx, u32 offset);
void lzss_set_size(lzss_context* ctx, u32 size);
void lzss_set_file(lzss_context* ctx, FILE* file);
void lzss_set_usersettings(lzss_context* ctx, settings* usersettings);
u32 lzss_get_decompressed_size(u8* compressed, u32 compressedsize);
int lzss_decompress(u8* compressed, u32 compressedsize, u8* decompressed, u32 decompressedsize);
#endif // _LZSS_H_

444
ctrtool/main.c Normal file
View File

@ -0,0 +1,444 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "utils.h"
#include "ctr.h"
#include "ncch.h"
#include "ncsd.h"
#include "cia.h"
#include "tmd.h"
#include "tik.h"
#include "lzss.h"
#include "keyset.h"
#include "exefs.h"
#include "info.h"
#include "settings.h"
#include "firm.h"
#include "cwav.h"
#include "romfs.h"
enum cryptotype
{
Plain,
CTR,
CBC
};
typedef struct
{
int actions;
u32 filetype;
FILE* infile;
u32 infilesize;
settings usersettings;
} toolcontext;
static void usage(const char *argv0)
{
fprintf(stderr,
"Usage: %s [options...] <file>\n"
"CTRTOOL (c) neimod.\n"
"\n"
"Options:\n"
" -i, --info Show file info.\n"
" This is the default action.\n"
" -x, --extract Extract data from file.\n"
" This is also the default action.\n"
" -p, --plain Extract data without decrypting.\n"
" -r, --raw Keep raw data, don't unpack.\n"
" -k, --keyset=file Specify keyset file.\n"
" -v, --verbose Give verbose output.\n"
" -y, --verify Verify hashes and signatures.\n"
" --unitsize=size Set media unit size (default 0x200).\n"
" --commonkey=key Set common key.\n"
" --ncchkey=key Set ncch key.\n"
" --ncchsyskey=key Set ncch fixed system key.\n"
" --showkeys Show the keys being used.\n"
" -t, --intype=type Specify input file type [ncsd, ncch, exheader, cia, tmd, lzss,\n"
" firm, cwav, romfs]\n"
"LZSS options:\n"
" --lzssout=file Specify lzss output file\n"
"CXI/CCI options:\n"
" -n, --ncch=offs Specify offset for NCCH header.\n"
" --exefs=file Specify ExeFS file path.\n"
" --exefsdir=dir Specify ExeFS directory path.\n"
" --romfs=file Specify RomFS file path.\n"
" --exheader=file Specify Extended Header file path.\n"
"CIA options:\n"
" --certs=file Specify Certificate chain file path.\n"
" --tik=file Specify Ticket file path.\n"
" --tmd=file Specify TMD file path.\n"
" --contents=file Specify Contents file path.\n"
" --meta=file Specify Meta file path.\n"
"FIRM options:\n"
" --firmdir=dir Specify Firm directory path.\n"
"CWAV options:\n"
" --wav=file Specify wav output file.\n"
" --wavloops=count Specify wav loop count, default 0.\n"
"ROMFS options:\n"
" --romfsdir=dir Specify RomFS directory path.\n"
" --listromfs List files in RomFS.\n"
"\n",
argv0);
exit(1);
}
int main(int argc, char* argv[])
{
toolcontext ctx;
u8 magic[4];
char infname[512];
int c;
u32 ncchoffset = ~0;
char keysetfname[512] = "keys.xml";
keyset tmpkeys;
unsigned int checkkeysetfile = 0;
memset(&ctx, 0, sizeof(toolcontext));
ctx.actions = InfoFlag | ExtractFlag;
ctx.filetype = FILETYPE_UNKNOWN;
settings_init(&ctx.usersettings);
keyset_init(&ctx.usersettings.keys);
keyset_init(&tmpkeys);
while (1)
{
int option_index;
static struct option long_options[] =
{
{"extract", 0, NULL, 'x'},
{"plain", 0, NULL, 'p'},
{"info", 0, NULL, 'i'},
{"exefs", 1, NULL, 0},
{"romfs", 1, NULL, 1},
{"exheader", 1, NULL, 2},
{"certs", 1, NULL, 3},
{"tik", 1, NULL, 4},
{"tmd", 1, NULL, 5},
{"contents", 1, NULL, 6},
{"meta", 1, NULL, 7},
{"exefsdir", 1, NULL, 8},
{"keyset", 1, NULL, 'k'},
{"ncch", 1, NULL, 'n'},
{"verbose", 0, NULL, 'v'},
{"verify", 0, NULL, 'y'},
{"raw", 0, NULL, 'r'},
{"unitsize", 1, NULL, 9},
{"showkeys", 0, NULL, 10},
{"commonkey", 1, NULL, 11},
{"ncchkey", 1, NULL, 12},
{"intype", 1, NULL, 't'},
{"lzssout", 1, NULL, 13},
{"firmdir", 1, NULL, 14},
{"ncchsyskey", 1, NULL, 15},
{"wav", 1, NULL, 16},
{"romfsdir", 1, NULL, 17},
{"listromfs", 0, NULL, 18},
{"wavloops", 1, NULL, 19},
{NULL},
};
c = getopt_long(argc, argv, "ryxivpk:n:t:", long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 'x':
ctx.actions |= ExtractFlag;
break;
case 'v':
ctx.actions |= VerboseFlag;
break;
case 'y':
ctx.actions |= VerifyFlag;
break;
case 'p':
ctx.actions |= PlainFlag;
break;
case 'r':
ctx.actions |= RawFlag;
break;
case 'i':
ctx.actions |= InfoFlag;
break;
case 'n':
ncchoffset = strtoul(optarg, 0, 0);
break;
case 'k':
strncpy(keysetfname, optarg, sizeof(keysetfname));
checkkeysetfile = 1;
break;
case 't':
if (!strcmp(optarg, "exheader"))
ctx.filetype = FILETYPE_EXHEADER;
else if (!strcmp(optarg, "ncch"))
ctx.filetype = FILETYPE_CXI;
else if (!strcmp(optarg, "ncsd"))
ctx.filetype = FILETYPE_CCI;
else if (!strcmp(optarg, "cia"))
ctx.filetype = FILETYPE_CIA;
else if (!strcmp(optarg, "tmd"))
ctx.filetype = FILETYPE_TMD;
else if (!strcmp(optarg, "lzss"))
ctx.filetype = FILETYPE_LZSS;
else if (!strcmp(optarg, "firm"))
ctx.filetype = FILETYPE_FIRM;
else if (!strcmp(optarg, "cwav"))
ctx.filetype = FILETYPE_CWAV;
else if (!strcmp(optarg, "romfs"))
ctx.filetype = FILETYPE_ROMFS;
break;
case 0: settings_set_exefs_path(&ctx.usersettings, optarg); break;
case 1: settings_set_romfs_path(&ctx.usersettings, optarg); break;
case 2: settings_set_exheader_path(&ctx.usersettings, optarg); break;
case 3: settings_set_certs_path(&ctx.usersettings, optarg); break;
case 4: settings_set_tik_path(&ctx.usersettings, optarg); break;
case 5: settings_set_tmd_path(&ctx.usersettings, optarg); break;
case 6: settings_set_content_path(&ctx.usersettings, optarg); break;
case 7: settings_set_content_path(&ctx.usersettings, optarg); break;
case 8: settings_set_exefs_dir_path(&ctx.usersettings, optarg); break;
case 9: settings_set_mediaunit_size(&ctx.usersettings, strtoul(optarg, 0, 0)); break;
case 10: ctx.actions |= ShowKeysFlag; break;
case 11: keyset_parse_commonkey(&tmpkeys, optarg, strlen(optarg)); break;
case 12: keyset_parse_ncchkey(&tmpkeys, optarg, strlen(optarg)); break;
case 13: settings_set_lzss_path(&ctx.usersettings, optarg); break;
case 14: settings_set_firm_dir_path(&ctx.usersettings, optarg); break;
case 15: keyset_parse_ncchfixedsystemkey(&tmpkeys, optarg, strlen(optarg)); break;
case 16: settings_set_wav_path(&ctx.usersettings, optarg); break;
case 17: settings_set_romfs_dir_path(&ctx.usersettings, optarg); break;
case 18: settings_set_list_romfs_files(&ctx.usersettings, 1); break;
case 19: settings_set_cwav_loopcount(&ctx.usersettings, strtoul(optarg, 0, 0)); break;
default:
usage(argv[0]);
}
}
if (optind == argc - 1)
{
// Exactly one extra argument - an input file
strncpy(infname, argv[optind], sizeof(infname));
}
else if ( (optind < argc) || (argc == 1) )
{
// Too many extra args
usage(argv[0]);
}
keyset_load(&ctx.usersettings.keys, keysetfname, (ctx.actions & VerboseFlag) | checkkeysetfile);
keyset_merge(&ctx.usersettings.keys, &tmpkeys);
if (ctx.actions & ShowKeysFlag)
keyset_dump(&ctx.usersettings.keys);
ctx.infile = fopen(infname, "rb");
if (ctx.infile == 0)
{
fprintf(stderr, "error: could not open input file!\n");
return -1;
}
fseek(ctx.infile, 0, SEEK_END);
ctx.infilesize = ftell(ctx.infile);
fseek(ctx.infile, 0, SEEK_SET);
if (ctx.filetype == FILETYPE_UNKNOWN)
{
fseek(ctx.infile, 0x100, SEEK_SET);
fread(&magic, 1, 4, ctx.infile);
switch(getle32(magic))
{
case MAGIC_NCCH:
ctx.filetype = FILETYPE_CXI;
break;
case MAGIC_NCSD:
ctx.filetype = FILETYPE_CCI;
break;
default:
break;
}
}
if (ctx.filetype == FILETYPE_UNKNOWN)
{
fseek(ctx.infile, 0, SEEK_SET);
fread(magic, 1, 4, ctx.infile);
switch(getle32(magic))
{
case 0x2020:
ctx.filetype = FILETYPE_CIA;
break;
case MAGIC_FIRM:
ctx.filetype = FILETYPE_FIRM;
break;
case MAGIC_CWAV:
ctx.filetype = FILETYPE_CWAV;
break;
case MAGIC_IVFC:
ctx.filetype = FILETYPE_ROMFS; // TODO: need to determine more here.. savegames use IVFC too, but is not ROMFS.
break;
}
}
if (ctx.filetype == FILETYPE_UNKNOWN)
{
fprintf(stdout, "Unknown file\n");
exit(1);
}
switch(ctx.filetype)
{
case FILETYPE_CCI:
{
ncsd_context ncsdctx;
ncsd_init(&ncsdctx);
ncsd_set_file(&ncsdctx, ctx.infile);
ncsd_set_size(&ncsdctx, ctx.infilesize);
ncsd_set_usersettings(&ncsdctx, &ctx.usersettings);
ncsd_process(&ncsdctx, ctx.actions);
break;
}
case FILETYPE_FIRM:
{
firm_context firmctx;
firm_init(&firmctx);
firm_set_file(&firmctx, ctx.infile);
firm_set_size(&firmctx, ctx.infilesize);
firm_set_usersettings(&firmctx, &ctx.usersettings);
firm_process(&firmctx, ctx.actions);
break;
}
case FILETYPE_CXI:
{
ncch_context ncchctx;
ncch_init(&ncchctx);
ncch_set_file(&ncchctx, ctx.infile);
ncch_set_size(&ncchctx, ctx.infilesize);
ncch_set_usersettings(&ncchctx, &ctx.usersettings);
ncch_process(&ncchctx, ctx.actions);
break;
}
case FILETYPE_CIA:
{
cia_context ciactx;
cia_init(&ciactx);
cia_set_file(&ciactx, ctx.infile);
cia_set_size(&ciactx, ctx.infilesize);
cia_set_usersettings(&ciactx, &ctx.usersettings);
cia_process(&ciactx, ctx.actions);
break;
}
case FILETYPE_EXHEADER:
{
exheader_context exheaderctx;
exheader_init(&exheaderctx);
exheader_set_file(&exheaderctx, ctx.infile);
exheader_set_size(&exheaderctx, ctx.infilesize);
settings_set_ignore_programid(&ctx.usersettings, 1);
exheader_set_usersettings(&exheaderctx, &ctx.usersettings);
exheader_process(&exheaderctx, ctx.actions);
break;
}
case FILETYPE_TMD:
{
tmd_context tmdctx;
tmd_init(&tmdctx);
tmd_set_file(&tmdctx, ctx.infile);
tmd_set_size(&tmdctx, ctx.infilesize);
tmd_set_usersettings(&tmdctx, &ctx.usersettings);
tmd_process(&tmdctx, ctx.actions);
break;
}
case FILETYPE_LZSS:
{
lzss_context lzssctx;
lzss_init(&lzssctx);
lzss_set_file(&lzssctx, ctx.infile);
lzss_set_size(&lzssctx, ctx.infilesize);
lzss_set_usersettings(&lzssctx, &ctx.usersettings);
lzss_process(&lzssctx, ctx.actions);
break;
}
case FILETYPE_CWAV:
{
cwav_context cwavctx;
cwav_init(&cwavctx);
cwav_set_file(&cwavctx, ctx.infile);
cwav_set_size(&cwavctx, ctx.infilesize);
cwav_set_usersettings(&cwavctx, &ctx.usersettings);
cwav_process(&cwavctx, ctx.actions);
break;
}
case FILETYPE_ROMFS:
{
romfs_context romfsctx;
romfs_init(&romfsctx);
romfs_set_file(&romfsctx, ctx.infile);
romfs_set_size(&romfsctx, ctx.infilesize);
romfs_set_usersettings(&romfsctx, &ctx.usersettings);
romfs_process(&romfsctx, ctx.actions);
break;
}
}
if (ctx.infile)
fclose(ctx.infile);
return 0;
}

582
ctrtool/ncch.c Normal file
View File

@ -0,0 +1,582 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "types.h"
#include "ncch.h"
#include "utils.h"
#include "ctr.h"
#include "settings.h"
static int programid_is_system(u8 programid[8])
{
u32 hiprogramid = getle32(programid+4);
if ( ((hiprogramid >> 14) == 0x10) && (hiprogramid & 0x10) )
return 1;
else
return 0;
}
void ncch_init(ncch_context* ctx)
{
memset(ctx, 0, sizeof(ncch_context));
exefs_init(&ctx->exefs);
}
void ncch_set_usersettings(ncch_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void ncch_set_offset(ncch_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void ncch_set_size(ncch_context* ctx, u32 size)
{
ctx->size = size;
}
void ncch_set_file(ncch_context* ctx, FILE* file)
{
ctx->file = file;
}
void ncch_get_counter(ncch_context* ctx, u8 counter[16], u8 type)
{
u32 version = getle16(ctx->header.version);
u32 mediaunitsize = ncch_get_mediaunit_size(ctx);
u8* partitionid = ctx->header.partitionid;
u32 i;
u32 x = 0;
memset(counter, 0, 16);
if (version == 2 || version == 0)
{
for(i=0; i<8; i++)
counter[i] = partitionid[7-i];
counter[8] = type;
}
else if (version == 1)
{
if (type == NCCHTYPE_EXHEADER)
x = 0x200;
else if (type == NCCHTYPE_EXEFS)
x = getle32(ctx->header.exefsoffset) * mediaunitsize;
else if (type == NCCHTYPE_ROMFS)
x = getle32(ctx->header.romfsoffset) * mediaunitsize;
for(i=0; i<8; i++)
counter[i] = partitionid[i];
for(i=0; i<4; i++)
counter[12+i] = x>>((3-i)*8);
}
}
int ncch_extract_prepare(ncch_context* ctx, u32 type, u32 flags)
{
u32 offset = 0;
u32 size = 0;
u8 counter[16];
switch(type)
{
case NCCHTYPE_EXEFS:
{
offset = ncch_get_exefs_offset(ctx);
size = ncch_get_exefs_size(ctx);
}
break;
case NCCHTYPE_ROMFS:
{
offset = ncch_get_romfs_offset(ctx);
size = ncch_get_romfs_size(ctx);
}
break;
case NCCHTYPE_EXHEADER:
{
offset = ncch_get_exheader_offset(ctx);
size = ncch_get_exheader_size(ctx) * 2;
}
break;
default:
{
fprintf(stderr, "Error invalid NCCH type\n");
goto clean;
}
break;
}
ctx->extractsize = size;
ctx->extractflags = flags;
fseek(ctx->file, offset, SEEK_SET);
ncch_get_counter(ctx, counter, type);
ctr_init_counter(&ctx->aes, ctx->key, counter);
return 1;
clean:
return 0;
}
int ncch_extract_buffer(ncch_context* ctx, u8* buffer, u32 buffersize, u32* outsize)
{
u32 max = buffersize;
if (max > ctx->extractsize)
max = ctx->extractsize;
*outsize = max;
if (ctx->extractsize)
{
if (max != fread(buffer, 1, max, ctx->file))
{
fprintf(stdout, "Error reading input file\n");
goto clean;
}
if (ctx->encrypted)
ctr_crypt_counter(&ctx->aes, buffer, buffer, max);
ctx->extractsize -= max;
}
return 1;
clean:
return 0;
}
void ncch_save(ncch_context* ctx, u32 type, u32 flags)
{
FILE* fout = 0;
filepath* path = 0;
u8 buffer[16*1024];
if (0 == ncch_extract_prepare(ctx, type, flags))
goto clean;
switch(type)
{
case NCCHTYPE_EXEFS: path = settings_get_exefs_path(ctx->usersettings); break;
case NCCHTYPE_ROMFS: path = settings_get_romfs_path(ctx->usersettings); break;
case NCCHTYPE_EXHEADER: path = settings_get_exheader_path(ctx->usersettings); break;
}
if (path == 0 || path->valid == 0)
goto clean;
fout = fopen(path->pathname, "wb");
if (0 == fout)
{
fprintf(stdout, "Error opening out file %s\n", path->pathname);
goto clean;
}
switch(type)
{
case NCCHTYPE_EXEFS: fprintf(stdout, "Saving ExeFS...\n"); break;
case NCCHTYPE_ROMFS: fprintf(stdout, "Saving RomFS...\n"); break;
case NCCHTYPE_EXHEADER: fprintf(stdout, "Saving Extended Header...\n"); break;
}
while(1)
{
u32 max;
if (0 == ncch_extract_buffer(ctx, buffer, sizeof(buffer), &max))
goto clean;
if (max == 0)
break;
if (max != fwrite(buffer, 1, max, fout))
{
fprintf(stdout, "Error writing output file\n");
goto clean;
}
}
clean:
if (fout)
fclose(fout);
return;
}
void ncch_verify(ncch_context* ctx, u32 flags)
{
u32 mediaunitsize = ncch_get_mediaunit_size(ctx);
u32 exefshashregionsize = getle32(ctx->header.exefshashregionsize) * mediaunitsize;
u32 romfshashregionsize = getle32(ctx->header.romfshashregionsize) * mediaunitsize;
u32 exheaderhashregionsize = getle32(ctx->header.extendedheadersize);
u8* exefshashregion = 0;
u8* romfshashregion = 0;
u8* exheaderhashregion = 0;
rsakey2048 ncchrsakey;
if (exefshashregionsize >= SIZE_128MB || romfshashregionsize >= SIZE_128MB || exheaderhashregionsize >= SIZE_128MB)
goto clean;
exefshashregion = malloc(exefshashregionsize);
romfshashregion = malloc(romfshashregionsize);
exheaderhashregion = malloc(exheaderhashregionsize);
if (ctx->usersettings)
{
if ( (ctx->header.flags[5] & 3) == 1)
ctx->headersigcheck = ncch_signature_verify(ctx, &ctx->usersettings->keys.ncchrsakey);
else
{
ctr_rsa_init_key_pubmodulus(&ncchrsakey, ctx->exheader.header.accessdesc.ncchpubkeymodulus);
ctx->headersigcheck = ncch_signature_verify(ctx, &ncchrsakey);
}
}
if (exefshashregionsize)
{
if (0 == ncch_extract_prepare(ctx, NCCHTYPE_EXEFS, flags))
goto clean;
if (0 == ncch_extract_buffer(ctx, exefshashregion, exefshashregionsize, &exefshashregionsize))
goto clean;
ctx->exefshashcheck = ctr_sha_256_verify(exefshashregion, exefshashregionsize, ctx->header.exefssuperblockhash);
}
if (romfshashregionsize)
{
if (0 == ncch_extract_prepare(ctx, NCCHTYPE_ROMFS, flags))
goto clean;
if (0 == ncch_extract_buffer(ctx, romfshashregion, romfshashregionsize, &romfshashregionsize))
goto clean;
ctx->romfshashcheck = ctr_sha_256_verify(romfshashregion, romfshashregionsize, ctx->header.romfssuperblockhash);
}
if (exheaderhashregionsize)
{
if (0 == ncch_extract_prepare(ctx, NCCHTYPE_EXHEADER, flags))
goto clean;
if (0 == ncch_extract_buffer(ctx, exheaderhashregion, exheaderhashregionsize, &exheaderhashregionsize))
goto clean;
ctx->exheaderhashcheck = ctr_sha_256_verify(exheaderhashregion, exheaderhashregionsize, ctx->header.extendedheaderhash);
}
free(exefshashregion);
free(romfshashregion);
free(exheaderhashregion);
clean:
return;
}
void ncch_process(ncch_context* ctx, u32 actions)
{
u8 exheadercounter[16];
u8 exefscounter[16];
int result = 1;
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(&ctx->header, 1, 0x200, ctx->file);
if (getle32(ctx->header.magic) != MAGIC_NCCH)
{
fprintf(stdout, "Error, NCCH segment corrupted\n");
return;
}
ncch_determine_key(ctx, actions);
ncch_get_counter(ctx, exheadercounter, NCCHTYPE_EXHEADER);
ncch_get_counter(ctx, exefscounter, NCCHTYPE_EXEFS);
exheader_set_file(&ctx->exheader, ctx->file);
exheader_set_offset(&ctx->exheader, ncch_get_exheader_offset(ctx) );
exheader_set_size(&ctx->exheader, ncch_get_exheader_size(ctx) );
exheader_set_usersettings(&ctx->exheader, ctx->usersettings);
exheader_set_partitionid(&ctx->exheader, ctx->header.partitionid);
exheader_set_programid(&ctx->exheader, ctx->header.programid);
exheader_set_counter(&ctx->exheader, exheadercounter);
exheader_set_key(&ctx->exheader, ctx->key);
exheader_set_encrypted(&ctx->exheader, ctx->encrypted);
exefs_set_file(&ctx->exefs, ctx->file);
exefs_set_offset(&ctx->exefs, ncch_get_exefs_offset(ctx) );
exefs_set_size(&ctx->exefs, ncch_get_exefs_size(ctx) );
exefs_set_partitionid(&ctx->exefs, ctx->header.partitionid);
exefs_set_usersettings(&ctx->exefs, ctx->usersettings);
exefs_set_counter(&ctx->exefs, exefscounter);
exefs_set_key(&ctx->exefs, ctx->key);
exefs_set_encrypted(&ctx->exefs, ctx->encrypted);
exheader_read(&ctx->exheader, actions);
if (actions & VerifyFlag)
ncch_verify(ctx, actions);
if (actions & InfoFlag)
ncch_print(ctx);
if (actions & ExtractFlag)
{
ncch_save(ctx, NCCHTYPE_EXEFS, actions);
ncch_save(ctx, NCCHTYPE_ROMFS, actions);
ncch_save(ctx, NCCHTYPE_EXHEADER, actions);
}
if (result && ncch_get_exheader_size(ctx))
{
if (!exheader_programid_valid(&ctx->exheader))
return;
result = exheader_process(&ctx->exheader, actions);
}
if (result && ncch_get_exheader_size(ctx))
{
exefs_set_compressedflag(&ctx->exefs, exheader_get_compressedflag(&ctx->exheader));
exefs_process(&ctx->exefs, actions);
}
}
int ncch_signature_verify(ncch_context* ctx, rsakey2048* key)
{
u8 hash[0x20];
ctr_sha_256(ctx->header.magic, 0x100, hash);
return ctr_rsa_verify_hash(ctx->header.signature, hash, key);
}
u32 ncch_get_exefs_offset(ncch_context* ctx)
{
u32 mediaunitsize = ncch_get_mediaunit_size(ctx);
return ctx->offset + getle32(ctx->header.exefsoffset) * mediaunitsize;
}
u32 ncch_get_exefs_size(ncch_context* ctx)
{
u32 mediaunitsize = ncch_get_mediaunit_size(ctx);
return getle32(ctx->header.exefssize) * mediaunitsize;
}
u32 ncch_get_romfs_offset(ncch_context* ctx)
{
u32 mediaunitsize = ncch_get_mediaunit_size(ctx);
return ctx->offset + getle32(ctx->header.romfsoffset) * mediaunitsize;
}
u32 ncch_get_romfs_size(ncch_context* ctx)
{
u32 mediaunitsize = ncch_get_mediaunit_size(ctx);
return getle32(ctx->header.romfssize) * mediaunitsize;
}
u32 ncch_get_exheader_offset(ncch_context* ctx)
{
return ctx->offset + 0x200;
}
u32 ncch_get_exheader_size(ncch_context* ctx)
{
return getle32(ctx->header.extendedheadersize);
}
u32 ncch_get_mediaunit_size(ncch_context* ctx)
{
unsigned int mediaunitsize = settings_get_mediaunit_size(ctx->usersettings);
if (mediaunitsize == 0)
{
unsigned short version = getle16(ctx->header.version);
if (version == 1)
mediaunitsize = 1;
else if (version == 2 || version == 0)
mediaunitsize = 1 << (ctx->header.flags[6] + 9);
}
return mediaunitsize;
}
void ncch_determine_key(ncch_context* ctx, u32 actions)
{
exheader_header exheader;
u8* key = settings_get_ncch_key(ctx->usersettings);
ctr_ncchheader* header = &ctx->header;
ctx->encrypted = 0;
memset(ctx->key, 0, 0x10);
if (actions & PlainFlag)
{
ctx->encrypted = 0;
}
else if (key != 0)
{
ctx->encrypted = 1;
memcpy(ctx->key, key, 0x10);
}
else
{
// No explicit NCCH key defined, so we try to decide
// Firstly, check if the NCCH is already decrypted, by reading the programid in the exheader
// Otherwise, use determination rules
fseek(ctx->file, ncch_get_exheader_offset(ctx), SEEK_SET);
memset(&exheader, 0, sizeof(exheader));
fread(&exheader, 1, sizeof(exheader), ctx->file);
if (!memcmp(exheader.arm11systemlocalcaps.programid, ctx->header.programid, 8))
{
// program id's match, so it's probably not encrypted
ctx->encrypted = 0;
}
else if (header->flags[7] & 4)
{
ctx->encrypted = 0; // not encrypted
}
else if (header->flags[7] & 1)
{
if (programid_is_system(header->programid))
{
// fixed system key
ctx->encrypted = 1;
key = settings_get_ncch_fixedsystemkey(ctx->usersettings);
if (!key)
fprintf(stdout, "Warning, could not read system fixed key.\n");
else
memcpy(ctx->key, key, 0x10);
}
else
{
// null key
ctx->encrypted = 1;
memset(ctx->key, 0, 0x10);
}
}
else
{
// secure key (cannot decrypt!)
fprintf(stdout, "Warning, could not read secure key.\n");
ctx->encrypted = 1;
memset(ctx->key, 0, 0x10);
}
}
}
static const char* formtypetostring(unsigned char flags)
{
unsigned char formtype = flags & 3;
switch(formtype)
{
case 0: return "Not assigned";
case 1: return "Simple content";
case 2: return "Executable content without RomFS";
case 3: return "Executable content";
default: return "Unknown";
}
}
static const char* contenttypetostring(unsigned char flags)
{
unsigned char contenttype = flags>>2;
switch(contenttype)
{
case 0: return "Application";
case 1: return "System Update";
case 2: return "Manual";
case 3: return "Child";
case 4: return "Trial";
default: return "Unknown";
}
}
void ncch_print(ncch_context* ctx)
{
char magic[5];
char productcode[0x11];
ctr_ncchheader *header = &ctx->header;
u32 offset = ctx->offset;
u32 mediaunitsize = ncch_get_mediaunit_size(ctx);
fprintf(stdout, "\nNCCH:\n");
memcpy(magic, header->magic, 4);
magic[4] = 0;
memcpy(productcode, header->productcode, 0x10);
productcode[0x10] = 0;
fprintf(stdout, "Header: %s\n", magic);
if (ctx->headersigcheck == Unchecked)
memdump(stdout, "Signature: ", header->signature, 0x100);
else if (ctx->headersigcheck == Good)
memdump(stdout, "Signature (GOOD): ", header->signature, 0x100);
else
memdump(stdout, "Signature (FAIL): ", header->signature, 0x100);
fprintf(stdout, "Content size: 0x%08x\n", getle32(header->contentsize)*mediaunitsize);
fprintf(stdout, "Partition id: %016llx\n", getle64(header->partitionid));
fprintf(stdout, "Maker code: %04x\n", getle16(header->makercode));
fprintf(stdout, "Version: %04x\n", getle16(header->version));
fprintf(stdout, "Program id: %016llx\n", getle64(header->programid));
fprintf(stdout, "Temp flag: %02x\n", header->tempflag);
fprintf(stdout, "Product code: %s\n", productcode);
fprintf(stdout, "Exheader size: %08x\n", getle32(header->extendedheadersize));
if (ctx->exheaderhashcheck == Unchecked)
memdump(stdout, "Exheader hash: ", header->extendedheaderhash, 0x20);
else if (ctx->exheaderhashcheck == Good)
memdump(stdout, "Exheader hash (GOOD): ", header->extendedheaderhash, 0x20);
else
memdump(stdout, "Exheader hash (FAIL): ", header->extendedheaderhash, 0x20);
fprintf(stdout, "Flags: %016llx\n", getle64(header->flags));
fprintf(stdout, " > Mediaunit size: 0x%x\n", mediaunitsize);
if (header->flags[7] & 4)
fprintf(stdout, " > Crypto key: None\n");
else if (header->flags[7] & 1)
fprintf(stdout, " > Crypto key: %s\n", programid_is_system(header->programid)? "Fixed":"Zeros");
else
fprintf(stdout, " > Crypto key: Secure\n");
fprintf(stdout, " > Form type: %s\n", formtypetostring(header->flags[5]));
fprintf(stdout, " > Content type: %s\n", contenttypetostring(header->flags[5]));
if (header->flags[4] & 1)
fprintf(stdout, " > Content platform: CTR\n");
if (header->flags[7] & 2)
fprintf(stdout, " > No RomFS mount\n");
fprintf(stdout, "Plain region offset: 0x%08x\n", getle32(header->plainregionsize)? offset+getle32(header->plainregionoffset)*mediaunitsize : 0);
fprintf(stdout, "Plain region size: 0x%08x\n", getle32(header->plainregionsize)*mediaunitsize);
fprintf(stdout, "ExeFS offset: 0x%08x\n", getle32(header->exefssize)? offset+getle32(header->exefsoffset)*mediaunitsize : 0);
fprintf(stdout, "ExeFS size: 0x%08x\n", getle32(header->exefssize)*mediaunitsize);
fprintf(stdout, "ExeFS hash region size: 0x%08x\n", getle32(header->exefshashregionsize)*mediaunitsize);
fprintf(stdout, "RomFS offset: 0x%08x\n", getle32(header->romfssize)? offset+getle32(header->romfsoffset)*mediaunitsize : 0);
fprintf(stdout, "RomFS size: 0x%08x\n", getle32(header->romfssize)*mediaunitsize);
fprintf(stdout, "RomFS hash region size: 0x%08x\n", getle32(header->romfshashregionsize)*mediaunitsize);
if (ctx->exefshashcheck == Unchecked)
memdump(stdout, "ExeFS Hash: ", header->exefssuperblockhash, 0x20);
else if (ctx->exefshashcheck == Good)
memdump(stdout, "ExeFS Hash (GOOD): ", header->exefssuperblockhash, 0x20);
else
memdump(stdout, "ExeFS Hash (FAIL): ", header->exefssuperblockhash, 0x20);
if (ctx->romfshashcheck == Unchecked)
memdump(stdout, "RomFS Hash: ", header->romfssuperblockhash, 0x20);
else if (ctx->romfshashcheck == Good)
memdump(stdout, "RomFS Hash (GOOD): ", header->romfssuperblockhash, 0x20);
else
memdump(stdout, "RomFS Hash (FAIL): ", header->romfssuperblockhash, 0x20);
}

94
ctrtool/ncch.h Normal file
View File

@ -0,0 +1,94 @@
#ifndef _NCCH_H_
#define _NCCH_H_
#include <stdio.h>
#include "types.h"
#include "keyset.h"
#include "filepath.h"
#include "ctr.h"
#include "exefs.h"
#include "exheader.h"
#include "settings.h"
typedef enum
{
NCCHTYPE_EXHEADER = 1,
NCCHTYPE_EXEFS = 2,
NCCHTYPE_ROMFS = 3,
} ctr_ncchtypes;
typedef struct
{
u8 signature[0x100];
u8 magic[4];
u8 contentsize[4];
u8 partitionid[8];
u8 makercode[2];
u8 version[2];
u8 reserved0[4];
u8 programid[8];
u8 tempflag;
u8 reserved1[0x2f];
u8 productcode[0x10];
u8 extendedheaderhash[0x20];
u8 extendedheadersize[4];
u8 reserved2[4];
u8 flags[8];
u8 plainregionoffset[4];
u8 plainregionsize[4];
u8 reserved3[8];
u8 exefsoffset[4];
u8 exefssize[4];
u8 exefshashregionsize[4];
u8 reserved4[4];
u8 romfsoffset[4];
u8 romfssize[4];
u8 romfshashregionsize[4];
u8 reserved5[4];
u8 exefssuperblockhash[0x20];
u8 romfssuperblockhash[0x20];
} ctr_ncchheader;
typedef struct
{
FILE* file;
u8 key[16];
u32 encrypted;
u32 offset;
u32 size;
settings* usersettings;
ctr_ncchheader header;
ctr_aes_context aes;
exefs_context exefs;
exheader_context exheader;
int exefshashcheck;
int romfshashcheck;
int exheaderhashcheck;
int headersigcheck;
u32 extractsize;
u32 extractflags;
} ncch_context;
void ncch_init(ncch_context* ctx);
void ncch_process(ncch_context* ctx, u32 actions);
void ncch_set_offset(ncch_context* ctx, u32 offset);
void ncch_set_size(ncch_context* ctx, u32 size);
void ncch_set_file(ncch_context* ctx, FILE* file);
void ncch_set_usersettings(ncch_context* ctx, settings* usersettings);
u32 ncch_get_exefs_offset(ncch_context* ctx);
u32 ncch_get_exefs_size(ncch_context* ctx);
u32 ncch_get_romfs_offset(ncch_context* ctx);
u32 ncch_get_romfs_size(ncch_context* ctx);
u32 ncch_get_exheader_offset(ncch_context* ctx);
u32 ncch_get_exheader_size(ncch_context* ctx);
void ncch_print(ncch_context* ctx);
int ncch_signature_verify(ncch_context* ctx, rsakey2048* key);
void ncch_verify(ncch_context* ctx, u32 flags);
void ncch_save(ncch_context* ctx, u32 type, u32 flags);
int ncch_extract_prepare(ncch_context* ctx, u32 type, u32 flags);
int ncch_extract_buffer(ncch_context* ctx, u8* buffer, u32 buffersize, u32* outsize);
u32 ncch_get_mediaunit_size(ncch_context* ctx);
void ncch_get_counter(ncch_context* ctx, u8 counter[16], u8 type);
void ncch_determine_key(ncch_context* ctx, u32 actions);
#endif // _NCCH_H_

128
ctrtool/ncsd.c Normal file
View File

@ -0,0 +1,128 @@
#include <stdio.h>
#include <string.h>
#include "types.h"
#include "ncsd.h"
#include "utils.h"
#include "ctr.h"
void ncsd_init(ncsd_context* ctx)
{
memset(ctx, 0, sizeof(ncsd_context));
}
void ncsd_set_offset(ncsd_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void ncsd_set_file(ncsd_context* ctx, FILE* file)
{
ctx->file = file;
}
void ncsd_set_size(ncsd_context* ctx, u32 size)
{
ctx->size = size;
}
void ncsd_set_usersettings(ncsd_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
int ncsd_signature_verify(const void* blob, rsakey2048* key)
{
u8* message = (u8*)blob + 0x100;
u8* sig = (u8*)blob;
u8 hash[0x20];
ctr_sha_256(message, 0x100, hash);
return ctr_rsa_verify_hash(sig, hash, key);
}
void ncsd_process(ncsd_context* ctx, u32 actions)
{
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(&ctx->header, 1, 0x200, ctx->file);
if (getle32(ctx->header.magic) != MAGIC_NCSD)
{
fprintf(stdout, "Error, NCSD segment corrupted\n");
return;
}
if (actions & VerifyFlag)
{
if (ctx->usersettings)
ctx->headersigcheck = ncsd_signature_verify(&ctx->header, &ctx->usersettings->keys.ncsdrsakey);
}
if (actions & InfoFlag)
ncsd_print(ctx);
ncch_set_file(&ctx->ncch, ctx->file);
ncch_set_offset(&ctx->ncch, 0x4000);
ncch_set_size(&ctx->ncch, ctx->size - 0x4000);
ncch_set_usersettings(&ctx->ncch, ctx->usersettings);
ncch_process(&ctx->ncch, actions);
}
unsigned int ncsd_get_mediaunit_size(ncsd_context* ctx)
{
unsigned int mediaunitsize = settings_get_mediaunit_size(ctx->usersettings);
if (mediaunitsize == 0)
mediaunitsize = 1<<(9+ctx->header.flags[6]);
return mediaunitsize;
}
void ncsd_print(ncsd_context* ctx)
{
char magic[5];
ctr_ncsdheader* header = &ctx->header;
unsigned int i;
unsigned int mediaunitsize = ncsd_get_mediaunit_size(ctx);
memcpy(magic, header->magic, 4);
magic[4] = 0;
fprintf(stdout, "Header: %s\n", magic);
if (ctx->headersigcheck == Unchecked)
memdump(stdout, "Signature: ", header->signature, 0x100);
else if (ctx->headersigcheck == Good)
memdump(stdout, "Signature (GOOD): ", header->signature, 0x100);
else
memdump(stdout, "Signature (FAIL): ", header->signature, 0x100);
fprintf(stdout, "Media size: 0x%08x\n", getle32(header->mediasize));
fprintf(stdout, "Media id: %016llx\n", getle64(header->mediaid));
//memdump(stdout, "Partition FS type: ", header->partitionfstype, 8);
//memdump(stdout, "Partition crypt type: ", header->partitioncrypttype, 8);
//memdump(stdout, "Partition offset/size: ", header->partitionoffsetandsize, 0x40);
fprintf(stdout, "\n");
for(i=0; i<8; i++)
{
u32 partitionoffset = header->partitiongeometry[i].offset * mediaunitsize;
u32 partitionsize = header->partitiongeometry[i].size * mediaunitsize;
if (partitionsize != 0)
{
fprintf(stdout, "Partition %d \n", i);
memdump(stdout, " Id: ", header->partitionid+i*8, 8);
fprintf(stdout, " Area: 0x%08X-0x%08X\n", partitionoffset, partitionoffset+partitionsize);
fprintf(stdout, " Filesystem: %02X\n", header->partitionfstype[i]);
fprintf(stdout, " Encryption: %02X\n", header->partitioncrypttype[i]);
fprintf(stdout, "\n");
}
}
memdump(stdout, "Extended header hash: ", header->extendedheaderhash, 0x20);
memdump(stdout, "Additional header size: ", header->additionalheadersize, 4);
memdump(stdout, "Sector zero offset: ", header->sectorzerooffset, 4);
memdump(stdout, "Flags: ", header->flags, 8);
fprintf(stdout, " > Mediaunit size: 0x%X\n", mediaunitsize);
}

55
ctrtool/ncsd.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef _NCSD_H_
#define _NCSD_H_
#include "types.h"
#include "keyset.h"
#include "settings.h"
#include "ncch.h"
typedef struct
{
u32 offset;
u32 size;
} ncsd_partition_geometry;
typedef struct
{
u8 signature[0x100];
u8 magic[4];
u8 mediasize[4];
u8 mediaid[8];
u8 partitionfstype[8];
u8 partitioncrypttype[8];
ncsd_partition_geometry partitiongeometry[8];
u8 extendedheaderhash[0x20];
u8 additionalheadersize[4];
u8 sectorzerooffset[4];
u8 flags[8];
u8 partitionid[0x40];
u8 reserved[0x30];
} ctr_ncsdheader;
typedef struct
{
FILE* file;
u32 offset;
u32 size;
ctr_ncsdheader header;
settings* usersettings;
int headersigcheck;
ncch_context ncch;
} ncsd_context;
void ncsd_init(ncsd_context* ctx);
void ncsd_set_offset(ncsd_context* ctx, u32 offset);
void ncsd_set_size(ncsd_context* ctx, u32 size);
void ncsd_set_file(ncsd_context* ctx, FILE* file);
void ncsd_set_usersettings(ncsd_context* ctx, settings* usersettings);
int ncsd_signature_verify(const void* blob, rsakey2048* key);
void ncsd_process(ncsd_context* ctx, u32 actions);
void ncsd_print(ncsd_context* ctx);
unsigned int ncsd_get_mediaunit_size(ncsd_context* ctx);
#endif // _NCSD_H_

1164
ctrtool/polarssl/aes.c Normal file

File diff suppressed because it is too large Load Diff

139
ctrtool/polarssl/aes.h Normal file
View File

@ -0,0 +1,139 @@
/**
* \file aes.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_AES_H
#define POLARSSL_AES_H
#define AES_ENCRYPT 1
#define AES_DECRYPT 0
#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0800
#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0810
/**
* \brief AES context structure
*/
typedef struct
{
int nr; /*!< number of rounds */
unsigned long *rk; /*!< AES round keys */
unsigned long buf[68]; /*!< unaligned data */
}
aes_context;
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief AES key schedule (encryption)
*
* \param ctx AES context to be initialized
* \param key encryption key
* \param keysize must be 128, 192 or 256
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
*/
int aes_setkey_enc( aes_context *ctx, const unsigned char *key, int keysize );
/**
* \brief AES key schedule (decryption)
*
* \param ctx AES context to be initialized
* \param key decryption key
* \param keysize must be 128, 192 or 256
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
*/
int aes_setkey_dec( aes_context *ctx, const unsigned char *key, int keysize );
/**
* \brief AES-ECB block encryption/decryption
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param input 16-byte input block
* \param output 16-byte output block
*
* \return 0 if successful
*/
int aes_crypt_ecb( aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] );
/**
* \brief AES-CBC buffer encryption/decryption
* Length should be a multiple of the block
* size (16 bytes)
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH
*/
int aes_crypt_cbc( aes_context *ctx,
int mode,
int length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
/**
* \brief AES-CFB128 buffer encryption/decryption.
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param length length of the input data
* \param iv_off offset in IV (updated after use)
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful
*/
int aes_crypt_cfb128( aes_context *ctx,
int mode,
int length,
int *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int aes_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* aes.h */

2038
ctrtool/polarssl/bignum.c Normal file

File diff suppressed because it is too large Load Diff

533
ctrtool/polarssl/bignum.h Normal file
View File

@ -0,0 +1,533 @@
/**
* \file bignum.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_BIGNUM_H
#define POLARSSL_BIGNUM_H
#include <stdio.h>
#define POLARSSL_ERR_MPI_FILE_IO_ERROR 0x0002
#define POLARSSL_ERR_MPI_BAD_INPUT_DATA 0x0004
#define POLARSSL_ERR_MPI_INVALID_CHARACTER 0x0006
#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL 0x0008
#define POLARSSL_ERR_MPI_NEGATIVE_VALUE 0x000A
#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO 0x000C
#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE 0x000E
#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup
/*
* Define the base integer type, architecture-wise
*/
#if defined(POLARSSL_HAVE_INT8)
typedef unsigned char t_int;
typedef unsigned short t_dbl;
#else
#if defined(POLARSSL_HAVE_INT16)
typedef unsigned short t_int;
typedef unsigned long t_dbl;
#else
typedef unsigned long t_int;
#if defined(_MSC_VER) && defined(_M_IX86)
typedef unsigned __int64 t_dbl;
#else
#if defined(__amd64__) || defined(__x86_64__) || \
defined(__ppc64__) || defined(__powerpc64__) || \
defined(__ia64__) || defined(__alpha__)
typedef unsigned int t_dbl __attribute__((mode(TI)));
#else
#if defined(POLARSSL_HAVE_LONGLONG)
typedef unsigned long long t_dbl;
#endif
#endif
#endif
#endif
#endif
/**
* \brief MPI structure
*/
typedef struct
{
int s; /*!< integer sign */
int n; /*!< total # of limbs */
t_int *p; /*!< pointer to limbs */
}
mpi;
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Initialize one or more mpi
*/
void mpi_init( mpi *X, ... );
/**
* \brief Unallocate one or more mpi
*/
void mpi_free( mpi *X, ... );
/**
* \brief Enlarge to the specified number of limbs
*
* \param X MPI to grow
* \param nblimbs The target number of limbs
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_grow( mpi *X, int nblimbs );
/**
* \brief Copy the contents of Y into X
*
* \param X Destination MPI
* \param Y Source MPI
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_copy( mpi *X, const mpi *Y );
/**
* \brief Swap the contents of X and Y
*
* \param X First MPI value
* \param Y Second MPI value
*/
void mpi_swap( mpi *X, mpi *Y );
/**
* \brief Set value from integer
*
* \param X MPI to set
* \param z Value to use
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_lset( mpi *X, int z );
/**
* \brief Return the number of least significant bits
*
* \param X MPI to use
*/
int mpi_lsb( const mpi *X );
/**
* \brief Return the number of most significant bits
*
* \param X MPI to use
*/
int mpi_msb( const mpi *X );
/**
* \brief Return the total size in bytes
*
* \param X MPI to use
*/
int mpi_size( const mpi *X );
/**
* \brief Import from an ASCII string
*
* \param X Destination MPI
* \param radix Input numeric base
* \param s Null-terminated string buffer
*
* \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code
*/
int mpi_read_string( mpi *X, int radix, const char *s );
/**
* \brief Export into an ASCII string
*
* \param X Source MPI
* \param radix Output numeric base
* \param s String buffer
* \param slen String buffer size
*
* \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code.
* *slen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* \note Call this function with *slen = 0 to obtain the
* minimum required buffer size in *slen.
*/
int mpi_write_string( const mpi *X, int radix, char *s, int *slen );
/**
* \brief Read X from an opened file
*
* \param X Destination MPI
* \param radix Input numeric base
* \param fin Input file handle
*
* \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code
*/
int mpi_read_file( mpi *X, int radix, FILE *fin );
/**
* \brief Write X into an opened file, or stdout if fout is NULL
*
* \param p Prefix, can be NULL
* \param X Source MPI
* \param radix Output numeric base
* \param fout Output file handle (can be NULL)
*
* \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code
*
* \note Set fout == NULL to print X on the console.
*/
int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout );
/**
* \brief Import X from unsigned binary data, big endian
*
* \param X Destination MPI
* \param buf Input buffer
* \param buflen Input buffer size
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_read_binary( mpi *X, const unsigned char *buf, int buflen );
/**
* \brief Export X into unsigned binary data, big endian
*
* \param X Source MPI
* \param buf Output buffer
* \param buflen Output buffer size
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
*/
int mpi_write_binary( const mpi *X, unsigned char *buf, int buflen );
/**
* \brief Left-shift: X <<= count
*
* \param X MPI to shift
* \param count Amount to shift
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_shift_l( mpi *X, int count );
/**
* \brief Right-shift: X >>= count
*
* \param X MPI to shift
* \param count Amount to shift
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_shift_r( mpi *X, int count );
/**
* \brief Compare unsigned values
*
* \param X Left-hand MPI
* \param Y Right-hand MPI
*
* \return 1 if |X| is greater than |Y|,
* -1 if |X| is lesser than |Y| or
* 0 if |X| is equal to |Y|
*/
int mpi_cmp_abs( const mpi *X, const mpi *Y );
/**
* \brief Compare signed values
*
* \param X Left-hand MPI
* \param Y Right-hand MPI
*
* \return 1 if X is greater than Y,
* -1 if X is lesser than Y or
* 0 if X is equal to Y
*/
int mpi_cmp_mpi( const mpi *X, const mpi *Y );
/**
* \brief Compare signed values
*
* \param X Left-hand MPI
* \param z The integer value to compare to
*
* \return 1 if X is greater than z,
* -1 if X is lesser than z or
* 0 if X is equal to z
*/
int mpi_cmp_int( const mpi *X, int z );
/**
* \brief Unsigned addition: X = |A| + |B|
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_add_abs( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Unsigned substraction: X = |A| - |B|
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A
*/
int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Signed addition: X = A + B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Signed substraction: X = A - B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Signed addition: X = A + b
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The integer value to add
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_add_int( mpi *X, const mpi *A, int b );
/**
* \brief Signed substraction: X = A - b
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The integer value to subtract
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_sub_int( mpi *X, const mpi *A, int b );
/**
* \brief Baseline multiplication: X = A * B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Baseline multiplication: X = A * b
* Note: b is an unsigned integer type, thus
* Negative values of b are ignored.
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The integer value to multiply with
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_mul_int( mpi *X, const mpi *A, t_int b );
/**
* \brief Division by mpi: A = Q * B + R
*
* \param Q Destination MPI for the quotient
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
*
* \note Either Q or R can be NULL.
*/
int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B );
/**
* \brief Division by int: A = Q * b + R
*
* \param Q Destination MPI for the quotient
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param b Integer to divide by
*
* \return 0 if successful,
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
*
* \note Either Q or R can be NULL.
*/
int mpi_div_int( mpi *Q, mpi *R, const mpi *A, int b );
/**
* \brief Modulo: R = A mod B
*
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0,
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0
*/
int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B );
/**
* \brief Modulo: r = A mod b
*
* \param r Destination t_int
* \param A Left-hand MPI
* \param b Integer to divide by
*
* \return 0 if successful,
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0,
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0
*/
int mpi_mod_int( t_int *r, const mpi *A, int b );
/**
* \brief Sliding-window exponentiation: X = A^E mod N
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param E Exponent MPI
* \param N Modular MPI
* \param _RR Speed-up MPI used for recalculations
*
* \return 0 if successful,
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even
*
* \note _RR is used to avoid re-computing R*R mod N across
* multiple calls, which speeds up things a bit. It can
* be set to NULL if the extra performance is unneeded.
*/
int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR );
/**
* \brief Greatest common divisor: G = gcd(A, B)
*
* \param G Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* 1 if memory allocation failed
*/
int mpi_gcd( mpi *G, const mpi *A, const mpi *B );
/**
* \brief Modular inverse: X = A^-1 mod N
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param N Right-hand MPI
*
* \return 0 if successful,
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil
POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N
*/
int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N );
/**
* \brief Miller-Rabin primality test
*
* \param X MPI to check
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful (probably prime),
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
*/
int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
/**
* \brief Prime number generation
*
* \param X Destination MPI
* \param nbits Required size of X in bits
* \param dh_flag If 1, then (X-1)/2 will be prime too
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful (probably prime),
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
*/
int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
int (*f_rng)(void *), void *p_rng );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mpi_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* bignum.h */

736
ctrtool/polarssl/bn_mul.h Normal file
View File

@ -0,0 +1,736 @@
/**
* \file bn_mul.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* Multiply source vector [s] with b, add result
* to destination vector [d] and set carry c.
*
* Currently supports:
*
* . IA-32 (386+) . AMD64 / EM64T
* . IA-32 (SSE2) . Motorola 68000
* . PowerPC, 32-bit . MicroBlaze
* . PowerPC, 64-bit . TriCore
* . SPARC v8 . ARM v3+
* . Alpha . MIPS32
* . C, longlong . C, generic
*/
#ifndef POLARSSL_BN_MUL_H
#define POLARSSL_BN_MUL_H
#include "polarssl/config.h"
#if defined(POLARSSL_HAVE_ASM)
#if defined(__GNUC__)
#if defined(__i386__)
#define MULADDC_INIT \
asm( " \
movl %%ebx, %0; \
movl %5, %%esi; \
movl %6, %%edi; \
movl %7, %%ecx; \
movl %8, %%ebx; \
"
#define MULADDC_CORE \
" \
lodsl; \
mull %%ebx; \
addl %%ecx, %%eax; \
adcl $0, %%edx; \
addl (%%edi), %%eax; \
adcl $0, %%edx; \
movl %%edx, %%ecx; \
stosl; \
"
#if defined(POLARSSL_HAVE_SSE2)
#define MULADDC_HUIT \
" \
movd %%ecx, %%mm1; \
movd %%ebx, %%mm0; \
movd (%%edi), %%mm3; \
paddq %%mm3, %%mm1; \
movd (%%esi), %%mm2; \
pmuludq %%mm0, %%mm2; \
movd 4(%%esi), %%mm4; \
pmuludq %%mm0, %%mm4; \
movd 8(%%esi), %%mm6; \
pmuludq %%mm0, %%mm6; \
movd 12(%%esi), %%mm7; \
pmuludq %%mm0, %%mm7; \
paddq %%mm2, %%mm1; \
movd 4(%%edi), %%mm3; \
paddq %%mm4, %%mm3; \
movd 8(%%edi), %%mm5; \
paddq %%mm6, %%mm5; \
movd 12(%%edi), %%mm4; \
paddq %%mm4, %%mm7; \
movd %%mm1, (%%edi); \
movd 16(%%esi), %%mm2; \
pmuludq %%mm0, %%mm2; \
psrlq $32, %%mm1; \
movd 20(%%esi), %%mm4; \
pmuludq %%mm0, %%mm4; \
paddq %%mm3, %%mm1; \
movd 24(%%esi), %%mm6; \
pmuludq %%mm0, %%mm6; \
movd %%mm1, 4(%%edi); \
psrlq $32, %%mm1; \
movd 28(%%esi), %%mm3; \
pmuludq %%mm0, %%mm3; \
paddq %%mm5, %%mm1; \
movd 16(%%edi), %%mm5; \
paddq %%mm5, %%mm2; \
movd %%mm1, 8(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm7, %%mm1; \
movd 20(%%edi), %%mm5; \
paddq %%mm5, %%mm4; \
movd %%mm1, 12(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm2, %%mm1; \
movd 24(%%edi), %%mm5; \
paddq %%mm5, %%mm6; \
movd %%mm1, 16(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm4, %%mm1; \
movd 28(%%edi), %%mm5; \
paddq %%mm5, %%mm3; \
movd %%mm1, 20(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm6, %%mm1; \
movd %%mm1, 24(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm3, %%mm1; \
movd %%mm1, 28(%%edi); \
addl $32, %%edi; \
addl $32, %%esi; \
psrlq $32, %%mm1; \
movd %%mm1, %%ecx; \
"
#define MULADDC_STOP \
" \
emms; \
movl %4, %%ebx; \
movl %%ecx, %1; \
movl %%edi, %2; \
movl %%esi, %3; \
" \
: "=m" (t), "=m" (c), "=m" (d), "=m" (s) \
: "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \
: "eax", "ecx", "edx", "esi", "edi" \
);
#else
#define MULADDC_STOP \
" \
movl %4, %%ebx; \
movl %%ecx, %1; \
movl %%edi, %2; \
movl %%esi, %3; \
" \
: "=m" (t), "=m" (c), "=m" (d), "=m" (s) \
: "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \
: "eax", "ecx", "edx", "esi", "edi" \
);
#endif /* SSE2 */
#endif /* i386 */
#if defined(__amd64__) || defined (__x86_64__)
#define MULADDC_INIT \
asm( "movq %0, %%rsi " :: "m" (s)); \
asm( "movq %0, %%rdi " :: "m" (d)); \
asm( "movq %0, %%rcx " :: "m" (c)); \
asm( "movq %0, %%rbx " :: "m" (b)); \
asm( "xorq %r8, %r8 " );
#define MULADDC_CORE \
asm( "movq (%rsi),%rax " ); \
asm( "mulq %rbx " ); \
asm( "addq $8, %rsi " ); \
asm( "addq %rcx, %rax " ); \
asm( "movq %r8, %rcx " ); \
asm( "adcq $0, %rdx " ); \
asm( "nop " ); \
asm( "addq %rax, (%rdi) " ); \
asm( "adcq %rdx, %rcx " ); \
asm( "addq $8, %rdi " );
#define MULADDC_STOP \
asm( "movq %%rcx, %0 " : "=m" (c)); \
asm( "movq %%rdi, %0 " : "=m" (d)); \
asm( "movq %%rsi, %0 " : "=m" (s) :: \
"rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
#endif /* AMD64 */
#if defined(__mc68020__) || defined(__mcpu32__)
#define MULADDC_INIT \
asm( "movl %0, %%a2 " :: "m" (s)); \
asm( "movl %0, %%a3 " :: "m" (d)); \
asm( "movl %0, %%d3 " :: "m" (c)); \
asm( "movl %0, %%d2 " :: "m" (b)); \
asm( "moveq #0, %d0 " );
#define MULADDC_CORE \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "moveq #0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "addxl %d4, %d3 " );
#define MULADDC_STOP \
asm( "movl %%d3, %0 " : "=m" (c)); \
asm( "movl %%a3, %0 " : "=m" (d)); \
asm( "movl %%a2, %0 " : "=m" (s) :: \
"d0", "d1", "d2", "d3", "d4", "a2", "a3" );
#define MULADDC_HUIT \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addxl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d3:%d1 " ); \
asm( "addxl %d4, %d1 " ); \
asm( "addxl %d0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addxl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d3:%d1 " ); \
asm( "addxl %d4, %d1 " ); \
asm( "addxl %d0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addxl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d3:%d1 " ); \
asm( "addxl %d4, %d1 " ); \
asm( "addxl %d0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addxl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d3:%d1 " ); \
asm( "addxl %d4, %d1 " ); \
asm( "addxl %d0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "addxl %d0, %d3 " );
#endif /* MC68000 */
#if defined(__powerpc__) || defined(__ppc__)
#if defined(__powerpc64__) || defined(__ppc64__)
#if defined(__MACH__) && defined(__APPLE__)
#define MULADDC_INIT \
asm( "ld r3, %0 " :: "m" (s)); \
asm( "ld r4, %0 " :: "m" (d)); \
asm( "ld r5, %0 " :: "m" (c)); \
asm( "ld r6, %0 " :: "m" (b)); \
asm( "addi r3, r3, -8 " ); \
asm( "addi r4, r4, -8 " ); \
asm( "addic r5, r5, 0 " );
#define MULADDC_CORE \
asm( "ldu r7, 8(r3) " ); \
asm( "mulld r8, r7, r6 " ); \
asm( "mulhdu r9, r7, r6 " ); \
asm( "adde r8, r8, r5 " ); \
asm( "ld r7, 8(r4) " ); \
asm( "addze r5, r9 " ); \
asm( "addc r8, r8, r7 " ); \
asm( "stdu r8, 8(r4) " );
#define MULADDC_STOP \
asm( "addze r5, r5 " ); \
asm( "addi r4, r4, 8 " ); \
asm( "addi r3, r3, 8 " ); \
asm( "std r5, %0 " : "=m" (c)); \
asm( "std r4, %0 " : "=m" (d)); \
asm( "std r3, %0 " : "=m" (s) :: \
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
#else
#define MULADDC_INIT \
asm( "ld %%r3, %0 " :: "m" (s)); \
asm( "ld %%r4, %0 " :: "m" (d)); \
asm( "ld %%r5, %0 " :: "m" (c)); \
asm( "ld %%r6, %0 " :: "m" (b)); \
asm( "addi %r3, %r3, -8 " ); \
asm( "addi %r4, %r4, -8 " ); \
asm( "addic %r5, %r5, 0 " );
#define MULADDC_CORE \
asm( "ldu %r7, 8(%r3) " ); \
asm( "mulld %r8, %r7, %r6 " ); \
asm( "mulhdu %r9, %r7, %r6 " ); \
asm( "adde %r8, %r8, %r5 " ); \
asm( "ld %r7, 8(%r4) " ); \
asm( "addze %r5, %r9 " ); \
asm( "addc %r8, %r8, %r7 " ); \
asm( "stdu %r8, 8(%r4) " );
#define MULADDC_STOP \
asm( "addze %r5, %r5 " ); \
asm( "addi %r4, %r4, 8 " ); \
asm( "addi %r3, %r3, 8 " ); \
asm( "std %%r5, %0 " : "=m" (c)); \
asm( "std %%r4, %0 " : "=m" (d)); \
asm( "std %%r3, %0 " : "=m" (s) :: \
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
#endif
#else /* PPC32 */
#if defined(__MACH__) && defined(__APPLE__)
#define MULADDC_INIT \
asm( "lwz r3, %0 " :: "m" (s)); \
asm( "lwz r4, %0 " :: "m" (d)); \
asm( "lwz r5, %0 " :: "m" (c)); \
asm( "lwz r6, %0 " :: "m" (b)); \
asm( "addi r3, r3, -4 " ); \
asm( "addi r4, r4, -4 " ); \
asm( "addic r5, r5, 0 " );
#define MULADDC_CORE \
asm( "lwzu r7, 4(r3) " ); \
asm( "mullw r8, r7, r6 " ); \
asm( "mulhwu r9, r7, r6 " ); \
asm( "adde r8, r8, r5 " ); \
asm( "lwz r7, 4(r4) " ); \
asm( "addze r5, r9 " ); \
asm( "addc r8, r8, r7 " ); \
asm( "stwu r8, 4(r4) " );
#define MULADDC_STOP \
asm( "addze r5, r5 " ); \
asm( "addi r4, r4, 4 " ); \
asm( "addi r3, r3, 4 " ); \
asm( "stw r5, %0 " : "=m" (c)); \
asm( "stw r4, %0 " : "=m" (d)); \
asm( "stw r3, %0 " : "=m" (s) :: \
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
#else
#define MULADDC_INIT \
asm( "lwz %%r3, %0 " :: "m" (s)); \
asm( "lwz %%r4, %0 " :: "m" (d)); \
asm( "lwz %%r5, %0 " :: "m" (c)); \
asm( "lwz %%r6, %0 " :: "m" (b)); \
asm( "addi %r3, %r3, -4 " ); \
asm( "addi %r4, %r4, -4 " ); \
asm( "addic %r5, %r5, 0 " );
#define MULADDC_CORE \
asm( "lwzu %r7, 4(%r3) " ); \
asm( "mullw %r8, %r7, %r6 " ); \
asm( "mulhwu %r9, %r7, %r6 " ); \
asm( "adde %r8, %r8, %r5 " ); \
asm( "lwz %r7, 4(%r4) " ); \
asm( "addze %r5, %r9 " ); \
asm( "addc %r8, %r8, %r7 " ); \
asm( "stwu %r8, 4(%r4) " );
#define MULADDC_STOP \
asm( "addze %r5, %r5 " ); \
asm( "addi %r4, %r4, 4 " ); \
asm( "addi %r3, %r3, 4 " ); \
asm( "stw %%r5, %0 " : "=m" (c)); \
asm( "stw %%r4, %0 " : "=m" (d)); \
asm( "stw %%r3, %0 " : "=m" (s) :: \
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
#endif
#endif /* PPC32 */
#endif /* PPC64 */
#if defined(__sparc__)
#define MULADDC_INIT \
asm( "ld %0, %%o0 " :: "m" (s)); \
asm( "ld %0, %%o1 " :: "m" (d)); \
asm( "ld %0, %%o2 " :: "m" (c)); \
asm( "ld %0, %%o3 " :: "m" (b));
#define MULADDC_CORE \
asm( "ld [%o0], %o4 " ); \
asm( "inc 4, %o0 " ); \
asm( "ld [%o1], %o5 " ); \
asm( "umul %o3, %o4, %o4 " ); \
asm( "addcc %o4, %o2, %o4 " ); \
asm( "rd %y, %g1 " ); \
asm( "addx %g1, 0, %g1 " ); \
asm( "addcc %o4, %o5, %o4 " ); \
asm( "st %o4, [%o1] " ); \
asm( "addx %g1, 0, %o2 " ); \
asm( "inc 4, %o1 " );
#define MULADDC_STOP \
asm( "st %%o2, %0 " : "=m" (c)); \
asm( "st %%o1, %0 " : "=m" (d)); \
asm( "st %%o0, %0 " : "=m" (s) :: \
"g1", "o0", "o1", "o2", "o3", "o4", "o5" );
#endif /* SPARCv8 */
#if defined(__microblaze__) || defined(microblaze)
#define MULADDC_INIT \
asm( "lwi r3, %0 " :: "m" (s)); \
asm( "lwi r4, %0 " :: "m" (d)); \
asm( "lwi r5, %0 " :: "m" (c)); \
asm( "lwi r6, %0 " :: "m" (b)); \
asm( "andi r7, r6, 0xffff" ); \
asm( "bsrli r6, r6, 16 " );
#define MULADDC_CORE \
asm( "lhui r8, r3, 0 " ); \
asm( "addi r3, r3, 2 " ); \
asm( "lhui r9, r3, 0 " ); \
asm( "addi r3, r3, 2 " ); \
asm( "mul r10, r9, r6 " ); \
asm( "mul r11, r8, r7 " ); \
asm( "mul r12, r9, r7 " ); \
asm( "mul r13, r8, r6 " ); \
asm( "bsrli r8, r10, 16 " ); \
asm( "bsrli r9, r11, 16 " ); \
asm( "add r13, r13, r8 " ); \
asm( "add r13, r13, r9 " ); \
asm( "bslli r10, r10, 16 " ); \
asm( "bslli r11, r11, 16 " ); \
asm( "add r12, r12, r10 " ); \
asm( "addc r13, r13, r0 " ); \
asm( "add r12, r12, r11 " ); \
asm( "addc r13, r13, r0 " ); \
asm( "lwi r10, r4, 0 " ); \
asm( "add r12, r12, r10 " ); \
asm( "addc r13, r13, r0 " ); \
asm( "add r12, r12, r5 " ); \
asm( "addc r5, r13, r0 " ); \
asm( "swi r12, r4, 0 " ); \
asm( "addi r4, r4, 4 " );
#define MULADDC_STOP \
asm( "swi r5, %0 " : "=m" (c)); \
asm( "swi r4, %0 " : "=m" (d)); \
asm( "swi r3, %0 " : "=m" (s) :: \
"r3", "r4" , "r5" , "r6" , "r7" , "r8" , \
"r9", "r10", "r11", "r12", "r13" );
#endif /* MicroBlaze */
#if defined(__tricore__)
#define MULADDC_INIT \
asm( "ld.a %%a2, %0 " :: "m" (s)); \
asm( "ld.a %%a3, %0 " :: "m" (d)); \
asm( "ld.w %%d4, %0 " :: "m" (c)); \
asm( "ld.w %%d1, %0 " :: "m" (b)); \
asm( "xor %d5, %d5 " );
#define MULADDC_CORE \
asm( "ld.w %d0, [%a2+] " ); \
asm( "madd.u %e2, %e4, %d0, %d1 " ); \
asm( "ld.w %d0, [%a3] " ); \
asm( "addx %d2, %d2, %d0 " ); \
asm( "addc %d3, %d3, 0 " ); \
asm( "mov %d4, %d3 " ); \
asm( "st.w [%a3+], %d2 " );
#define MULADDC_STOP \
asm( "st.w %0, %%d4 " : "=m" (c)); \
asm( "st.a %0, %%a3 " : "=m" (d)); \
asm( "st.a %0, %%a2 " : "=m" (s) :: \
"d0", "d1", "e2", "d4", "a2", "a3" );
#endif /* TriCore */
#if defined(__arm__)
#define MULADDC_INIT \
asm( "ldr r0, %0 " :: "m" (s)); \
asm( "ldr r1, %0 " :: "m" (d)); \
asm( "ldr r2, %0 " :: "m" (c)); \
asm( "ldr r3, %0 " :: "m" (b));
#define MULADDC_CORE \
asm( "ldr r4, [r0], #4 " ); \
asm( "mov r5, #0 " ); \
asm( "ldr r6, [r1] " ); \
asm( "umlal r2, r5, r3, r4 " ); \
asm( "adds r7, r6, r2 " ); \
asm( "adc r2, r5, #0 " ); \
asm( "str r7, [r1], #4 " );
#define MULADDC_STOP \
asm( "str r2, %0 " : "=m" (c)); \
asm( "str r1, %0 " : "=m" (d)); \
asm( "str r0, %0 " : "=m" (s) :: \
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" );
#endif /* ARMv3 */
#if defined(__alpha__)
#define MULADDC_INIT \
asm( "ldq $1, %0 " :: "m" (s)); \
asm( "ldq $2, %0 " :: "m" (d)); \
asm( "ldq $3, %0 " :: "m" (c)); \
asm( "ldq $4, %0 " :: "m" (b));
#define MULADDC_CORE \
asm( "ldq $6, 0($1) " ); \
asm( "addq $1, 8, $1 " ); \
asm( "mulq $6, $4, $7 " ); \
asm( "umulh $6, $4, $6 " ); \
asm( "addq $7, $3, $7 " ); \
asm( "cmpult $7, $3, $3 " ); \
asm( "ldq $5, 0($2) " ); \
asm( "addq $7, $5, $7 " ); \
asm( "cmpult $7, $5, $5 " ); \
asm( "stq $7, 0($2) " ); \
asm( "addq $2, 8, $2 " ); \
asm( "addq $6, $3, $3 " ); \
asm( "addq $5, $3, $3 " );
#define MULADDC_STOP \
asm( "stq $3, %0 " : "=m" (c)); \
asm( "stq $2, %0 " : "=m" (d)); \
asm( "stq $1, %0 " : "=m" (s) :: \
"$1", "$2", "$3", "$4", "$5", "$6", "$7" );
#endif /* Alpha */
#if defined(__mips__)
#define MULADDC_INIT \
asm( "lw $10, %0 " :: "m" (s)); \
asm( "lw $11, %0 " :: "m" (d)); \
asm( "lw $12, %0 " :: "m" (c)); \
asm( "lw $13, %0 " :: "m" (b));
#define MULADDC_CORE \
asm( "lw $14, 0($10) " ); \
asm( "multu $13, $14 " ); \
asm( "addi $10, $10, 4 " ); \
asm( "mflo $14 " ); \
asm( "mfhi $9 " ); \
asm( "addu $14, $12, $14 " ); \
asm( "lw $15, 0($11) " ); \
asm( "sltu $12, $14, $12 " ); \
asm( "addu $15, $14, $15 " ); \
asm( "sltu $14, $15, $14 " ); \
asm( "addu $12, $12, $9 " ); \
asm( "sw $15, 0($11) " ); \
asm( "addu $12, $12, $14 " ); \
asm( "addi $11, $11, 4 " );
#define MULADDC_STOP \
asm( "sw $12, %0 " : "=m" (c)); \
asm( "sw $11, %0 " : "=m" (d)); \
asm( "sw $10, %0 " : "=m" (s) :: \
"$9", "$10", "$11", "$12", "$13", "$14", "$15" );
#endif /* MIPS */
#endif /* GNUC */
#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
#define MULADDC_INIT \
__asm mov esi, s \
__asm mov edi, d \
__asm mov ecx, c \
__asm mov ebx, b
#define MULADDC_CORE \
__asm lodsd \
__asm mul ebx \
__asm add eax, ecx \
__asm adc edx, 0 \
__asm add eax, [edi] \
__asm adc edx, 0 \
__asm mov ecx, edx \
__asm stosd
#if defined(POLARSSL_HAVE_SSE2)
#define EMIT __asm _emit
#define MULADDC_HUIT \
EMIT 0x0F EMIT 0x6E EMIT 0xC9 \
EMIT 0x0F EMIT 0x6E EMIT 0xC3 \
EMIT 0x0F EMIT 0x6E EMIT 0x1F \
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
EMIT 0x0F EMIT 0x6E EMIT 0x16 \
EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \
EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \
EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \
EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \
EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \
EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \
EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCA \
EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \
EMIT 0x0F EMIT 0xD4 EMIT 0xDC \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \
EMIT 0x0F EMIT 0xD4 EMIT 0xEE \
EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \
EMIT 0x0F EMIT 0xD4 EMIT 0xFC \
EMIT 0x0F EMIT 0x7E EMIT 0x0F \
EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \
EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \
EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \
EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \
EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCD \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \
EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCF \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \
EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCA \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \
EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCC \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \
EMIT 0x0F EMIT 0xD4 EMIT 0xDD \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCE \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \
EMIT 0x83 EMIT 0xC7 EMIT 0x20 \
EMIT 0x83 EMIT 0xC6 EMIT 0x20 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0x7E EMIT 0xC9
#define MULADDC_STOP \
EMIT 0x0F EMIT 0x77 \
__asm mov c, ecx \
__asm mov d, edi \
__asm mov s, esi \
#else
#define MULADDC_STOP \
__asm mov c, ecx \
__asm mov d, edi \
__asm mov s, esi \
#endif /* SSE2 */
#endif /* MSVC */
#endif /* POLARSSL_HAVE_ASM */
#if !defined(MULADDC_CORE)
#if defined(POLARSSL_HAVE_LONGLONG)
#define MULADDC_INIT \
{ \
t_dbl r; \
t_int r0, r1;
#define MULADDC_CORE \
r = *(s++) * (t_dbl) b; \
r0 = r; \
r1 = r >> biL; \
r0 += c; r1 += (r0 < c); \
r0 += *d; r1 += (r0 < *d); \
c = r1; *(d++) = r0;
#define MULADDC_STOP \
}
#else
#define MULADDC_INIT \
{ \
t_int s0, s1, b0, b1; \
t_int r0, r1, rx, ry; \
b0 = ( b << biH ) >> biH; \
b1 = ( b >> biH );
#define MULADDC_CORE \
s0 = ( *s << biH ) >> biH; \
s1 = ( *s >> biH ); s++; \
rx = s0 * b1; r0 = s0 * b0; \
ry = s1 * b0; r1 = s1 * b1; \
r1 += ( rx >> biH ); \
r1 += ( ry >> biH ); \
rx <<= biH; ry <<= biH; \
r0 += rx; r1 += (r0 < rx); \
r0 += ry; r1 += (r0 < ry); \
r0 += c; r1 += (r0 < c); \
r0 += *d; r1 += (r0 < *d); \
c = r1; *(d++) = r0;
#define MULADDC_STOP \
}
#endif /* C (generic) */
#endif /* C (longlong) */
#endif /* bn_mul.h */

336
ctrtool/polarssl/config.h Normal file
View File

@ -0,0 +1,336 @@
/**
* \file config.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This set of compile-time options may be used to enable
* or disable features selectively, and reduce the global
* memory footprint.
*/
#ifndef POLARSSL_CONFIG_H
#define POLARSSL_CONFIG_H
#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE 1
#endif
/*
* Uncomment if native integers are 8-bit wide.
*
#define POLARSSL_HAVE_INT8
*/
/*
* Uncomment if native integers are 16-bit wide.
*
#define POLARSSL_HAVE_INT16
*/
/*
* Uncomment if the compiler supports long long.
*
#define POLARSSL_HAVE_LONGLONG
*/
/*
* Uncomment to enable the use of assembly code.
*
* Requires support for asm() in compiler.
*
* Used in:
* library/timing.c
* library/padlock.c
* include/polarssl/bn_mul.h
*
*/
//#define POLARSSL_HAVE_ASM
/*
* Uncomment if the CPU supports SSE2 (IA-32 specific).
*
#define POLARSSL_HAVE_SSE2
*/
/*
* Enable all SSL/TLS debugging messages.
*/
#define POLARSSL_DEBUG_MSG
/*
* Enable the checkup functions (*_self_test).
*/
//#define POLARSSL_SELF_TEST
/*
* Enable run-time version information functions
*/
#define POLARSSL_VERSION_C
/*
* Enable the prime-number generation code.
*/
#define POLARSSL_GENPRIME
/*
* Uncomment this macro to store the AES tables in ROM.
*
#define POLARSSL_AES_ROM_TABLES
*/
/*
* Module: library/aes.c
* Caller: library/ssl_tls.c
*
* This module enables the following ciphersuites:
* SSL_RSA_AES_128_SHA
* SSL_RSA_AES_256_SHA
* SSL_EDH_RSA_AES_256_SHA
*/
#define POLARSSL_AES_C
/*
* Module: library/arc4.c
* Caller: library/ssl_tls.c
*
* This module enables the following ciphersuites:
* SSL_RSA_RC4_128_MD5
* SSL_RSA_RC4_128_SHA
*/
#define POLARSSL_ARC4_C
/*
* Module: library/base64.c
* Caller: library/x509parse.c
*
* This module is required for X.509 support.
*/
#define POLARSSL_BASE64_C
/*
* Module: library/bignum.c
* Caller: library/dhm.c
* library/rsa.c
* library/ssl_tls.c
* library/x509parse.c
*
* This module is required for RSA and DHM support.
*/
#define POLARSSL_BIGNUM_C
/*
* Module: library/camellia.c
* Caller: library/ssl_tls.c
*
* This module enabled the following cipher suites:
* SSL_RSA_CAMELLIA_128_SHA
* SSL_RSA_CAMELLIA_256_SHA
* SSL_EDH_RSA_CAMELLIA_256_SHA
*/
#define POLARSSL_CAMELLIA_C
/*
* Module: library/certs.c
* Caller:
*
* This module is used for testing (ssl_client/server).
*/
#define POLARSSL_CERTS_C
/*
* Module: library/debug.c
* Caller: library/ssl_cli.c
* library/ssl_srv.c
* library/ssl_tls.c
*
* This module provides debugging functions.
*/
#define POLARSSL_DEBUG_C
/*
* Module: library/des.c
* Caller: library/ssl_tls.c
*
* This module enables the following ciphersuites:
* SSL_RSA_DES_168_SHA
* SSL_EDH_RSA_DES_168_SHA
*/
#define POLARSSL_DES_C
/*
* Module: library/dhm.c
* Caller: library/ssl_cli.c
* library/ssl_srv.c
*
* This module enables the following ciphersuites:
* SSL_EDH_RSA_DES_168_SHA
* SSL_EDH_RSA_AES_256_SHA
* SSL_EDH_RSA_CAMELLIA_256_SHA
*/
#define POLARSSL_DHM_C
/*
* Module: library/havege.c
* Caller:
*
* This module enables the HAVEGE random number generator.
*/
#define POLARSSL_HAVEGE_C
/*
* Module: library/md2.c
* Caller: library/x509parse.c
*
* Uncomment to enable support for (rare) MD2-signed X.509 certs.
*
#define POLARSSL_MD2_C
*/
/*
* Module: library/md4.c
* Caller: library/x509parse.c
*
* Uncomment to enable support for (rare) MD4-signed X.509 certs.
*
#define POLARSSL_MD4_C
*/
/*
* Module: library/md5.c
* Caller: library/ssl_tls.c
* library/x509parse.c
*
* This module is required for SSL/TLS and X.509.
*/
#define POLARSSL_MD5_C
/*
* Module: library/net.c
* Caller:
*
* This module provides TCP/IP networking routines.
*/
#define POLARSSL_NET_C
/*
* Module: library/padlock.c
* Caller: library/aes.c
*
* This modules adds support for the VIA PadLock on x86.
*/
#define POLARSSL_PADLOCK_C
/*
* Module: library/rsa.c
* Caller: library/ssl_cli.c
* library/ssl_srv.c
* library/ssl_tls.c
* library/x509.c
*
* This module is required for SSL/TLS and MD5-signed certificates.
*/
#define POLARSSL_RSA_C
/*
* Module: library/sha1.c
* Caller: library/ssl_cli.c
* library/ssl_srv.c
* library/ssl_tls.c
* library/x509parse.c
*
* This module is required for SSL/TLS and SHA1-signed certificates.
*/
#define POLARSSL_SHA1_C
/*
* Module: library/sha2.c
* Caller:
*
* This module adds support for SHA-224 and SHA-256.
*/
#define POLARSSL_SHA2_C
/*
* Module: library/sha4.c
* Caller:
*
* This module adds support for SHA-384 and SHA-512.
*/
#define POLARSSL_SHA4_C
/*
* Module: library/ssl_cli.c
* Caller:
*
* This module is required for SSL/TLS client support.
*/
#define POLARSSL_SSL_CLI_C
/*
* Module: library/ssl_srv.c
* Caller:
*
* This module is required for SSL/TLS server support.
*/
#define POLARSSL_SSL_SRV_C
/*
* Module: library/ssl_tls.c
* Caller: library/ssl_cli.c
* library/ssl_srv.c
*
* This module is required for SSL/TLS.
*/
#define POLARSSL_SSL_TLS_C
/*
* Module: library/timing.c
* Caller: library/havege.c
*
* This module is used by the HAVEGE random number generator.
*/
#define POLARSSL_TIMING_C
/*
* Module: library/x509parse.c
* Caller: library/ssl_cli.c
* library/ssl_srv.c
* library/ssl_tls.c
*
* This module is required for X.509 certificate parsing.
*/
#define POLARSSL_X509_PARSE_C
/*
* Module: library/x509_write.c
* Caller:
*
* This module is required for X.509 certificate writing.
*/
#define POLARSSL_X509_WRITE_C
/*
* Module: library/xtea.c
* Caller:
*/
#define POLARSSL_XTEA_C
#endif /* config.h */

View File

@ -0,0 +1,98 @@
/**
* \file padlock.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_PADLOCK_H
#define POLARSSL_PADLOCK_H
#include "polarssl/aes.h"
#if defined(POLARSSL_HAVE_ASM) && defined(__GNUC__) && defined(__i386__)
#ifndef POLARSSL_HAVE_X86
#define POLARSSL_HAVE_X86
#endif
#define PADLOCK_RNG 0x000C
#define PADLOCK_ACE 0x00C0
#define PADLOCK_PHE 0x0C00
#define PADLOCK_PMM 0x3000
#define PADLOCK_ALIGN16(x) (unsigned long *) (16 + ((long) x & ~15))
#define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED -0x08E0
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief PadLock detection routine
*
* \param The feature to detect
*
* \return 1 if CPU has support for the feature, 0 otherwise
*/
int padlock_supports( int feature );
/**
* \brief PadLock AES-ECB block en(de)cryption
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param input 16-byte input block
* \param output 16-byte output block
*
* \return 0 if success, 1 if operation failed
*/
int padlock_xcryptecb( aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] );
/**
* \brief PadLock AES-CBC buffer en(de)cryption
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if success, 1 if operation failed
*/
int padlock_xcryptcbc( aes_context *ctx,
int mode,
int length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
#ifdef __cplusplus
}
#endif
#endif /* HAVE_X86 */
#endif /* padlock.h */

823
ctrtool/polarssl/rsa.c Normal file
View File

@ -0,0 +1,823 @@
/*
* The RSA public-key cryptosystem
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* RSA was designed by Ron Rivest, Adi Shamir and Len Adleman.
*
* http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
* http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
*/
#include "polarssl/config.h"
#if defined(POLARSSL_RSA_C)
#include "polarssl/rsa.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/*
* Initialize an RSA context
*/
void rsa_init( rsa_context *ctx,
int padding,
int hash_id )
{
memset( ctx, 0, sizeof( rsa_context ) );
ctx->padding = padding;
ctx->hash_id = hash_id;
}
#if defined(POLARSSL_GENPRIME)
/*
* Generate an RSA keypair
*/
int rsa_gen_key( rsa_context *ctx,
int (*f_rng)(void *),
void *p_rng,
int nbits, int exponent )
{
int ret;
mpi P1, Q1, H, G;
if( f_rng == NULL || nbits < 128 || exponent < 3 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
mpi_init( &P1, &Q1, &H, &G, NULL );
/*
* find primes P and Q with Q < P so that:
* GCD( E, (P-1)*(Q-1) ) == 1
*/
MPI_CHK( mpi_lset( &ctx->E, exponent ) );
do
{
MPI_CHK( mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0,
f_rng, p_rng ) );
MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0,
f_rng, p_rng ) );
if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
mpi_swap( &ctx->P, &ctx->Q );
if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 )
continue;
MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
if( mpi_msb( &ctx->N ) != nbits )
continue;
MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) );
}
while( mpi_cmp_int( &G, 1 ) != 0 );
/*
* D = E^-1 mod ((P-1)*(Q-1))
* DP = D mod (P - 1)
* DQ = D mod (Q - 1)
* QP = Q^-1 mod P
*/
MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H ) );
MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
cleanup:
mpi_free( &G, &H, &Q1, &P1, NULL );
if( ret != 0 )
{
rsa_free( ctx );
return( POLARSSL_ERR_RSA_KEY_GEN_FAILED | ret );
}
return( 0 );
}
#endif
/*
* Check a public RSA key
*/
int rsa_check_pubkey( const rsa_context *ctx )
{
if( !ctx->N.p || !ctx->E.p )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
if( ( ctx->N.p[0] & 1 ) == 0 ||
( ctx->E.p[0] & 1 ) == 0 )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
if( mpi_msb( &ctx->N ) < 128 ||
mpi_msb( &ctx->N ) > 4096 )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
if( mpi_msb( &ctx->E ) < 2 ||
mpi_msb( &ctx->E ) > 64 )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
return( 0 );
}
/*
* Check a private RSA key
*/
int rsa_check_privkey( const rsa_context *ctx )
{
int ret;
mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2;
if( ( ret = rsa_check_pubkey( ctx ) ) != 0 )
return( ret );
if( !ctx->P.p || !ctx->Q.p || !ctx->D.p )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
mpi_init( &PQ, &DE, &P1, &Q1, &H, &I, &G, &G2, &L1, &L2, NULL );
MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) );
MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) );
MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) );
MPI_CHK( mpi_gcd( &G2, &P1, &Q1 ) );
MPI_CHK( mpi_div_mpi( &L1, &L2, &H, &G2 ) );
MPI_CHK( mpi_mod_mpi( &I, &DE, &L1 ) );
/*
* Check for a valid PKCS1v2 private key
*/
if( mpi_cmp_mpi( &PQ, &ctx->N ) == 0 &&
mpi_cmp_int( &L2, 0 ) == 0 &&
mpi_cmp_int( &I, 1 ) == 0 &&
mpi_cmp_int( &G, 1 ) == 0 )
{
mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, &G2, &L1, &L2, NULL );
return( 0 );
}
cleanup:
mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, &G2, &L1, &L2, NULL );
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED | ret );
}
/*
* Do an RSA public key operation
*/
int rsa_public( rsa_context *ctx,
const unsigned char *input,
unsigned char *output )
{
int ret, olen;
mpi T;
mpi_init( &T, NULL );
MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
{
mpi_free( &T, NULL );
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
}
olen = ctx->len;
MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
MPI_CHK( mpi_write_binary( &T, output, olen ) );
cleanup:
mpi_free( &T, NULL );
if( ret != 0 )
return( POLARSSL_ERR_RSA_PUBLIC_FAILED | ret );
return( 0 );
}
/*
* Do an RSA private key operation
*/
int rsa_private( rsa_context *ctx,
const unsigned char *input,
unsigned char *output )
{
int ret, olen;
mpi T, T1, T2;
mpi_init( &T, &T1, &T2, NULL );
MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
{
mpi_free( &T, NULL );
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
}
#if 0
MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) );
#else
/*
* faster decryption using the CRT
*
* T1 = input ^ dP mod P
* T2 = input ^ dQ mod Q
*/
MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) );
MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) );
/*
* T = (T1 - T2) * (Q^-1 mod P) mod P
*/
MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) );
MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) );
MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) );
/*
* output = T2 + T * Q
*/
MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) );
MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) );
#endif
olen = ctx->len;
MPI_CHK( mpi_write_binary( &T, output, olen ) );
cleanup:
mpi_free( &T, &T1, &T2, NULL );
if( ret != 0 )
return( POLARSSL_ERR_RSA_PRIVATE_FAILED | ret );
return( 0 );
}
/*
* Add the message padding, then do an RSA operation
*/
int rsa_pkcs1_encrypt( rsa_context *ctx,
int (*f_rng)(void *),
void *p_rng,
int mode, int ilen,
const unsigned char *input,
unsigned char *output )
{
int nb_pad, olen;
unsigned char *p = output;
olen = ctx->len;
switch( ctx->padding )
{
case RSA_PKCS_V15:
if( ilen < 0 || olen < ilen + 11 || f_rng == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
nb_pad = olen - 3 - ilen;
*p++ = 0;
*p++ = RSA_CRYPT;
while( nb_pad-- > 0 )
{
int rng_dl = 100;
do {
*p = (unsigned char) f_rng( p_rng );
} while( *p == 0 && --rng_dl );
// Check if RNG failed to generate data
//
if( rng_dl == 0 )
return POLARSSL_ERR_RSA_RNG_FAILED;
p++;
}
*p++ = 0;
memcpy( p, input, ilen );
break;
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
return( ( mode == RSA_PUBLIC )
? rsa_public( ctx, output, output )
: rsa_private( ctx, output, output ) );
}
/*
* Do an RSA operation, then remove the message padding
*/
int rsa_pkcs1_decrypt( rsa_context *ctx,
int mode, int *olen,
const unsigned char *input,
unsigned char *output,
int output_max_len)
{
int ret, ilen;
unsigned char *p;
unsigned char buf[1024];
ilen = ctx->len;
if( ilen < 16 || ilen > (int) sizeof( buf ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ret = ( mode == RSA_PUBLIC )
? rsa_public( ctx, input, buf )
: rsa_private( ctx, input, buf );
if( ret != 0 )
return( ret );
p = buf;
switch( ctx->padding )
{
case RSA_PKCS_V15:
if( *p++ != 0 || *p++ != RSA_CRYPT )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
while( *p != 0 )
{
if( p >= buf + ilen - 1 )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
p++;
}
p++;
break;
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
if (ilen - (int)(p - buf) > output_max_len)
return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
*olen = ilen - (int)(p - buf);
memcpy( output, p, *olen );
return( 0 );
}
/*
* Do an RSA operation to sign the message digest
*/
int rsa_pkcs1_sign( rsa_context *ctx,
int mode,
int hash_id,
int hashlen,
const unsigned char *hash,
unsigned char *sig )
{
int nb_pad, olen;
unsigned char *p = sig;
olen = ctx->len;
switch( ctx->padding )
{
case RSA_PKCS_V15:
switch( hash_id )
{
case SIG_RSA_RAW:
nb_pad = olen - 3 - hashlen;
break;
case SIG_RSA_MD2:
case SIG_RSA_MD4:
case SIG_RSA_MD5:
nb_pad = olen - 3 - 34;
break;
case SIG_RSA_SHA1:
nb_pad = olen - 3 - 35;
break;
case SIG_RSA_SHA224:
nb_pad = olen - 3 - 47;
break;
case SIG_RSA_SHA256:
nb_pad = olen - 3 - 51;
break;
case SIG_RSA_SHA384:
nb_pad = olen - 3 - 67;
break;
case SIG_RSA_SHA512:
nb_pad = olen - 3 - 83;
break;
default:
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
}
if( nb_pad < 8 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
*p++ = 0;
*p++ = RSA_SIGN;
memset( p, 0xFF, nb_pad );
p += nb_pad;
*p++ = 0;
break;
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
switch( hash_id )
{
case SIG_RSA_RAW:
memcpy( p, hash, hashlen );
break;
case SIG_RSA_MD2:
memcpy( p, ASN1_HASH_MDX, 18 );
memcpy( p + 18, hash, 16 );
p[13] = 2; break;
case SIG_RSA_MD4:
memcpy( p, ASN1_HASH_MDX, 18 );
memcpy( p + 18, hash, 16 );
p[13] = 4; break;
case SIG_RSA_MD5:
memcpy( p, ASN1_HASH_MDX, 18 );
memcpy( p + 18, hash, 16 );
p[13] = 5; break;
case SIG_RSA_SHA1:
memcpy( p, ASN1_HASH_SHA1, 15 );
memcpy( p + 15, hash, 20 );
break;
case SIG_RSA_SHA224:
memcpy( p, ASN1_HASH_SHA2X, 19 );
memcpy( p + 19, hash, 28 );
p[1] += 28; p[14] = 4; p[18] += 28; break;
case SIG_RSA_SHA256:
memcpy( p, ASN1_HASH_SHA2X, 19 );
memcpy( p + 19, hash, 32 );
p[1] += 32; p[14] = 1; p[18] += 32; break;
case SIG_RSA_SHA384:
memcpy( p, ASN1_HASH_SHA2X, 19 );
memcpy( p + 19, hash, 48 );
p[1] += 48; p[14] = 2; p[18] += 48; break;
case SIG_RSA_SHA512:
memcpy( p, ASN1_HASH_SHA2X, 19 );
memcpy( p + 19, hash, 64 );
p[1] += 64; p[14] = 3; p[18] += 64; break;
default:
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
}
return( ( mode == RSA_PUBLIC )
? rsa_public( ctx, sig, sig )
: rsa_private( ctx, sig, sig ) );
}
/*
* Do an RSA operation and check the message digest
*/
int rsa_pkcs1_verify( rsa_context *ctx,
int mode,
int hash_id,
int hashlen,
const unsigned char *hash,
unsigned char *sig )
{
int ret, len, siglen;
unsigned char *p, c;
unsigned char buf[1024];
siglen = ctx->len;
if( siglen < 16 || siglen > (int) sizeof( buf ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ret = ( mode == RSA_PUBLIC )
? rsa_public( ctx, sig, buf )
: rsa_private( ctx, sig, buf );
if( ret != 0 )
return( ret );
p = buf;
switch( ctx->padding )
{
case RSA_PKCS_V15:
if( *p++ != 0 || *p++ != RSA_SIGN )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
while( *p != 0 )
{
if( p >= buf + siglen - 1 || *p != 0xFF )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
p++;
}
p++;
break;
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
len = siglen - (int)( p - buf );
if( len == 34 )
{
c = p[13];
p[13] = 0;
if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( ( c == 2 && hash_id == SIG_RSA_MD2 ) ||
( c == 4 && hash_id == SIG_RSA_MD4 ) ||
( c == 5 && hash_id == SIG_RSA_MD5 ) )
{
if( memcmp( p + 18, hash, 16 ) == 0 )
return( 0 );
else
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
}
}
if( len == 35 && hash_id == SIG_RSA_SHA1 )
{
if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 &&
memcmp( p + 15, hash, 20 ) == 0 )
return( 0 );
else
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
}
if( ( len == 19 + 28 && p[14] == 4 && hash_id == SIG_RSA_SHA224 ) ||
( len == 19 + 32 && p[14] == 1 && hash_id == SIG_RSA_SHA256 ) ||
( len == 19 + 48 && p[14] == 2 && hash_id == SIG_RSA_SHA384 ) ||
( len == 19 + 64 && p[14] == 3 && hash_id == SIG_RSA_SHA512 ) )
{
c = p[1] - 17;
p[1] = 17;
p[14] = 0;
if( p[18] == c &&
memcmp( p, ASN1_HASH_SHA2X, 18 ) == 0 &&
memcmp( p + 19, hash, c ) == 0 )
return( 0 );
else
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
}
if( len == hashlen && hash_id == SIG_RSA_RAW )
{
if( memcmp( p, hash, hashlen ) == 0 )
return( 0 );
else
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
}
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
/*
* Free the components of an RSA key
*/
void rsa_free( rsa_context *ctx )
{
mpi_free( &ctx->RQ, &ctx->RP, &ctx->RN,
&ctx->QP, &ctx->DQ, &ctx->DP,
&ctx->Q, &ctx->P, &ctx->D,
&ctx->E, &ctx->N, NULL );
}
#if defined(POLARSSL_SELF_TEST)
#include "polarssl/sha1.h"
/*
* Example RSA-1024 keypair, for test purposes
*/
#define KEY_LEN 128
#define RSA_N "9292758453063D803DD603D5E777D788" \
"8ED1D5BF35786190FA2F23EBC0848AEA" \
"DDA92CA6C3D80B32C4D109BE0F36D6AE" \
"7130B9CED7ACDF54CFC7555AC14EEBAB" \
"93A89813FBF3C4F8066D2D800F7C38A8" \
"1AE31942917403FF4946B0A83D3D3E05" \
"EE57C6F5F5606FB5D4BC6CD34EE0801A" \
"5E94BB77B07507233A0BC7BAC8F90F79"
#define RSA_E "10001"
#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
"66CA472BC44D253102F8B4A9D3BFA750" \
"91386C0077937FE33FA3252D28855837" \
"AE1B484A8A9A45F7EE8C0C634F99E8CD" \
"DF79C5CE07EE72C7F123142198164234" \
"CABB724CF78B8173B9F880FC86322407" \
"AF1FEDFDDE2BEB674CA15F3E81A1521E" \
"071513A1E85B5DFA031F21ECAE91A34D"
#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
"2C01CAD19EA484A87EA4377637E75500" \
"FCB2005C5C7DD6EC4AC023CDA285D796" \
"C3D9E75E1EFC42488BB4F1D13AC30A57"
#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \
"E211C2B9E5DB1ED0BF61D0D9899620F4" \
"910E4168387E3C30AA1E00C339A79508" \
"8452DD96A9A5EA5D9DCA68DA636032AF"
#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \
"3C94D22288ACD763FD8E5600ED4A702D" \
"F84198A5F06C2E72236AE490C93F07F8" \
"3CC559CD27BC2D1CA488811730BB5725"
#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \
"D8AAEA56749EA28623272E4F7D0592AF" \
"7C1F1313CAC9471B5C523BFE592F517B" \
"407A1BD76C164B93DA2D32A383E58357"
#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \
"F38D18D2B2F0E2DD275AA977E2BF4411" \
"F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
"A74206CEC169D74BF5A8C50D6F48EA08"
#define PT_LEN 24
#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \
"\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"
static int myrand( void *rng_state )
{
if( rng_state != NULL )
rng_state = NULL;
return( rand() );
}
/*
* Checkup routine
*/
int rsa_self_test( int verbose )
{
int len;
rsa_context rsa;
unsigned char sha1sum[20];
unsigned char rsa_plaintext[PT_LEN];
unsigned char rsa_decrypted[PT_LEN];
unsigned char rsa_ciphertext[KEY_LEN];
rsa_init( &rsa, RSA_PKCS_V15, 0 );
rsa.len = KEY_LEN;
mpi_read_string( &rsa.N , 16, RSA_N );
mpi_read_string( &rsa.E , 16, RSA_E );
mpi_read_string( &rsa.D , 16, RSA_D );
mpi_read_string( &rsa.P , 16, RSA_P );
mpi_read_string( &rsa.Q , 16, RSA_Q );
mpi_read_string( &rsa.DP, 16, RSA_DP );
mpi_read_string( &rsa.DQ, 16, RSA_DQ );
mpi_read_string( &rsa.QP, 16, RSA_QP );
if( verbose != 0 )
printf( " RSA key validation: " );
if( rsa_check_pubkey( &rsa ) != 0 ||
rsa_check_privkey( &rsa ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n PKCS#1 encryption : " );
memcpy( rsa_plaintext, RSA_PT, PT_LEN );
if( rsa_pkcs1_encrypt( &rsa, &myrand, NULL, RSA_PUBLIC, PT_LEN,
rsa_plaintext, rsa_ciphertext ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n PKCS#1 decryption : " );
if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len,
rsa_ciphertext, rsa_decrypted,
sizeof(rsa_decrypted) ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n PKCS#1 data sign : " );
sha1( rsa_plaintext, PT_LEN, sha1sum );
if( rsa_pkcs1_sign( &rsa, RSA_PRIVATE, SIG_RSA_SHA1, 20,
sha1sum, rsa_ciphertext ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n PKCS#1 sig. verify: " );
if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20,
sha1sum, rsa_ciphertext ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n\n" );
rsa_free( &rsa );
return( 0 );
}
#endif
#endif

353
ctrtool/polarssl/rsa.h Normal file
View File

@ -0,0 +1,353 @@
/**
* \file rsa.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_RSA_H
#define POLARSSL_RSA_H
#include "polarssl/bignum.h"
/*
* RSA Error codes
*/
#define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x0400
#define POLARSSL_ERR_RSA_INVALID_PADDING -0x0410
#define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x0420
#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x0430
#define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x0440
#define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x0450
#define POLARSSL_ERR_RSA_VERIFY_FAILED -0x0460
#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x0470
#define POLARSSL_ERR_RSA_RNG_FAILED -0x0480
/*
* PKCS#1 constants
*/
#define SIG_RSA_RAW 0
#define SIG_RSA_MD2 2
#define SIG_RSA_MD4 3
#define SIG_RSA_MD5 4
#define SIG_RSA_SHA1 5
#define SIG_RSA_SHA224 14
#define SIG_RSA_SHA256 11
#define SIG_RSA_SHA384 12
#define SIG_RSA_SHA512 13
#define RSA_PUBLIC 0
#define RSA_PRIVATE 1
#define RSA_PKCS_V15 0
#define RSA_PKCS_V21 1
#define RSA_SIGN 1
#define RSA_CRYPT 2
#define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30"
#define ASN1_STR_NULL "\x05"
#define ASN1_STR_OID "\x06"
#define ASN1_STR_OCTET_STRING "\x04"
#define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00"
#define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a"
#define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00"
#define OID_ISO_MEMBER_BODIES "\x2a"
#define OID_ISO_IDENTIFIED_ORG "\x2b"
/*
* ISO Member bodies OID parts
*/
#define OID_COUNTRY_US "\x86\x48"
#define OID_RSA_DATA_SECURITY "\x86\xf7\x0d"
/*
* ISO Identified organization OID parts
*/
#define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a"
/*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm DigestAlgorithmIdentifier,
* digest Digest }
*
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
*
* Digest ::= OCTET STRING
*/
#define ASN1_HASH_MDX \
( \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \
ASN1_STR_OID "\x08" \
OID_DIGEST_ALG_MDX \
ASN1_STR_NULL "\x00" \
ASN1_STR_OCTET_STRING "\x10" \
)
#define ASN1_HASH_SHA1 \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \
ASN1_STR_OID "\x05" \
OID_HASH_ALG_SHA1 \
ASN1_STR_NULL "\x00" \
ASN1_STR_OCTET_STRING "\x14"
#define ASN1_HASH_SHA2X \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \
ASN1_STR_OID "\x09" \
OID_HASH_ALG_SHA2X \
ASN1_STR_NULL "\x00" \
ASN1_STR_OCTET_STRING "\x00"
/**
* \brief RSA context structure
*/
typedef struct
{
int ver; /*!< always 0 */
int len; /*!< size(N) in chars */
mpi N; /*!< public modulus */
mpi E; /*!< public exponent */
mpi D; /*!< private exponent */
mpi P; /*!< 1st prime factor */
mpi Q; /*!< 2nd prime factor */
mpi DP; /*!< D % (P - 1) */
mpi DQ; /*!< D % (Q - 1) */
mpi QP; /*!< 1 / (Q % P) */
mpi RN; /*!< cached R^2 mod N */
mpi RP; /*!< cached R^2 mod P */
mpi RQ; /*!< cached R^2 mod Q */
int padding; /*!< 1.5 or OAEP/PSS */
int hash_id; /*!< hash identifier */
}
rsa_context;
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Initialize an RSA context
*
* \param ctx RSA context to be initialized
* \param padding RSA_PKCS_V15 or RSA_PKCS_V21
* \param hash_id RSA_PKCS_V21 hash identifier
*
* \note The hash_id parameter is actually ignored
* when using RSA_PKCS_V15 padding.
*
* \note Currently, RSA_PKCS_V21 padding
* is not supported.
*/
void rsa_init( rsa_context *ctx,
int padding,
int hash_id);
/**
* \brief Generate an RSA keypair
*
* \param ctx RSA context that will hold the key
* \param f_rng RNG function
* \param p_rng RNG parameter
* \param nbits size of the public key in bits
* \param exponent public exponent (e.g., 65537)
*
* \note rsa_init() must be called beforehand to setup
* the RSA context.
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*/
int rsa_gen_key( rsa_context *ctx,
int (*f_rng)(void *),
void *p_rng,
int nbits, int exponent );
/**
* \brief Check a public RSA key
*
* \param ctx RSA context to be checked
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*/
int rsa_check_pubkey( const rsa_context *ctx );
/**
* \brief Check a private RSA key
*
* \param ctx RSA context to be checked
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*/
int rsa_check_privkey( const rsa_context *ctx );
/**
* \brief Do an RSA public key operation
*
* \param ctx RSA context
* \param input input buffer
* \param output output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note This function does NOT take care of message
* padding. Also, be sure to set input[0] = 0 or assure that
* input is smaller than N.
*
* \note The input and output buffers must be large
* enough (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_public( rsa_context *ctx,
const unsigned char *input,
unsigned char *output );
/**
* \brief Do an RSA private key operation
*
* \param ctx RSA context
* \param input input buffer
* \param output output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The input and output buffers must be large
* enough (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_private( rsa_context *ctx,
const unsigned char *input,
unsigned char *output );
/**
* \brief Add the message padding, then do an RSA operation
*
* \param ctx RSA context
* \param f_rng RNG function
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param ilen contains the plaintext length
* \param input buffer holding the data to be encrypted
* \param output buffer that will hold the ciphertext
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_pkcs1_encrypt( rsa_context *ctx,
int (*f_rng)(void *),
void *p_rng,
int mode, int ilen,
const unsigned char *input,
unsigned char *output );
/**
* \brief Do an RSA operation, then remove the message padding
*
* \param ctx RSA context
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param input buffer holding the encrypted data
* \param output buffer that will hold the plaintext
* \param olen will contain the plaintext length
* \param output_max_len maximum length of the output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
* an error is thrown.
*/
int rsa_pkcs1_decrypt( rsa_context *ctx,
int mode, int *olen,
const unsigned char *input,
unsigned char *output,
int output_max_len );
/**
* \brief Do a private RSA to sign a message digest
*
* \param ctx RSA context
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer that will hold the ciphertext
*
* \return 0 if the signing operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_pkcs1_sign( rsa_context *ctx,
int mode,
int hash_id,
int hashlen,
const unsigned char *hash,
unsigned char *sig );
/**
* \brief Do a public RSA and check the message digest
*
* \param ctx points to an RSA public key
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer holding the ciphertext
*
* \return 0 if the verify operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_pkcs1_verify( rsa_context *ctx,
int mode,
int hash_id,
int hashlen,
const unsigned char *hash,
unsigned char *sig );
/**
* \brief Free the components of an RSA key
*
* \param ctx RSA Context to free
*/
void rsa_free( rsa_context *ctx );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int rsa_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* rsa.h */

702
ctrtool/polarssl/sha2.c Normal file
View File

@ -0,0 +1,702 @@
/*
* FIPS-180-2 compliant SHA-256 implementation
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* The SHA-256 Secure Hash Standard was published by NIST in 2002.
*
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
*/
#include "polarssl/config.h"
#if defined(POLARSSL_SHA2_C)
#include "polarssl/sha2.h"
#include <string.h>
#include <stdio.h>
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
| ( (unsigned long) (b)[(i) + 1] << 16 ) \
| ( (unsigned long) (b)[(i) + 2] << 8 ) \
| ( (unsigned long) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
/*
* SHA-256 context setup
*/
void sha2_starts( sha2_context *ctx, int is224 )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
if( is224 == 0 )
{
/* SHA-256 */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
else
{
/* SHA-224 */
ctx->state[0] = 0xC1059ED8;
ctx->state[1] = 0x367CD507;
ctx->state[2] = 0x3070DD17;
ctx->state[3] = 0xF70E5939;
ctx->state[4] = 0xFFC00B31;
ctx->state[5] = 0x68581511;
ctx->state[6] = 0x64F98FA7;
ctx->state[7] = 0xBEFA4FA4;
}
ctx->is224 = is224;
}
static void sha2_process( sha2_context *ctx, const unsigned char data[64] )
{
unsigned long temp1, temp2, W[64];
unsigned long A, B, C, D, E, F, G, H;
GET_ULONG_BE( W[ 0], data, 0 );
GET_ULONG_BE( W[ 1], data, 4 );
GET_ULONG_BE( W[ 2], data, 8 );
GET_ULONG_BE( W[ 3], data, 12 );
GET_ULONG_BE( W[ 4], data, 16 );
GET_ULONG_BE( W[ 5], data, 20 );
GET_ULONG_BE( W[ 6], data, 24 );
GET_ULONG_BE( W[ 7], data, 28 );
GET_ULONG_BE( W[ 8], data, 32 );
GET_ULONG_BE( W[ 9], data, 36 );
GET_ULONG_BE( W[10], data, 40 );
GET_ULONG_BE( W[11], data, 44 );
GET_ULONG_BE( W[12], data, 48 );
GET_ULONG_BE( W[13], data, 52 );
GET_ULONG_BE( W[14], data, 56 );
GET_ULONG_BE( W[15], data, 60 );
#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
#define F0(x,y,z) ((x & y) | (z & (x | y)))
#define F1(x,y,z) (z ^ (x & (y ^ z)))
#define R(t) \
( \
W[t] = S1(W[t - 2]) + W[t - 7] + \
S0(W[t - 15]) + W[t - 16] \
)
#define P(a,b,c,d,e,f,g,h,x,K) \
{ \
temp1 = h + S3(e) + F1(e,f,g) + K + x; \
temp2 = S2(a) + F0(a,b,c); \
d += temp1; h = temp1 + temp2; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
F = ctx->state[5];
G = ctx->state[6];
H = ctx->state[7];
P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );
P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );
P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );
P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );
P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );
P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );
P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );
P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );
P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );
P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );
P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );
P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );
P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );
P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );
P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );
P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );
P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );
P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );
P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );
P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );
P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );
P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );
P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );
P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );
P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );
P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );
P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );
P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );
P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );
P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );
P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );
P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );
P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );
P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );
P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );
P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );
P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );
P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );
P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );
P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );
P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );
P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );
P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );
P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );
P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );
P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );
P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );
P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );
P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );
P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );
P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );
P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );
P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );
P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );
P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );
P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );
P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );
P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );
P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );
P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );
P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );
P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );
P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );
P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
ctx->state[5] += F;
ctx->state[6] += G;
ctx->state[7] += H;
}
/*
* SHA-256 process buffer
*/
void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen )
{
int fill;
unsigned long left;
if( ilen <= 0 )
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (unsigned long) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, fill );
sha2_process( ctx, ctx->buffer );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
sha2_process( ctx, input );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, ilen );
}
}
static const unsigned char sha2_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SHA-256 final digest
*/
void sha2_finish( sha2_context *ctx, unsigned char output[32] )
{
unsigned long last, padn;
unsigned long high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_ULONG_BE( high, msglen, 0 );
PUT_ULONG_BE( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
sha2_update( ctx, (unsigned char *) sha2_padding, padn );
sha2_update( ctx, msglen, 8 );
PUT_ULONG_BE( ctx->state[0], output, 0 );
PUT_ULONG_BE( ctx->state[1], output, 4 );
PUT_ULONG_BE( ctx->state[2], output, 8 );
PUT_ULONG_BE( ctx->state[3], output, 12 );
PUT_ULONG_BE( ctx->state[4], output, 16 );
PUT_ULONG_BE( ctx->state[5], output, 20 );
PUT_ULONG_BE( ctx->state[6], output, 24 );
if( ctx->is224 == 0 )
PUT_ULONG_BE( ctx->state[7], output, 28 );
}
/*
* output = SHA-256( input buffer )
*/
void sha2( const unsigned char *input, int ilen,
unsigned char output[32], int is224 )
{
sha2_context ctx;
sha2_starts( &ctx, is224 );
sha2_update( &ctx, input, ilen );
sha2_finish( &ctx, output );
memset( &ctx, 0, sizeof( sha2_context ) );
}
/*
* output = SHA-256( file contents )
*/
int sha2_file( const char *path, unsigned char output[32], int is224 )
{
FILE *f;
size_t n;
sha2_context ctx;
unsigned char buf[1024];
if( ( f = fopen( path, "rb" ) ) == NULL )
return( 1 );
sha2_starts( &ctx, is224 );
while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
sha2_update( &ctx, buf, (int) n );
sha2_finish( &ctx, output );
memset( &ctx, 0, sizeof( sha2_context ) );
if( ferror( f ) != 0 )
{
fclose( f );
return( 2 );
}
fclose( f );
return( 0 );
}
/*
* SHA-256 HMAC context setup
*/
void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, int keylen,
int is224 )
{
int i;
unsigned char sum[32];
if( keylen > 64 )
{
sha2( key, keylen, sum, is224 );
keylen = ( is224 ) ? 28 : 32;
key = sum;
}
memset( ctx->ipad, 0x36, 64 );
memset( ctx->opad, 0x5C, 64 );
for( i = 0; i < keylen; i++ )
{
ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
}
sha2_starts( ctx, is224 );
sha2_update( ctx, ctx->ipad, 64 );
memset( sum, 0, sizeof( sum ) );
}
/*
* SHA-256 HMAC process buffer
*/
void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, int ilen )
{
sha2_update( ctx, input, ilen );
}
/*
* SHA-256 HMAC final digest
*/
void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] )
{
int is224, hlen;
unsigned char tmpbuf[32];
is224 = ctx->is224;
hlen = ( is224 == 0 ) ? 32 : 28;
sha2_finish( ctx, tmpbuf );
sha2_starts( ctx, is224 );
sha2_update( ctx, ctx->opad, 64 );
sha2_update( ctx, tmpbuf, hlen );
sha2_finish( ctx, output );
memset( tmpbuf, 0, sizeof( tmpbuf ) );
}
/*
* SHA-256 HMAC context reset
*/
void sha2_hmac_reset( sha2_context *ctx )
{
sha2_starts( ctx, ctx->is224 );
sha2_update( ctx, ctx->ipad, 64 );
}
/*
* output = HMAC-SHA-256( hmac key, input buffer )
*/
void sha2_hmac( const unsigned char *key, int keylen,
const unsigned char *input, int ilen,
unsigned char output[32], int is224 )
{
sha2_context ctx;
sha2_hmac_starts( &ctx, key, keylen, is224 );
sha2_hmac_update( &ctx, input, ilen );
sha2_hmac_finish( &ctx, output );
memset( &ctx, 0, sizeof( sha2_context ) );
}
#if defined(POLARSSL_SELF_TEST)
/*
* FIPS-180-2 test vectors
*/
static unsigned char sha2_test_buf[3][57] =
{
{ "abc" },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
{ "" }
};
static const int sha2_test_buflen[3] =
{
3, 56, 1000
};
static const unsigned char sha2_test_sum[6][32] =
{
/*
* SHA-224 test vectors
*/
{ 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
0xE3, 0x6C, 0x9D, 0xA7 },
{ 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
0x52, 0x52, 0x25, 0x25 },
{ 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
0x4E, 0xE7, 0xAD, 0x67 },
/*
* SHA-256 test vectors
*/
{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
{ 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
};
/*
* RFC 4231 test vectors
*/
static unsigned char sha2_hmac_test_key[7][26] =
{
{ "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
"\x0B\x0B\x0B\x0B" },
{ "Jefe" },
{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
"\xAA\xAA\xAA\xAA" },
{ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
"\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
{ "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
"\x0C\x0C\x0C\x0C" },
{ "" }, /* 0xAA 131 times */
{ "" }
};
static const int sha2_hmac_test_keylen[7] =
{
20, 4, 20, 25, 20, 131, 131
};
static unsigned char sha2_hmac_test_buf[7][153] =
{
{ "Hi There" },
{ "what do ya want for nothing?" },
{ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
{ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
{ "Test With Truncation" },
{ "Test Using Larger Than Block-Size Key - Hash Key First" },
{ "This is a test using a larger than block-size key "
"and a larger than block-size data. The key needs to "
"be hashed before being used by the HMAC algorithm." }
};
static const int sha2_hmac_test_buflen[7] =
{
8, 28, 50, 50, 20, 54, 152
};
static const unsigned char sha2_hmac_test_sum[14][32] =
{
/*
* HMAC-SHA-224 test vectors
*/
{ 0x89, 0x6F, 0xB1, 0x12, 0x8A, 0xBB, 0xDF, 0x19,
0x68, 0x32, 0x10, 0x7C, 0xD4, 0x9D, 0xF3, 0x3F,
0x47, 0xB4, 0xB1, 0x16, 0x99, 0x12, 0xBA, 0x4F,
0x53, 0x68, 0x4B, 0x22 },
{ 0xA3, 0x0E, 0x01, 0x09, 0x8B, 0xC6, 0xDB, 0xBF,
0x45, 0x69, 0x0F, 0x3A, 0x7E, 0x9E, 0x6D, 0x0F,
0x8B, 0xBE, 0xA2, 0xA3, 0x9E, 0x61, 0x48, 0x00,
0x8F, 0xD0, 0x5E, 0x44 },
{ 0x7F, 0xB3, 0xCB, 0x35, 0x88, 0xC6, 0xC1, 0xF6,
0xFF, 0xA9, 0x69, 0x4D, 0x7D, 0x6A, 0xD2, 0x64,
0x93, 0x65, 0xB0, 0xC1, 0xF6, 0x5D, 0x69, 0xD1,
0xEC, 0x83, 0x33, 0xEA },
{ 0x6C, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3C, 0xAC,
0x6A, 0x2A, 0xBC, 0x1B, 0xB3, 0x82, 0x62, 0x7C,
0xEC, 0x6A, 0x90, 0xD8, 0x6E, 0xFC, 0x01, 0x2D,
0xE7, 0xAF, 0xEC, 0x5A },
{ 0x0E, 0x2A, 0xEA, 0x68, 0xA9, 0x0C, 0x8D, 0x37,
0xC9, 0x88, 0xBC, 0xDB, 0x9F, 0xCA, 0x6F, 0xA8 },
{ 0x95, 0xE9, 0xA0, 0xDB, 0x96, 0x20, 0x95, 0xAD,
0xAE, 0xBE, 0x9B, 0x2D, 0x6F, 0x0D, 0xBC, 0xE2,
0xD4, 0x99, 0xF1, 0x12, 0xF2, 0xD2, 0xB7, 0x27,
0x3F, 0xA6, 0x87, 0x0E },
{ 0x3A, 0x85, 0x41, 0x66, 0xAC, 0x5D, 0x9F, 0x02,
0x3F, 0x54, 0xD5, 0x17, 0xD0, 0xB3, 0x9D, 0xBD,
0x94, 0x67, 0x70, 0xDB, 0x9C, 0x2B, 0x95, 0xC9,
0xF6, 0xF5, 0x65, 0xD1 },
/*
* HMAC-SHA-256 test vectors
*/
{ 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53,
0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B,
0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7,
0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 },
{ 0x5B, 0xDC, 0xC1, 0x46, 0xBF, 0x60, 0x75, 0x4E,
0x6A, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xC7,
0x5A, 0x00, 0x3F, 0x08, 0x9D, 0x27, 0x39, 0x83,
0x9D, 0xEC, 0x58, 0xB9, 0x64, 0xEC, 0x38, 0x43 },
{ 0x77, 0x3E, 0xA9, 0x1E, 0x36, 0x80, 0x0E, 0x46,
0x85, 0x4D, 0xB8, 0xEB, 0xD0, 0x91, 0x81, 0xA7,
0x29, 0x59, 0x09, 0x8B, 0x3E, 0xF8, 0xC1, 0x22,
0xD9, 0x63, 0x55, 0x14, 0xCE, 0xD5, 0x65, 0xFE },
{ 0x82, 0x55, 0x8A, 0x38, 0x9A, 0x44, 0x3C, 0x0E,
0xA4, 0xCC, 0x81, 0x98, 0x99, 0xF2, 0x08, 0x3A,
0x85, 0xF0, 0xFA, 0xA3, 0xE5, 0x78, 0xF8, 0x07,
0x7A, 0x2E, 0x3F, 0xF4, 0x67, 0x29, 0x66, 0x5B },
{ 0xA3, 0xB6, 0x16, 0x74, 0x73, 0x10, 0x0E, 0xE0,
0x6E, 0x0C, 0x79, 0x6C, 0x29, 0x55, 0x55, 0x2B },
{ 0x60, 0xE4, 0x31, 0x59, 0x1E, 0xE0, 0xB6, 0x7F,
0x0D, 0x8A, 0x26, 0xAA, 0xCB, 0xF5, 0xB7, 0x7F,
0x8E, 0x0B, 0xC6, 0x21, 0x37, 0x28, 0xC5, 0x14,
0x05, 0x46, 0x04, 0x0F, 0x0E, 0xE3, 0x7F, 0x54 },
{ 0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB,
0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44,
0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93,
0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2 }
};
/*
* Checkup routine
*/
int sha2_self_test( int verbose )
{
int i, j, k, buflen;
unsigned char buf[1024];
unsigned char sha2sum[32];
sha2_context ctx;
for( i = 0; i < 6; i++ )
{
j = i % 3;
k = i < 3;
if( verbose != 0 )
printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 );
sha2_starts( &ctx, k );
if( j == 2 )
{
memset( buf, 'a', buflen = 1000 );
for( j = 0; j < 1000; j++ )
sha2_update( &ctx, buf, buflen );
}
else
sha2_update( &ctx, sha2_test_buf[j],
sha2_test_buflen[j] );
sha2_finish( &ctx, sha2sum );
if( memcmp( sha2sum, sha2_test_sum[i], 32 - k * 4 ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n" );
}
if( verbose != 0 )
printf( "\n" );
for( i = 0; i < 14; i++ )
{
j = i % 7;
k = i < 7;
if( verbose != 0 )
printf( " HMAC-SHA-%d test #%d: ", 256 - k * 32, j + 1 );
if( j == 5 || j == 6 )
{
memset( buf, '\xAA', buflen = 131 );
sha2_hmac_starts( &ctx, buf, buflen, k );
}
else
sha2_hmac_starts( &ctx, sha2_hmac_test_key[j],
sha2_hmac_test_keylen[j], k );
sha2_hmac_update( &ctx, sha2_hmac_test_buf[j],
sha2_hmac_test_buflen[j] );
sha2_hmac_finish( &ctx, sha2sum );
buflen = ( j == 4 ) ? 16 : 32 - k * 4;
if( memcmp( sha2sum, sha2_hmac_test_sum[i], buflen ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n" );
}
if( verbose != 0 )
printf( "\n" );
return( 0 );
}
#endif
#endif

155
ctrtool/polarssl/sha2.h Normal file
View File

@ -0,0 +1,155 @@
/**
* \file sha2.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_SHA2_H
#define POLARSSL_SHA2_H
/**
* \brief SHA-256 context structure
*/
typedef struct
{
unsigned long total[2]; /*!< number of bytes processed */
unsigned long state[8]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
unsigned char ipad[64]; /*!< HMAC: inner padding */
unsigned char opad[64]; /*!< HMAC: outer padding */
int is224; /*!< 0 => SHA-256, else SHA-224 */
}
sha2_context;
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief SHA-256 context setup
*
* \param ctx context to be initialized
* \param is224 0 = use SHA256, 1 = use SHA224
*/
void sha2_starts( sha2_context *ctx, int is224 );
/**
* \brief SHA-256 process buffer
*
* \param ctx SHA-256 context
* \param input buffer holding the data
* \param ilen length of the input data
*/
void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen );
/**
* \brief SHA-256 final digest
*
* \param ctx SHA-256 context
* \param output SHA-224/256 checksum result
*/
void sha2_finish( sha2_context *ctx, unsigned char output[32] );
/**
* \brief Output = SHA-256( input buffer )
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output SHA-224/256 checksum result
* \param is224 0 = use SHA256, 1 = use SHA224
*/
void sha2( const unsigned char *input, int ilen,
unsigned char output[32], int is224 );
/**
* \brief Output = SHA-256( file contents )
*
* \param path input file name
* \param output SHA-224/256 checksum result
* \param is224 0 = use SHA256, 1 = use SHA224
*
* \return 0 if successful, 1 if fopen failed,
* or 2 if fread failed
*/
int sha2_file( const char *path, unsigned char output[32], int is224 );
/**
* \brief SHA-256 HMAC context setup
*
* \param ctx HMAC context to be initialized
* \param key HMAC secret key
* \param keylen length of the HMAC key
* \param is224 0 = use SHA256, 1 = use SHA224
*/
void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, int keylen,
int is224 );
/**
* \brief SHA-256 HMAC process buffer
*
* \param ctx HMAC context
* \param input buffer holding the data
* \param ilen length of the input data
*/
void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, int ilen );
/**
* \brief SHA-256 HMAC final digest
*
* \param ctx HMAC context
* \param output SHA-224/256 HMAC checksum result
*/
void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] );
/**
* \brief SHA-256 HMAC context reset
*
* \param ctx HMAC context to be reset
*/
void sha2_hmac_reset( sha2_context *ctx );
/**
* \brief Output = HMAC-SHA-256( hmac key, input buffer )
*
* \param key HMAC secret key
* \param keylen length of the HMAC key
* \param input buffer holding the data
* \param ilen length of the input data
* \param output HMAC-SHA-224/256 result
* \param is224 0 = use SHA256, 1 = use SHA224
*/
void sha2_hmac( const unsigned char *key, int keylen,
const unsigned char *input, int ilen,
unsigned char output[32], int is224 );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int sha2_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* sha2.h */

352
ctrtool/romfs.c Normal file
View File

@ -0,0 +1,352 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "types.h"
#include "romfs.h"
#include "utils.h"
void romfs_init(romfs_context* ctx)
{
memset(ctx, 0, sizeof(romfs_context));
ivfc_init(&ctx->ivfc);
}
void romfs_set_file(romfs_context* ctx, FILE* file)
{
ctx->file = file;
}
void romfs_set_offset(romfs_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void romfs_set_size(romfs_context* ctx, u32 size)
{
ctx->size = size;
}
void romfs_set_usersettings(romfs_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void romfs_process(romfs_context* ctx, u32 actions)
{
u32 dirblockoffset = 0;
u32 dirblocksize = 0;
u32 fileblockoffset = 0;
u32 fileblocksize = 0;
ivfc_set_offset(&ctx->ivfc, ctx->offset);
ivfc_set_size(&ctx->ivfc, ctx->size);
ivfc_set_file(&ctx->ivfc, ctx->file);
ivfc_set_usersettings(&ctx->ivfc, ctx->usersettings);
ivfc_process(&ctx->ivfc, actions);
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(&ctx->header, 1, sizeof(romfs_header), ctx->file);
if (getle32(ctx->header.magic) != MAGIC_IVFC)
{
fprintf(stdout, "Error, RomFS corrupted\n");
return;
}
ctx->infoblockoffset = ctx->offset + 0x1000;
fseek(ctx->file, ctx->infoblockoffset, SEEK_SET);
fread(&ctx->infoheader, 1, sizeof(romfs_infoheader), ctx->file);
if (getle32(ctx->infoheader.headersize) != sizeof(romfs_infoheader))
{
fprintf(stderr, "Error, info header mismatch\n");
return;
}
dirblockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.section[1].offset);
dirblocksize = getle32(ctx->infoheader.section[1].size);
fileblockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.section[3].offset);
fileblocksize = getle32(ctx->infoheader.section[3].size);
ctx->dirblock = malloc(dirblocksize);
ctx->dirblocksize = dirblocksize;
ctx->fileblock = malloc(fileblocksize);
ctx->fileblocksize = fileblocksize;
ctx->datablockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.dataoffset);
if (ctx->dirblock)
{
fseek(ctx->file, dirblockoffset, SEEK_SET);
fread(ctx->dirblock, 1, dirblocksize, ctx->file);
}
if (ctx->fileblock)
{
fseek(ctx->file, fileblockoffset, SEEK_SET);
fread(ctx->fileblock, 1, fileblocksize, ctx->file);
}
if (actions & InfoFlag)
romfs_print(ctx);
romfs_visit_dir(ctx, 0, 0, actions, settings_get_romfs_dir_path(ctx->usersettings));
}
int romfs_dirblock_read(romfs_context* ctx, u32 diroffset, u32 dirsize, void* buffer)
{
if (!ctx->dirblock)
return 0;
if (diroffset+dirsize > ctx->dirblocksize)
return 0;
memcpy(buffer, ctx->dirblock + diroffset, dirsize);
return 1;
}
int romfs_dirblock_readentry(romfs_context* ctx, u32 diroffset, romfs_direntry* entry)
{
u32 size_without_name = sizeof(romfs_direntry) - ROMFS_MAXNAMESIZE;
u32 namesize;
if (!ctx->dirblock)
return 0;
if (!romfs_dirblock_read(ctx, diroffset, size_without_name, entry))
return 0;
namesize = getle32(entry->namesize);
if (namesize > (ROMFS_MAXNAMESIZE-2))
namesize = (ROMFS_MAXNAMESIZE-2);
memset(entry->name + namesize, 0, 2);
if (!romfs_dirblock_read(ctx, diroffset + size_without_name, namesize, entry->name))
return 0;
return 1;
}
int romfs_fileblock_read(romfs_context* ctx, u32 fileoffset, u32 filesize, void* buffer)
{
if (!ctx->fileblock)
return 0;
if (fileoffset+filesize > ctx->fileblocksize)
return 0;
memcpy(buffer, ctx->fileblock + fileoffset, filesize);
return 1;
}
int romfs_fileblock_readentry(romfs_context* ctx, u32 fileoffset, romfs_fileentry* entry)
{
u32 size_without_name = sizeof(romfs_fileentry) - ROMFS_MAXNAMESIZE;
u32 namesize;
if (!ctx->fileblock)
return 0;
if (!romfs_fileblock_read(ctx, fileoffset, size_without_name, entry))
return 0;
namesize = getle32(entry->namesize);
if (namesize > (ROMFS_MAXNAMESIZE-2))
namesize = (ROMFS_MAXNAMESIZE-2);
memset(entry->name + namesize, 0, 2);
if (!romfs_fileblock_read(ctx, fileoffset + size_without_name, namesize, entry->name))
return 0;
return 1;
}
void romfs_visit_dir(romfs_context* ctx, u32 diroffset, u32 depth, u32 actions, filepath* rootpath)
{
u32 siblingoffset;
u32 childoffset;
u32 fileoffset;
filepath currentpath;
romfs_direntry* entry = &ctx->direntry;
if (!romfs_dirblock_readentry(ctx, diroffset, entry))
return;
// fprintf(stdout, "%08X %08X %08X %08X %08X ",
// getle32(entry->parentoffset), getle32(entry->siblingoffset), getle32(entry->childoffset),
// getle32(entry->fileoffset), getle32(entry->weirdoffset));
// fwprintf(stdout, L"%ls\n", entry->name);
if (rootpath && rootpath->valid)
{
filepath_copy(&currentpath, rootpath);
filepath_append_utf16(&currentpath, entry->name);
if (currentpath.valid)
{
makedir(currentpath.pathname);
}
else
{
fprintf(stderr, "Error creating directory in root %s\n", rootpath->pathname);
return;
}
}
else
{
filepath_init(&currentpath);
if (settings_get_list_romfs_files(ctx->usersettings))
{
u32 i;
for(i=0; i<depth; i++)
printf(" ");
fwprintf(stdout, L"%ls\n", entry->name);
}
}
siblingoffset = getle32(entry->siblingoffset);
childoffset = getle32(entry->childoffset);
fileoffset = getle32(entry->fileoffset);
if (fileoffset != (~0))
romfs_visit_file(ctx, fileoffset, depth+1, actions, &currentpath);
if (childoffset != (~0))
romfs_visit_dir(ctx, childoffset, depth+1, actions, &currentpath);
if (siblingoffset != (~0))
romfs_visit_dir(ctx, siblingoffset, depth, actions, rootpath);
}
void romfs_visit_file(romfs_context* ctx, u32 fileoffset, u32 depth, u32 actions, filepath* rootpath)
{
u32 siblingoffset = 0;
filepath currentpath;
romfs_fileentry* entry = &ctx->fileentry;
if (!romfs_fileblock_readentry(ctx, fileoffset, entry))
return;
// fprintf(stdout, "%08X %08X %016llX %016llX %08X ",
// getle32(entry->parentdiroffset), getle32(entry->siblingoffset), ctx->datablockoffset+getle64(entry->dataoffset),
// getle64(entry->datasize), getle32(entry->unknown));
// fwprintf(stdout, L"%ls\n", entry->name);
if (rootpath && rootpath->valid)
{
filepath_copy(&currentpath, rootpath);
filepath_append_utf16(&currentpath, entry->name);
if (currentpath.valid)
{
fprintf(stdout, "Saving %s...\n", currentpath.pathname);
romfs_extract_datafile(ctx, getle64(entry->dataoffset), getle64(entry->datasize), &currentpath);
}
else
{
fprintf(stderr, "Error creating directory in root %s\n", rootpath->pathname);
return;
}
}
else
{
filepath_init(&currentpath);
if (settings_get_list_romfs_files(ctx->usersettings))
{
u32 i;
for(i=0; i<depth; i++)
printf(" ");
fwprintf(stdout, L"%ls\n", entry->name);
}
}
siblingoffset = getle32(entry->siblingoffset);
if (siblingoffset != (~0))
romfs_visit_file(ctx, siblingoffset, depth, actions, rootpath);
}
void romfs_extract_datafile(romfs_context* ctx, u64 offset, u64 size, filepath* path)
{
FILE* outfile = 0;
u32 max;
u8 buffer[4096];
if (path == 0 || path->valid == 0)
goto clean;
offset += ctx->datablockoffset;
if ( (offset >> 32) )
{
fprintf(stderr, "Error, support for 64-bit offset not yet implemented.\n");
goto clean;
}
fseek(ctx->file, offset, SEEK_SET);
outfile = fopen(path->pathname, "wb");
if (outfile == 0)
{
fprintf(stderr, "Error opening file for writing\n");
goto clean;
}
while(size)
{
max = sizeof(buffer);
if (max > size)
max = size;
if (max != fread(buffer, 1, max, ctx->file))
{
fprintf(stderr, "Error reading file\n");
goto clean;
}
if (max != fwrite(buffer, 1, max, outfile))
{
fprintf(stderr, "Error writing file\n");
goto clean;
}
size -= max;
}
clean:
if (outfile)
fclose(outfile);
}
void romfs_print(romfs_context* ctx)
{
u32 i;
fprintf(stdout, "\nRomFS:\n");
fprintf(stdout, "Header size: 0x%08X\n", getle32(ctx->infoheader.headersize));
for(i=0; i<4; i++)
{
fprintf(stdout, "Section %d offset: 0x%08X\n", i, ctx->offset + 0x1000 + getle32(ctx->infoheader.section[i].offset));
fprintf(stdout, "Section %d size: 0x%08X\n", i, getle32(ctx->infoheader.section[i].size));
}
fprintf(stdout, "Data offset: 0x%08X\n", ctx->offset + 0x1000 + getle32(ctx->infoheader.dataoffset));
}

90
ctrtool/romfs.h Normal file
View File

@ -0,0 +1,90 @@
#ifndef __ROMFS_H__
#define __ROMFS_H__
#include "types.h"
#include "info.h"
#include "ctr.h"
#include "filepath.h"
#include "settings.h"
#include "ivfc.h"
#define ROMFS_MAXNAMESIZE 254 // limit set by ctrtool
typedef struct
{
u8 magic[4];
} romfs_header;
typedef struct
{
u8 offset[4];
u8 size[4];
} romfs_sectionheader;
typedef struct
{
u8 headersize[4];
romfs_sectionheader section[4];
u8 dataoffset[4];
} romfs_infoheader;
typedef struct
{
u8 parentoffset[4];
u8 siblingoffset[4];
u8 childoffset[4];
u8 fileoffset[4];
u8 weirdoffset[4]; // this one is weird. it always points to a dir entry, but seems unrelated to the romfs structure.
u8 namesize[4];
u8 name[ROMFS_MAXNAMESIZE];
} romfs_direntry;
typedef struct
{
u8 parentdiroffset[4];
u8 siblingoffset[4];
u8 dataoffset[8];
u8 datasize[8];
u8 weirdoffset[4]; // this one is also weird. it always points to a file entry, but seems unrelated to the romfs structure.
u8 namesize[4];
u8 name[ROMFS_MAXNAMESIZE];
} romfs_fileentry;
typedef struct
{
FILE* file;
settings* usersettings;
u32 offset;
u32 size;
romfs_header header;
romfs_infoheader infoheader;
u8* dirblock;
u32 dirblocksize;
u8* fileblock;
u32 fileblocksize;
u32 datablockoffset;
u32 infoblockoffset;
romfs_direntry direntry;
romfs_fileentry fileentry;
ivfc_context ivfc;
} romfs_context;
void romfs_init(romfs_context* ctx);
void romfs_set_file(romfs_context* ctx, FILE* file);
void romfs_set_offset(romfs_context* ctx, u32 offset);
void romfs_set_size(romfs_context* ctx, u32 size);
void romfs_set_usersettings(romfs_context* ctx, settings* usersettings);
void romfs_test(romfs_context* ctx);
int romfs_dirblock_read(romfs_context* ctx, u32 diroffset, u32 dirsize, void* buffer);
int romfs_dirblock_readentry(romfs_context* ctx, u32 diroffset, romfs_direntry* entry);
int romfs_fileblock_read(romfs_context* ctx, u32 fileoffset, u32 filesize, void* buffer);
int romfs_fileblock_readentry(romfs_context* ctx, u32 fileoffset, romfs_fileentry* entry);
void romfs_visit_dir(romfs_context* ctx, u32 diroffset, u32 depth, u32 actions, filepath* rootpath);
void romfs_visit_file(romfs_context* ctx, u32 fileoffset, u32 depth, u32 actions, filepath* rootpath);
void romfs_extract_datafile(romfs_context* ctx, u64 offset, u64 size, filepath* path);
void romfs_process(romfs_context* ctx, u32 actions);
void romfs_print(romfs_context* ctx);
#endif // __ROMFS_H__

256
ctrtool/settings.c Normal file
View File

@ -0,0 +1,256 @@
#include <stdio.h>
#include <string.h>
#include "settings.h"
void settings_init(settings* usersettings)
{
memset(usersettings, 0, sizeof(settings));
}
filepath* settings_get_wav_path(settings* usersettings)
{
if (usersettings)
return &usersettings->wavpath;
else
return 0;
}
filepath* settings_get_lzss_path(settings* usersettings)
{
if (usersettings)
return &usersettings->lzsspath;
else
return 0;
}
filepath* settings_get_exefs_path(settings* usersettings)
{
if (usersettings)
return &usersettings->exefspath;
else
return 0;
}
filepath* settings_get_romfs_path(settings* usersettings)
{
if (usersettings)
return &usersettings->romfspath;
else
return 0;
}
filepath* settings_get_exheader_path(settings* usersettings)
{
if (usersettings)
return &usersettings->exheaderpath;
else
return 0;
}
filepath* settings_get_exefs_dir_path(settings* usersettings)
{
if (usersettings)
return &usersettings->exefsdirpath;
else
return 0;
}
filepath* settings_get_romfs_dir_path(settings* usersettings)
{
if (usersettings)
return &usersettings->romfsdirpath;
else
return 0;
}
filepath* settings_get_firm_dir_path(settings* usersettings)
{
if (usersettings)
return &usersettings->firmdirpath;
else
return 0;
}
filepath* settings_get_certs_path(settings* usersettings)
{
if (usersettings)
return &usersettings->certspath;
else
return 0;
}
filepath* settings_get_tik_path(settings* usersettings)
{
if (usersettings)
return &usersettings->tikpath;
else
return 0;
}
filepath* settings_get_tmd_path(settings* usersettings)
{
if (usersettings)
return &usersettings->tmdpath;
else
return 0;
}
filepath* settings_get_meta_path(settings* usersettings)
{
if (usersettings)
return &usersettings->metapath;
else
return 0;
}
filepath* settings_get_content_path(settings* usersettings)
{
if (usersettings)
return &usersettings->contentpath;
else
return 0;
}
unsigned int settings_get_mediaunit_size(settings* usersettings)
{
if (usersettings)
return usersettings->mediaunitsize;
else
return 0;
}
unsigned char* settings_get_ncch_key(settings* usersettings)
{
if (usersettings && usersettings->keys.ncchkey.valid)
return usersettings->keys.ncchkey.data;
else
return 0;
}
unsigned char* settings_get_ncch_fixedsystemkey(settings* usersettings)
{
if (usersettings && usersettings->keys.ncchfixedsystemkey.valid)
return usersettings->keys.ncchfixedsystemkey.data;
else
return 0;
}
unsigned char* settings_get_common_key(settings* usersettings)
{
if (usersettings && usersettings->keys.commonkey.valid)
return usersettings->keys.commonkey.data;
else
return 0;
}
int settings_get_ignore_programid(settings* usersettings)
{
if (usersettings)
return usersettings->ignoreprogramid;
else
return 0;
}
int settings_get_list_romfs_files(settings* usersettings)
{
if (usersettings)
return usersettings->listromfs;
else
return 0;
}
int settings_get_cwav_loopcount(settings* usersettings)
{
if (usersettings)
return usersettings->cwavloopcount;
else
return 0;
}
void settings_set_wav_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->wavpath, path);
}
void settings_set_lzss_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->lzsspath, path);
}
void settings_set_exefs_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->exefspath, path);
}
void settings_set_romfs_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->romfspath, path);
}
void settings_set_firm_dir_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->firmdirpath, path);
}
void settings_set_exheader_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->exheaderpath, path);
}
void settings_set_certs_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->certspath, path);
}
void settings_set_tik_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->tikpath, path);
}
void settings_set_tmd_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->tmdpath, path);
}
void settings_set_meta_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->metapath, path);
}
void settings_set_content_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->contentpath, path);
}
void settings_set_exefs_dir_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->exefsdirpath, path);
}
void settings_set_romfs_dir_path(settings* usersettings, const char* path)
{
filepath_set(&usersettings->romfsdirpath, path);
}
void settings_set_mediaunit_size(settings* usersettings, unsigned int size)
{
usersettings->mediaunitsize = size;
}
void settings_set_ignore_programid(settings* usersettings, int enable)
{
usersettings->ignoreprogramid = enable;
}
void settings_set_list_romfs_files(settings* usersettings, int enable)
{
usersettings->listromfs = enable;
}
void settings_set_cwav_loopcount(settings* usersettings, u32 loopcount)
{
usersettings->cwavloopcount = loopcount;
}

70
ctrtool/settings.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef _SETTINGS_H_
#define _SETTINGS_H_
#include "types.h"
#include "keyset.h"
#include "filepath.h"
typedef struct
{
keyset keys;
filepath exefspath;
filepath exefsdirpath;
filepath firmdirpath;
filepath romfspath;
filepath romfsdirpath;
filepath exheaderpath;
filepath certspath;
filepath contentpath;
filepath tikpath;
filepath tmdpath;
filepath metapath;
filepath lzsspath;
filepath wavpath;
unsigned int mediaunitsize;
int ignoreprogramid;
int listromfs;
u32 cwavloopcount;
} settings;
void settings_init(settings* usersettings);
filepath* settings_get_lzss_path(settings* usersettings);
filepath* settings_get_exefs_path(settings* usersettings);
filepath* settings_get_romfs_path(settings* usersettings);
filepath* settings_get_exheader_path(settings* usersettings);
filepath* settings_get_certs_path(settings* usersettings);
filepath* settings_get_tik_path(settings* usersettings);
filepath* settings_get_tmd_path(settings* usersettings);
filepath* settings_get_meta_path(settings* usersettings);
filepath* settings_get_content_path(settings* usersettings);
filepath* settings_get_exefs_dir_path(settings* usersettings);
filepath* settings_get_romfs_dir_path(settings* usersettings);
filepath* settings_get_firm_dir_path(settings* usersettings);
filepath* settings_get_wav_path(settings* usersettings);
unsigned int settings_get_mediaunit_size(settings* usersettings);
unsigned char* settings_get_ncch_key(settings* usersettings);
unsigned char* settings_get_ncch_fixedsystemkey(settings* usersettings);
unsigned char* settings_get_common_key(settings* usersettings);
int settings_get_ignore_programid(settings* usersettings);
int settings_get_list_romfs_files(settings* usersettings);
int settings_get_cwav_loopcount(settings* usersettings);
void settings_set_lzss_path(settings* usersettings, const char* path);
void settings_set_exefs_path(settings* usersettings, const char* path);
void settings_set_romfs_path(settings* usersettings, const char* path);
void settings_set_exheader_path(settings* usersettings, const char* path);
void settings_set_certs_path(settings* usersettings, const char* path);
void settings_set_tik_path(settings* usersettings, const char* path);
void settings_set_tmd_path(settings* usersettings, const char* path);
void settings_set_meta_path(settings* usersettings, const char* path);
void settings_set_content_path(settings* usersettings, const char* path);
void settings_set_exefs_dir_path(settings* usersettings, const char* path);
void settings_set_romfs_dir_path(settings* usersettings, const char* path);
void settings_set_firm_dir_path(settings* usersettings, const char* path);
void settings_set_wav_path(settings* usersettings, const char* path);
void settings_set_mediaunit_size(settings* usersettings, unsigned int size);
void settings_set_ignore_programid(settings* usersettings, int enable);
void settings_set_list_romfs_files(settings* usersettings, int enable);
void settings_set_cwav_loopcount(settings* usersettings, u32 loopcount);
#endif // _SETTINGS_H_

138
ctrtool/stream.c Normal file
View File

@ -0,0 +1,138 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "stream.h"
void stream_in_init(stream_in_context* ctx)
{
memset(ctx, 0, sizeof(stream_in_context));
}
void stream_out_init(stream_out_context* ctx)
{
memset(ctx, 0, sizeof(stream_out_context));
}
void stream_in_allocate(stream_in_context* ctx, u32 buffersize, FILE* file)
{
ctx->inbuffer = malloc(buffersize);
ctx->inbuffersize = buffersize;
ctx->infile = file;
ctx->infileposition = 0;
}
void stream_out_allocate(stream_out_context* ctx, u32 buffersize, FILE* file)
{
ctx->outbuffer = malloc(buffersize);
ctx->outbuffersize = buffersize;
ctx->outfile = file;
}
void stream_in_destroy(stream_in_context* ctx)
{
free(ctx->inbuffer);
ctx->inbuffer = 0;
}
void stream_out_destroy(stream_out_context* ctx)
{
free(ctx->outbuffer);
ctx->outbuffer = 0;
}
int stream_in_byte(stream_in_context* ctx, u8* byte)
{
if (ctx->inbufferpos >= ctx->inbufferavailable)
{
size_t readbytes = fread(ctx->inbuffer, 1, ctx->inbuffersize, ctx->infile);
if (readbytes <= 0)
return 0;
ctx->inbufferavailable = readbytes;
ctx->inbufferpos = 0;
ctx->infileposition += readbytes;
}
*byte = ctx->inbuffer[ctx->inbufferpos++];
return 1;
}
void stream_in_seek(stream_in_context* ctx, u32 position)
{
fseek(ctx->infile, position, SEEK_SET);
ctx->infileposition = position;
ctx->inbufferpos = 0;
ctx->inbufferavailable = 0;
}
void stream_in_reseek(stream_in_context* ctx)
{
fseek(ctx->infile, ctx->infileposition, SEEK_SET);
}
void stream_out_seek(stream_out_context* ctx, u32 position)
{
stream_out_flush(ctx);
fseek(ctx->outfile, position, SEEK_SET);
}
void stream_out_skip(stream_out_context* ctx, u32 size)
{
stream_out_flush(ctx);
fseek(ctx->outfile, size, SEEK_CUR);
}
int stream_out_byte(stream_out_context* ctx, u8 byte)
{
if (ctx->outbufferpos >= ctx->outbuffersize)
{
if (stream_out_flush(ctx) == 0)
return 0;
}
ctx->outbuffer[ctx->outbufferpos++] = byte;
return 1;
}
int stream_out_buffer(stream_out_context* ctx, const void* buffer, u32 size)
{
u32 i;
for(i=0; i<size; i++)
{
if (!stream_out_byte(ctx, ((u8*)buffer)[i]))
return 0;
}
return 1;
}
int stream_out_flush(stream_out_context* ctx)
{
if (ctx->outbufferpos > 0)
{
size_t writtenbytes = fwrite(ctx->outbuffer, 1, ctx->outbufferpos, ctx->outfile);
if (writtenbytes < 0)
return 0;
ctx->outbufferpos = 0;
}
return 1;
}
void stream_out_position(stream_out_context* ctx, u32* position)
{
stream_out_flush(ctx);
*position = ftell(ctx->outfile);
}

45
ctrtool/stream.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef __STREAM_H__
#define __STREAM_H__
#include <stdio.h>
#include "types.h"
typedef struct
{
FILE* infile;
u32 infileposition;
u8* inbuffer;
u32 inbuffersize;
u32 inbufferavailable;
u32 inbufferpos;
} stream_in_context;
typedef struct
{
FILE* outfile;
u8* outbuffer;
u32 outbuffersize;
u32 outbufferpos;
} stream_out_context;
// create/destroy
void stream_in_init(stream_in_context* ctx);
void stream_in_allocate(stream_in_context* ctx, u32 buffersize, FILE* file);
void stream_in_destroy(stream_in_context* ctx);
void stream_out_init(stream_out_context* ctx);
void stream_out_allocate(stream_out_context* ctx, u32 buffersize, FILE* file);
void stream_out_destroy(stream_out_context* ctx);
// read/write operations
int stream_in_byte(stream_in_context* ctx, u8* byte);
void stream_in_seek(stream_in_context* ctx, u32 position);
void stream_in_reseek(stream_in_context* ctx);
int stream_out_byte(stream_out_context* ctx, u8 byte);
int stream_out_buffer(stream_out_context* ctx, const void* buffer, u32 size);
int stream_out_flush(stream_out_context* ctx);
void stream_out_seek(stream_out_context* ctx, u32 position);
void stream_out_skip(stream_out_context* ctx, u32 size);
void stream_out_position(stream_out_context* ctx, u32* position);
#endif // __STREAM_H__

127
ctrtool/tik.c Normal file
View File

@ -0,0 +1,127 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "tik.h"
#include "ctr.h"
#include "utils.h"
void tik_init(tik_context* ctx)
{
memset(ctx, 0, sizeof(tik_context));
}
void tik_set_file(tik_context* ctx, FILE* file)
{
ctx->file = file;
}
void tik_set_offset(tik_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void tik_set_size(tik_context* ctx, u32 size)
{
ctx->size = size;
}
void tik_set_usersettings(tik_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void tik_get_decrypted_titlekey(tik_context* ctx, u8 decryptedkey[0x10])
{
memcpy(decryptedkey, ctx->titlekey, 16);
}
void tik_get_titleid(tik_context* ctx, u8 titleid[8])
{
memcpy(titleid, ctx->tik.title_id, 8);
}
void tik_get_iv(tik_context* ctx, u8 iv[16])
{
memset(iv, 0, 16);
memcpy(iv, ctx->tik.title_id, 8);
}
void tik_decrypt_titlekey(tik_context* ctx, u8 decryptedkey[0x10])
{
u8 iv[16];
u8* key = settings_get_common_key(ctx->usersettings);
memset(decryptedkey, 0, 0x10);
if (!key)
{
fprintf(stdout, "Warning, could not read common key.\n");
}
else
{
memset(iv, 0, 0x10);
memcpy(iv, ctx->tik.title_id, 8);
ctr_init_cbc_decrypt(&ctx->aes, key, iv);
ctr_decrypt_cbc(&ctx->aes, ctx->tik.encrypted_title_key, decryptedkey, 0x10);
}
}
void tik_process(tik_context* ctx, u32 actions)
{
if (ctx->size < sizeof(eticket))
{
fprintf(stderr, "Error, ticket size too small\n");
goto clean;
}
fseek(ctx->file, ctx->offset, SEEK_SET);
fread((u8*)&ctx->tik, 1, sizeof(eticket), ctx->file);
tik_decrypt_titlekey(ctx, ctx->titlekey);
if (actions & InfoFlag)
{
tik_print(ctx);
}
clean:
return;
}
void tik_print(tik_context* ctx)
{
int i;
eticket* tik = &ctx->tik;
fprintf(stdout, "\nTicket content:\n");
fprintf(stdout,
"Signature Type: %08x\n"
"Issuer: %s\n",
getle32(tik->sig_type), tik->issuer
);
fprintf(stdout, "Signature:\n");
hexdump(tik->signature, 0x100);
fprintf(stdout, "\n");
memdump(stdout, "Encrypted Titlekey: ", tik->encrypted_title_key, 0x10);
if (settings_get_common_key(ctx->usersettings))
memdump(stdout, "Decrypted Titlekey: ", ctx->titlekey, 0x10);
memdump(stdout, "Ticket ID: ", tik->ticket_id, 0x08);
fprintf(stdout, "Ticket Version: %d\n", getle16(tik->ticket_version));
memdump(stdout, "Title ID: ", tik->title_id, 0x08);
fprintf(stdout, "Common Key Index: %d\n", tik->commonkey_idx);
fprintf(stdout, "Content permission map:\n");
for(i = 0; i < 0x40; i++) {
printf(" %02x", tik->content_permissions[i]);
if ((i+1) % 8 == 0)
printf("\n");
}
printf("\n");
}

64
ctrtool/tik.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef __TIK_H__
#define __TIK_H__
#include "types.h"
#include "keyset.h"
#include "ctr.h"
#include "settings.h"
typedef struct
{
u8 enable_timelimit[4];
u8 timelimit_seconds[4];
} timelimit_entry;
typedef struct
{
u8 sig_type[4];
u8 signature[0x100];
u8 padding1[0x3c];
u8 issuer[0x40];
u8 ecdsa[0x3c];
u8 padding2[0x03];
u8 encrypted_title_key[0x10];
u8 unknown;
u8 ticket_id[8];
u8 console_id[4];
u8 title_id[8];
u8 sys_access[2];
u8 ticket_version[2];
u8 time_mask[4];
u8 permit_mask[4];
u8 title_export;
u8 commonkey_idx;
u8 unknown_buf[0x30];
u8 content_permissions[0x40];
u8 padding0[2];
timelimit_entry timelimits[8];
} eticket;
typedef struct
{
FILE* file;
u32 offset;
u32 size;
u8 titlekey[16];
eticket tik;
ctr_aes_context aes;
settings* usersettings;
} tik_context;
void tik_init(tik_context* ctx);
void tik_set_file(tik_context* ctx, FILE* file);
void tik_set_offset(tik_context* ctx, u32 offset);
void tik_set_size(tik_context* ctx, u32 size);
void tik_set_usersettings(tik_context* ctx, settings* usersettings);
void tik_get_decrypted_titlekey(tik_context* ctx, u8 decryptedkey[0x10]);
void tik_get_titleid(tik_context* ctx, u8 titleid[8]);
void tik_get_iv(tik_context* ctx, u8 iv[0x10]);
void tik_decrypt_titlekey(tik_context* ctx, u8 decryptedkey[0x10]);
void tik_print(tik_context* ctx);
void tik_process(tik_context* ctx, u32 actions);
#endif

111
ctrtool/tinyxml/tinystr.cpp Normal file
View File

@ -0,0 +1,111 @@
/*
www.sourceforge.net/projects/tinyxml
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef TIXML_USE_STL
#include "tinyxml/tinystr.h"
// Error value for find primitive
const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
// Null rep.
TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
void TiXmlString::reserve (size_type cap)
{
if (cap > capacity())
{
TiXmlString tmp;
tmp.init(length(), cap);
memcpy(tmp.start(), data(), length());
swap(tmp);
}
}
TiXmlString& TiXmlString::assign(const char* str, size_type len)
{
size_type cap = capacity();
if (len > cap || cap > 3*(len + 8))
{
TiXmlString tmp;
tmp.init(len);
memcpy(tmp.start(), str, len);
swap(tmp);
}
else
{
memmove(start(), str, len);
set_size(len);
}
return *this;
}
TiXmlString& TiXmlString::append(const char* str, size_type len)
{
size_type newsize = length() + len;
if (newsize > capacity())
{
reserve (newsize + capacity());
}
memmove(finish(), str, len);
set_size(newsize);
return *this;
}
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
{
TiXmlString tmp;
tmp.reserve(a.length() + b.length());
tmp += a;
tmp += b;
return tmp;
}
TiXmlString operator + (const TiXmlString & a, const char* b)
{
TiXmlString tmp;
TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
tmp.reserve(a.length() + b_len);
tmp += a;
tmp.append(b, b_len);
return tmp;
}
TiXmlString operator + (const char* a, const TiXmlString & b)
{
TiXmlString tmp;
TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
tmp.reserve(a_len + b.length());
tmp.append(a, a_len);
tmp += b;
return tmp;
}
#endif // TIXML_USE_STL

305
ctrtool/tinyxml/tinystr.h Normal file
View File

@ -0,0 +1,305 @@
/*
www.sourceforge.net/projects/tinyxml
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef TIXML_USE_STL
#ifndef TIXML_STRING_INCLUDED
#define TIXML_STRING_INCLUDED
#include <assert.h>
#include <string.h>
/* The support for explicit isn't that universal, and it isn't really
required - it is used to check that the TiXmlString class isn't incorrectly
used. Be nice to old compilers and macro it here:
*/
#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
// Microsoft visual studio, version 6 and higher.
#define TIXML_EXPLICIT explicit
#elif defined(__GNUC__) && (__GNUC__ >= 3 )
// GCC version 3 and higher.s
#define TIXML_EXPLICIT explicit
#else
#define TIXML_EXPLICIT
#endif
/*
TiXmlString is an emulation of a subset of the std::string template.
Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
Only the member functions relevant to the TinyXML project have been implemented.
The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
a string and there's no more room, we allocate a buffer twice as big as we need.
*/
class TiXmlString
{
public :
// The size type used
typedef size_t size_type;
// Error value for find primitive
static const size_type npos; // = -1;
// TiXmlString empty constructor
TiXmlString () : rep_(&nullrep_)
{
}
// TiXmlString copy constructor
TiXmlString ( const TiXmlString & copy) : rep_(0)
{
init(copy.length());
memcpy(start(), copy.data(), length());
}
// TiXmlString constructor, based on a string
TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
{
init( static_cast<size_type>( strlen(copy) ));
memcpy(start(), copy, length());
}
// TiXmlString constructor, based on a string
TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
{
init(len);
memcpy(start(), str, len);
}
// TiXmlString destructor
~TiXmlString ()
{
quit();
}
TiXmlString& operator = (const char * copy)
{
return assign( copy, (size_type)strlen(copy));
}
TiXmlString& operator = (const TiXmlString & copy)
{
return assign(copy.start(), copy.length());
}
// += operator. Maps to append
TiXmlString& operator += (const char * suffix)
{
return append(suffix, static_cast<size_type>( strlen(suffix) ));
}
// += operator. Maps to append
TiXmlString& operator += (char single)
{
return append(&single, 1);
}
// += operator. Maps to append
TiXmlString& operator += (const TiXmlString & suffix)
{
return append(suffix.data(), suffix.length());
}
// Convert a TiXmlString into a null-terminated char *
const char * c_str () const { return rep_->str; }
// Convert a TiXmlString into a char * (need not be null terminated).
const char * data () const { return rep_->str; }
// Return the length of a TiXmlString
size_type length () const { return rep_->size; }
// Alias for length()
size_type size () const { return rep_->size; }
// Checks if a TiXmlString is empty
bool empty () const { return rep_->size == 0; }
// Return capacity of string
size_type capacity () const { return rep_->capacity; }
// single char extraction
const char& at (size_type index) const
{
assert( index < length() );
return rep_->str[ index ];
}
// [] operator
char& operator [] (size_type index) const
{
assert( index < length() );
return rep_->str[ index ];
}
// find a char in a string. Return TiXmlString::npos if not found
size_type find (char lookup) const
{
return find(lookup, 0);
}
// find a char in a string from an offset. Return TiXmlString::npos if not found
size_type find (char tofind, size_type offset) const
{
if (offset >= length()) return npos;
for (const char* p = c_str() + offset; *p != '\0'; ++p)
{
if (*p == tofind) return static_cast< size_type >( p - c_str() );
}
return npos;
}
void clear ()
{
//Lee:
//The original was just too strange, though correct:
// TiXmlString().swap(*this);
//Instead use the quit & re-init:
quit();
init(0,0);
}
/* Function to reserve a big amount of data when we know we'll need it. Be aware that this
function DOES NOT clear the content of the TiXmlString if any exists.
*/
void reserve (size_type cap);
TiXmlString& assign (const char* str, size_type len);
TiXmlString& append (const char* str, size_type len);
void swap (TiXmlString& other)
{
Rep* r = rep_;
rep_ = other.rep_;
other.rep_ = r;
}
private:
void init(size_type sz) { init(sz, sz); }
void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
char* start() const { return rep_->str; }
char* finish() const { return rep_->str + rep_->size; }
struct Rep
{
size_type size, capacity;
char str[1];
};
void init(size_type sz, size_type cap)
{
if (cap)
{
// Lee: the original form:
// rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
// doesn't work in some cases of new being overloaded. Switching
// to the normal allocation, although use an 'int' for systems
// that are overly picky about structure alignment.
const size_type bytesNeeded = sizeof(Rep) + cap;
const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
rep_->str[ rep_->size = sz ] = '\0';
rep_->capacity = cap;
}
else
{
rep_ = &nullrep_;
}
}
void quit()
{
if (rep_ != &nullrep_)
{
// The rep_ is really an array of ints. (see the allocator, above).
// Cast it back before delete, so the compiler won't incorrectly call destructors.
delete [] ( reinterpret_cast<int*>( rep_ ) );
}
}
Rep * rep_;
static Rep nullrep_;
} ;
inline bool operator == (const TiXmlString & a, const TiXmlString & b)
{
return ( a.length() == b.length() ) // optimization on some platforms
&& ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare
}
inline bool operator < (const TiXmlString & a, const TiXmlString & b)
{
return strcmp(a.c_str(), b.c_str()) < 0;
}
inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; }
inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
TiXmlString operator + (const TiXmlString & a, const char* b);
TiXmlString operator + (const char* a, const TiXmlString & b);
/*
TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
Only the operators that we need for TinyXML have been developped.
*/
class TiXmlOutStream : public TiXmlString
{
public :
// TiXmlOutStream << operator.
TiXmlOutStream & operator << (const TiXmlString & in)
{
*this += in;
return *this;
}
// TiXmlOutStream << operator.
TiXmlOutStream & operator << (const char * in)
{
*this += in;
return *this;
}
} ;
#endif // TIXML_STRING_INCLUDED
#endif // TIXML_USE_STL

1886
ctrtool/tinyxml/tinyxml.cpp Normal file

File diff suppressed because it is too large Load Diff

1805
ctrtool/tinyxml/tinyxml.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
/*
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "tinyxml/tinyxml.h"
// The goal of the seperate error file is to make the first
// step towards localization. tinyxml (currently) only supports
// english error messages, but the could now be translated.
//
// It also cleans up the code a bit.
//
const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] =
{
"No error",
"Error",
"Failed to open file",
"Error parsing Element.",
"Failed to read Element name",
"Error reading Element value.",
"Error reading Attributes.",
"Error: empty tag.",
"Error reading end tag.",
"Error parsing Unknown.",
"Error parsing Comment.",
"Error parsing Declaration.",
"Error document empty.",
"Error null (0) or unexpected EOF found in input stream.",
"Error parsing CDATA.",
"Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
};

File diff suppressed because it is too large Load Diff

169
ctrtool/tmd.c Normal file
View File

@ -0,0 +1,169 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "tmd.h"
#include "utils.h"
void tmd_init(tmd_context* ctx)
{
memset(ctx, 0, sizeof(tmd_context));
}
void tmd_set_file(tmd_context* ctx, FILE* file)
{
ctx->file = file;
}
void tmd_set_offset(tmd_context* ctx, u32 offset)
{
ctx->offset = offset;
}
void tmd_set_size(tmd_context* ctx, u32 size)
{
ctx->size = size;
}
void tmd_set_usersettings(tmd_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
}
void tmd_process(tmd_context* ctx, u32 actions)
{
if (ctx->buffer == 0)
ctx->buffer = malloc(ctx->size);
if (ctx->buffer)
{
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(ctx->buffer, 1, ctx->size, ctx->file);
if (actions & InfoFlag)
{
tmd_print(ctx);
}
}
}
ctr_tmd_body *tmd_get_body(tmd_context *ctx)
{
unsigned int type = getbe32(ctx->buffer);
ctr_tmd_body *body = NULL;
if (type == TMD_RSA_2048_SHA256 || type == TMD_RSA_2048_SHA1)
{
body = (ctr_tmd_body*)(ctx->buffer + sizeof(ctr_tmd_header_2048));
}
else if (type == TMD_RSA_4096_SHA256 || type == TMD_RSA_4096_SHA1)
{
body = (ctr_tmd_body*)(ctx->buffer + sizeof(ctr_tmd_header_4096));
}
return body;
}
const char* tmd_get_type_string(unsigned int type)
{
switch(type)
{
case TMD_RSA_2048_SHA256: return "RSA 2048 - SHA256";
case TMD_RSA_4096_SHA256: return "RSA 4096 - SHA256";
case TMD_RSA_2048_SHA1: return "RSA 2048 - SHA1";
case TMD_RSA_4096_SHA1: return "RSA 4096 - SHA1";
default:
return "unknown";
}
}
void tmd_print(tmd_context* ctx)
{
unsigned int type = getbe32(ctx->buffer);
ctr_tmd_header_4096* header4096 = 0;
ctr_tmd_header_2048* header2048 = 0;
ctr_tmd_body* body = 0;
unsigned int contentcount = 0;
unsigned int i;
if (type == TMD_RSA_2048_SHA256 || type == TMD_RSA_2048_SHA1)
{
header2048 = (ctr_tmd_header_2048*)ctx->buffer;
}
else if (type == TMD_RSA_4096_SHA256 || type == TMD_RSA_4096_SHA1)
{
header4096 = (ctr_tmd_header_4096*)ctx->buffer;
}
else
{
return;
}
body = tmd_get_body(ctx);
contentcount = getbe16(body->contentcount);
fprintf(stdout, "\nTMD header:\n");
fprintf(stdout, "Signature type: %s\n", tmd_get_type_string(type));
fprintf(stdout, "Issuer: %s\n", body->issuer);
fprintf(stdout, "Version: %d\n", body->version);
fprintf(stdout, "CA CRL version: %d\n", body->ca_crl_version);
fprintf(stdout, "Signer CRL version: %d\n", body->signer_crl_version);
memdump(stdout, "System version: ", body->systemversion, 8);
memdump(stdout, "Title id: ", body->titleid, 8);
fprintf(stdout, "Title type: %08x\n", getbe32(body->titletype));
fprintf(stdout, "Group id: %04x\n", getbe16(body->groupid));
fprintf(stdout, "Access rights: %08x\n", getbe32(body->accessrights));
fprintf(stdout, "Title version: %04x\n", getbe16(body->titleversion));
fprintf(stdout, "Content count: %04x\n", getbe16(body->contentcount));
fprintf(stdout, "Boot content: %04x\n", getbe16(body->bootcontent));
memdump(stdout, "Hash: ", body->hash, 32);
fprintf(stdout, "\nTMD content info:\n");
for(i = 0; i < TMD_MAX_CONTENTS; i++)
{
ctr_tmd_contentinfo* info = (ctr_tmd_contentinfo*)(body->contentinfo + sizeof(ctr_tmd_contentinfo)*i);
if (getbe16(info->commandcount) == 0)
continue;
fprintf(stdout, "Content index: %04x\n", getbe16(info->index));
fprintf(stdout, "Command count: %04x\n", getbe16(info->commandcount));
memdump(stdout, "Unknown: ", info->unk, 32);
}
fprintf(stdout, "\nTMD contents:\n");
for(i = 0; i < contentcount; i++)
{
ctr_tmd_contentchunk* chunk = (ctr_tmd_contentchunk*)(body->contentinfo + 36*64 + i*48);
unsigned short type = getbe16(chunk->type);
fprintf(stdout, "Content id: %08x\n", getbe32(chunk->id));
fprintf(stdout, "Content index: %04x\n", getbe16(chunk->index));
fprintf(stdout, "Content type: %04x", getbe16(chunk->type));
if (type)
{
fprintf(stdout, " ");
if (type & 1)
fprintf(stdout, "[encrypted]");
if (type & 2)
fprintf(stdout, "[disc]");
if (type & 4)
fprintf(stdout, "[cfm]");
if (type & 0x4000)
fprintf(stdout, "[optional]");
if (type & 0x8000)
fprintf(stdout, "[shared]");
}
fprintf(stdout, "\n");
fprintf(stdout, "Content size: %016llx\n", getbe64(chunk->size));
switch(ctx->content_hash_stat[getbe16(chunk->index)]) {
case 1: memdump(stdout, "Content hash [OK]: ", chunk->hash, 32); break;
case 2: memdump(stdout, "Content hash [FAIL]: ", chunk->hash, 32); break;
default: memdump(stdout, "Content hash: ", chunk->hash, 32); break;
}
fprintf(stdout, "\n");
}
}

99
ctrtool/tmd.h Normal file
View File

@ -0,0 +1,99 @@
#ifndef _TMD_H_
#define _TMD_H_
#include "types.h"
#include "settings.h"
#define TMD_MAX_CONTENTS 64
typedef enum
{
TMD_RSA_2048_SHA256 = 0x00010004,
TMD_RSA_4096_SHA256 = 0x00010003,
TMD_RSA_2048_SHA1 = 0x00010001,
TMD_RSA_4096_SHA1 = 0x00010000
} ctr_tmdtype;
typedef struct
{
unsigned char padding[60];
unsigned char issuer[64];
unsigned char version;
unsigned char ca_crl_version;
unsigned char signer_crl_version;
unsigned char padding2;
unsigned char systemversion[8];
unsigned char titleid[8];
unsigned char titletype[4];
unsigned char groupid[2];
unsigned char padding3[62];
unsigned char accessrights[4];
unsigned char titleversion[2];
unsigned char contentcount[2];
unsigned char bootcontent[2];
unsigned char padding4[2];
unsigned char hash[32];
unsigned char contentinfo[36*64];
} ctr_tmd_body;
typedef struct
{
unsigned char index[2];
unsigned char commandcount[2];
unsigned char unk[32];
} ctr_tmd_contentinfo;
typedef struct
{
unsigned char id[4];
unsigned char index[2];
unsigned char type[2];
unsigned char size[8];
unsigned char hash[32];
} ctr_tmd_contentchunk;
typedef struct
{
unsigned char signaturetype[4];
unsigned char signature[256];
} ctr_tmd_header_2048;
typedef struct
{
unsigned char signaturetype[4];
unsigned char signature[512];
} ctr_tmd_header_4096;
typedef struct
{
FILE* file;
u32 offset;
u32 size;
u8* buffer;
u8 content_hash_stat[64];
settings* usersettings;
} tmd_context;
#ifdef __cplusplus
extern "C" {
#endif
void tmd_init(tmd_context* ctx);
void tmd_set_file(tmd_context* ctx, FILE* file);
void tmd_set_offset(tmd_context* ctx, u32 offset);
void tmd_set_size(tmd_context* ctx, u32 size);
void tmd_set_usersettings(tmd_context* ctx, settings* usersettings);
void tmd_print(tmd_context* ctx);
void tmd_process(tmd_context* ctx, u32 actions);
ctr_tmd_body *tmd_get_body(tmd_context *ctx);
#ifdef __cplusplus
}
#endif
#endif // _TMD_H_

36
ctrtool/types.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef __TYPES_H__
#define __TYPES_H__
#include <stdint.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
enum flags
{
ExtractFlag = (1<<0),
InfoFlag = (1<<1),
PlainFlag = (1<<2),
VerboseFlag = (1<<3),
VerifyFlag = (1<<4),
RawFlag = (1<<5),
ShowKeysFlag = (1<<6)
};
enum validstate
{
Unchecked = 0,
Good = 1,
Fail = 2,
};
#endif

192
ctrtool/utils.c Normal file
View File

@ -0,0 +1,192 @@
#include <stdio.h>
#include <string.h>
#include "utils.h"
#ifdef _WIN32
#include <direct.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#endif
u32 align(u32 offset, u32 alignment)
{
u32 mask = ~(alignment-1);
return (offset + (alignment-1)) & mask;
}
u64 align64(u64 offset, u32 alignment)
{
u64 mask = ~(alignment-1);
return (offset + (alignment-1)) & mask;
}
u64 getle64(const u8* p)
{
u64 n = p[0];
n |= (u64)p[1]<<8;
n |= (u64)p[2]<<16;
n |= (u64)p[3]<<24;
n |= (u64)p[4]<<32;
n |= (u64)p[5]<<40;
n |= (u64)p[6]<<48;
n |= (u64)p[7]<<56;
return n;
}
u64 getbe64(const u8* p)
{
u64 n = 0;
n |= (u64)p[0]<<56;
n |= (u64)p[1]<<48;
n |= (u64)p[2]<<40;
n |= (u64)p[3]<<32;
n |= (u64)p[4]<<24;
n |= (u64)p[5]<<16;
n |= (u64)p[6]<<8;
n |= (u64)p[7]<<0;
return n;
}
u32 getle32(const u8* p)
{
return (p[0]<<0) | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
}
u32 getbe32(const u8* p)
{
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | (p[3]<<0);
}
u32 getle16(const u8* p)
{
return (p[0]<<0) | (p[1]<<8);
}
u32 getbe16(const u8* p)
{
return (p[0]<<8) | (p[1]<<0);
}
void putle16(u8* p, u16 n)
{
p[0] = n;
p[1] = n>>8;
}
void putle32(u8* p, u32 n)
{
p[0] = n;
p[1] = n>>8;
p[2] = n>>16;
p[3] = n>>24;
}
void readkeyfile(u8* key, const char* keyfname)
{
FILE* f = fopen(keyfname, "rb");
u32 keysize = 0;
if (0 == f)
{
fprintf(stdout, "Error opening key file\n");
goto clean;
}
fseek(f, 0, SEEK_END);
keysize = ftell(f);
fseek(f, 0, SEEK_SET);
if (keysize != 16)
{
fprintf(stdout, "Error key size mismatch, got %d, expected %d\n", keysize, 16);
goto clean;
}
if (16 != fread(key, 1, 16, f))
{
fprintf(stdout, "Error reading key file\n");
goto clean;
}
clean:
if (f)
fclose(f);
}
void hexdump(void *ptr, int buflen)
{
u8 *buf = (u8*)ptr;
int i, j;
for (i=0; i<buflen; i+=16)
{
printf("%06x: ", i);
for (j=0; j<16; j++)
{
if (i+j < buflen)
{
printf("%02x ", buf[i+j]);
}
else
{
printf(" ");
}
}
printf(" ");
for (j=0; j<16; j++)
{
if (i+j < buflen)
{
printf("%c", (buf[i+j] >= 0x20 && buf[i+j] <= 0x7e) ? buf[i+j] : '.');
}
}
printf("\n");
}
}
void memdump(FILE* fout, const char* prefix, const u8* data, u32 size)
{
u32 i;
u32 prefixlen = strlen(prefix);
u32 offs = 0;
u32 line = 0;
while(size)
{
u32 max = 32;
if (max > size)
max = size;
if (line==0)
fprintf(fout, "%s", prefix);
else
fprintf(fout, "%*s", prefixlen, "");
for(i=0; i<max; i++)
fprintf(fout, "%02X", data[offs+i]);
fprintf(fout, "\n");
line++;
size -= max;
offs += max;
}
}
int makedir(const char* dir)
{
#ifdef _WIN32
return _mkdir(dir);
#else
return mkdir(dir, 0777);
#endif
}

42
ctrtool/utils.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef _UTILS_H_
#define _UTILS_H_
#include "types.h"
#ifdef _WIN32
#define PATH_SEPERATOR '\\'
#else
#define PATH_SEPERATOR '/'
#endif
#ifndef MAX_PATH
#define MAX_PATH 255
#endif
#ifdef __cplusplus
extern "C" {
#endif
u32 align(u32 offset, u32 alignment);
u64 align64(u64 offset, u32 alignment);
u64 getle64(const u8* p);
u32 getle32(const u8* p);
u32 getle16(const u8* p);
u64 getbe64(const u8* p);
u32 getbe32(const u8* p);
u32 getbe16(const u8* p);
void putle16(u8* p, u16 n);
void putle32(u8* p, u32 n);
void readkeyfile(u8* key, const char* keyfname);
void memdump(FILE* fout, const char* prefix, const u8* data, u32 size);
void hexdump(void *ptr, int buflen);
int key_load(char *name, u8 *out_buf);
int makedir(const char* dir);
#ifdef __cplusplus
}
#endif
#endif // _UTILS_H_

1047
ctrtool/windows/getopt.c Normal file

File diff suppressed because it is too large Load Diff

172
ctrtool/windows/getopt.h Normal file
View File

@ -0,0 +1,172 @@
/* Declarations for getopt.
Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef _GETOPT_H
#ifndef __need_getopt
# define _GETOPT_H 1
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
#ifndef __need_getopt
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option {
# if defined __STDC__ && __STDC__
const char *name;
# else
char *name;
# endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
# define no_argument 0
# define required_argument 1
# define optional_argument 2
#endif /* need getopt */
/* Get definitions and prototypes for functions to process the
arguments in ARGV (ARGC of them, minus the program name) for
options given in OPTS.
Return the option character from OPTS just read. Return -1 when
there are no more options. For unrecognized options, or options
missing arguments, `optopt' is set to the option letter, and '?' is
returned.
The OPTS string is a list of characters which are recognized option
letters, optionally followed by colons, specifying that that letter
takes an argument, to be placed in `optarg'.
If a letter in OPTS is followed by two colons, its argument is
optional. This behavior is specific to the GNU `getopt'.
The argument `--' causes premature termination of argument
scanning, explicitly telling `getopt' that there are no more
options.
If OPTS begins with `--', then non-option arguments are treated as
arguments to the option '\0'. This behavior is specific to the GNU
`getopt'. */
#if defined __STDC__ && __STDC__
# ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int __argc, char *const *__argv, const char *__shortopts);
# else /* not __GNU_LIBRARY__ */
extern int getopt ();
# endif /* __GNU_LIBRARY__ */
# ifndef __need_getopt
extern int getopt_long (int argc, char ** argv, const char * shortopts,
const struct option * longopts, int * longind);
extern int getopt_long_only (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind,
int __long_only);
# endif
#else /* not __STDC__ */
extern int getopt ();
# ifndef __need_getopt
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
# endif
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
/* Make sure we later can get all the definitions and declarations. */
#undef __need_getopt
#endif /* getopt.h */

188
ctrtool/windows/getopt1.c Normal file
View File

@ -0,0 +1,188 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "getopt.h"
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE
#endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char **argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* Not ELIDE_CODE. */
#ifdef TEST
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */