mirror of
https://github.com/3DSGuy/Project_CTR.git
synced 2025-06-18 13:35:41 -04:00
Added neimod's ctrtool
Will be base code for improvments
This commit is contained in:
commit
87681b8bc5
22
.gitattributes
vendored
Normal file
22
.gitattributes
vendored
Normal 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
215
.gitignore
vendored
Normal 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
15
ctrtool/Makefile
Normal 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
295
ctrtool/cia.c
Normal 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
72
ctrtool/cia.h
Normal 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
354
ctrtool/ctr.c
Normal 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
146
ctrtool/ctr.h
Normal 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
442
ctrtool/ctrtool.vcproj
Normal 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
1001
ctrtool/cwav.c
Normal file
File diff suppressed because it is too large
Load Diff
205
ctrtool/cwav.h
Normal file
205
ctrtool/cwav.h
Normal 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
337
ctrtool/exefs.c
Normal 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
60
ctrtool/exefs.h
Normal 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
423
ctrtool/exheader.c
Normal 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
143
ctrtool/exheader.h
Normal 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
90
ctrtool/filepath.c
Normal 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
20
ctrtool/filepath.h
Normal 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
254
ctrtool/firm.c
Normal 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
57
ctrtool/firm.h
Normal 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
16
ctrtool/info.h
Normal 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
187
ctrtool/ivfc.c
Normal 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
72
ctrtool/ivfc.h
Normal 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
262
ctrtool/keyset.cpp
Normal 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
70
ctrtool/keyset.h
Normal 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
195
ctrtool/lzss.c
Normal 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
26
ctrtool/lzss.h
Normal 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
444
ctrtool/main.c
Normal 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
582
ctrtool/ncch.c
Normal 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
94
ctrtool/ncch.h
Normal 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
128
ctrtool/ncsd.c
Normal 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
55
ctrtool/ncsd.h
Normal 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
1164
ctrtool/polarssl/aes.c
Normal file
File diff suppressed because it is too large
Load Diff
139
ctrtool/polarssl/aes.h
Normal file
139
ctrtool/polarssl/aes.h
Normal 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
2038
ctrtool/polarssl/bignum.c
Normal file
File diff suppressed because it is too large
Load Diff
533
ctrtool/polarssl/bignum.h
Normal file
533
ctrtool/polarssl/bignum.h
Normal 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
736
ctrtool/polarssl/bn_mul.h
Normal 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
336
ctrtool/polarssl/config.h
Normal 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 */
|
98
ctrtool/polarssl/padlock.h
Normal file
98
ctrtool/polarssl/padlock.h
Normal 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
823
ctrtool/polarssl/rsa.c
Normal 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
353
ctrtool/polarssl/rsa.h
Normal 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
702
ctrtool/polarssl/sha2.c
Normal 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
155
ctrtool/polarssl/sha2.h
Normal 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
352
ctrtool/romfs.c
Normal 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(¤tpath, rootpath);
|
||||
filepath_append_utf16(¤tpath, entry->name);
|
||||
if (currentpath.valid)
|
||||
{
|
||||
makedir(currentpath.pathname);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error creating directory in root %s\n", rootpath->pathname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
filepath_init(¤tpath);
|
||||
|
||||
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, ¤tpath);
|
||||
|
||||
if (childoffset != (~0))
|
||||
romfs_visit_dir(ctx, childoffset, depth+1, actions, ¤tpath);
|
||||
|
||||
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(¤tpath, rootpath);
|
||||
filepath_append_utf16(¤tpath, entry->name);
|
||||
if (currentpath.valid)
|
||||
{
|
||||
fprintf(stdout, "Saving %s...\n", currentpath.pathname);
|
||||
romfs_extract_datafile(ctx, getle64(entry->dataoffset), getle64(entry->datasize), ¤tpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error creating directory in root %s\n", rootpath->pathname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
filepath_init(¤tpath);
|
||||
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
90
ctrtool/romfs.h
Normal 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
256
ctrtool/settings.c
Normal 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
70
ctrtool/settings.h
Normal 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
138
ctrtool/stream.c
Normal 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
45
ctrtool/stream.h
Normal 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
127
ctrtool/tik.c
Normal 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
64
ctrtool/tik.h
Normal 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
111
ctrtool/tinyxml/tinystr.cpp
Normal 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
305
ctrtool/tinyxml/tinystr.h
Normal 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
1886
ctrtool/tinyxml/tinyxml.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1805
ctrtool/tinyxml/tinyxml.h
Normal file
1805
ctrtool/tinyxml/tinyxml.h
Normal file
File diff suppressed because it is too large
Load Diff
52
ctrtool/tinyxml/tinyxmlerror.cpp
Normal file
52
ctrtool/tinyxml/tinyxmlerror.cpp
Normal 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.",
|
||||
};
|
1638
ctrtool/tinyxml/tinyxmlparser.cpp
Normal file
1638
ctrtool/tinyxml/tinyxmlparser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
169
ctrtool/tmd.c
Normal file
169
ctrtool/tmd.c
Normal 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
99
ctrtool/tmd.h
Normal 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
36
ctrtool/types.h
Normal 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
192
ctrtool/utils.c
Normal 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
42
ctrtool/utils.h
Normal 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
1047
ctrtool/windows/getopt.c
Normal file
File diff suppressed because it is too large
Load Diff
172
ctrtool/windows/getopt.h
Normal file
172
ctrtool/windows/getopt.h
Normal 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
188
ctrtool/windows/getopt1.c
Normal 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 */
|
Loading…
Reference in New Issue
Block a user