mirror of
https://github.com/DarkStore-3DS/Project_CTR.git
synced 2026-07-02 16:59:03 +00:00
+55
-87
@@ -2,57 +2,64 @@
|
||||
#include "certs.h"
|
||||
|
||||
// Cert Sizes
|
||||
|
||||
u32 GetCertSize(u8 *cert)
|
||||
void GetCertSigSectionSizes(u32 *sign_size, u32 *sign_padlen, u8 *cert)
|
||||
{
|
||||
u32 SigSize = 0;
|
||||
u32 SigPadding = 0;
|
||||
GetCertSigSectionSizes(&SigSize,&SigPadding,cert);
|
||||
if(!SigSize || !SigPadding) return 0;
|
||||
|
||||
Cert_Struct *certcore = (Cert_Struct*)(cert+4+SigSize+SigPadding);
|
||||
|
||||
u32 PubKSectionSize = GetCertPubkSectionSize((pubk_types)u8_to_u32(certcore->KeyType,BE));
|
||||
|
||||
return (4+SigSize+SigPadding+sizeof(Cert_Struct)+PubKSectionSize);
|
||||
}
|
||||
|
||||
void GetCertSigSectionSizes(u32 *SigSize, u32 *SigPadding, u8 *cert)
|
||||
{
|
||||
sig_types sig = (sig_types)u8_to_u32(cert,BE);
|
||||
u32 sig = u8_to_u32(cert,BE);
|
||||
switch(sig){
|
||||
case RSA_4096_SHA1 :
|
||||
*SigSize = 0x200;
|
||||
*SigPadding = 0x3C;
|
||||
*sign_size = 0x200;
|
||||
*sign_padlen = 0x3C;
|
||||
break;
|
||||
case RSA_2048_SHA1 :
|
||||
*SigSize = 0x100;
|
||||
*SigPadding = 0x3C;
|
||||
*sign_size = 0x100;
|
||||
*sign_padlen = 0x3C;
|
||||
break;
|
||||
case ECC_SHA1 :
|
||||
*SigSize = 0x3C;
|
||||
*SigPadding = 0x40;
|
||||
*sign_size = 0x3C;
|
||||
*sign_padlen = 0x40;
|
||||
break;
|
||||
case RSA_4096_SHA256 :
|
||||
*SigSize = 0x200;
|
||||
*SigPadding = 0x3C;
|
||||
*sign_size = 0x200;
|
||||
*sign_padlen = 0x3C;
|
||||
break;
|
||||
case RSA_2048_SHA256 :
|
||||
*SigSize = 0x100;
|
||||
*SigPadding = 0x3C;
|
||||
*sign_size = 0x100;
|
||||
*sign_padlen = 0x3C;
|
||||
break;
|
||||
case ECC_SHA256 :
|
||||
*SigSize = 0x3C;
|
||||
*SigPadding = 0x40;
|
||||
*sign_size = 0x3C;
|
||||
*sign_padlen = 0x40;
|
||||
break;
|
||||
default :
|
||||
*SigSize = 0;
|
||||
*SigPadding = 0;
|
||||
*sign_size = 0;
|
||||
*sign_padlen = 0;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
u32 GetCertSize(u8 *cert)
|
||||
{
|
||||
u32 sign_size = 0;
|
||||
u32 sign_padlen = 0;
|
||||
GetCertSigSectionSizes(&sign_size,&sign_padlen,cert);
|
||||
if(!sign_size || !sign_padlen)
|
||||
return 0;
|
||||
|
||||
return sizeof(u32) + sign_size + sign_padlen + sizeof(cert_hdr) + GetCertPubkSectionSize(GetCertPubkType(cert));
|
||||
}
|
||||
|
||||
|
||||
cert_hdr* GetCertHdr(u8 *cert)
|
||||
{
|
||||
u32 sign_size = 0;
|
||||
u32 sign_padlen = 0;
|
||||
GetCertSigSectionSizes(&sign_size,&sign_padlen,cert);
|
||||
if(!sign_size || !sign_padlen) return NULL;
|
||||
|
||||
return (cert_hdr*)(cert+4+sign_size+sign_padlen);
|
||||
}
|
||||
|
||||
u32 GetCertPubkSectionSize(pubk_types type)
|
||||
{
|
||||
switch(type){
|
||||
@@ -66,80 +73,41 @@ u32 GetCertPubkSectionSize(pubk_types type)
|
||||
// Issuer/Name Functions
|
||||
u8 *GetCertIssuer(u8 *cert)
|
||||
{
|
||||
u32 SigSize = 0;
|
||||
u32 SigPadding = 0;
|
||||
GetCertSigSectionSizes(&SigSize,&SigPadding,cert);
|
||||
if(!SigSize || !SigPadding) return 0;
|
||||
|
||||
Cert_Struct *certcore = (Cert_Struct*)(cert+4+SigSize+SigPadding);
|
||||
return certcore->Issuer;
|
||||
cert_hdr *hdr = GetCertHdr(cert);
|
||||
return hdr->issuer;
|
||||
}
|
||||
u8 *GetCertName(u8 *cert)
|
||||
{
|
||||
u32 SigSize = 0;
|
||||
u32 SigPadding = 0;
|
||||
GetCertSigSectionSizes(&SigSize,&SigPadding,cert);
|
||||
if(!SigSize || !SigPadding) return 0;
|
||||
|
||||
Cert_Struct *certcore = (Cert_Struct*)(cert+4+SigSize+SigPadding);
|
||||
return certcore->Name;
|
||||
cert_hdr *hdr = GetCertHdr(cert);
|
||||
return hdr->name;
|
||||
}
|
||||
|
||||
int GenCertChildIssuer(u8 *dest, u8 *cert)
|
||||
void GenCertChildIssuer(u8 *dest, u8 *cert)
|
||||
{
|
||||
u8 *issuer = GetCertIssuer(cert);
|
||||
u8 *name = GetCertName(cert);
|
||||
|
||||
/*
|
||||
u32 out_size = strlen((char*)issuer) + strlen((char*)name) + 1;
|
||||
if(out_size > 0x40) return MEM_ERROR;
|
||||
*/
|
||||
|
||||
snprintf((char*)dest,0x40,"%s-%s",issuer,name);
|
||||
|
||||
/*
|
||||
strcat((char*)dest,(char*)issuer);
|
||||
strcat((char*)dest,"-");
|
||||
strcat((char*)dest,(char*)name);
|
||||
*/
|
||||
return 0;
|
||||
snprintf((char*)dest,0x40,"%s-%s",GetCertIssuer(cert),GetCertName(cert));
|
||||
}
|
||||
|
||||
// Pubk
|
||||
pubk_types GetCertPubkType(u8 *cert)
|
||||
{
|
||||
u32 SigSize = 0;
|
||||
u32 SigPadding = 0;
|
||||
GetCertSigSectionSizes(&SigSize,&SigPadding,cert);
|
||||
if(!SigSize || !SigPadding) return 0;
|
||||
cert_hdr *hdr = GetCertHdr(cert);
|
||||
|
||||
Cert_Struct *certcore = (Cert_Struct*)(cert+4+SigSize+SigPadding);
|
||||
|
||||
return (pubk_types)u8_to_u32(certcore->KeyType,BE);
|
||||
return (pubk_types)u8_to_u32(hdr->keyType,BE);
|
||||
}
|
||||
u8 *GetCertPubk(u8 *cert)
|
||||
{
|
||||
u32 SigSize = 0;
|
||||
u32 SigPadding = 0;
|
||||
GetCertSigSectionSizes(&SigSize,&SigPadding,cert);
|
||||
if(!SigSize || !SigPadding) return 0;
|
||||
return (cert+4+SigSize+SigPadding+sizeof(Cert_Struct));
|
||||
if(!GetCertHdr(cert))
|
||||
return NULL;
|
||||
return ((u8*)GetCertHdr(cert)) + sizeof(cert_hdr);
|
||||
}
|
||||
|
||||
bool VerifyCert(u8 *cert, u8 *pubk)
|
||||
{
|
||||
u32 SigSize = 0;
|
||||
u32 SigPadding = 0;
|
||||
GetCertSigSectionSizes(&SigSize,&SigPadding,cert);
|
||||
if(!SigSize || !SigPadding) return 0;
|
||||
if(!GetCertHdr(cert))
|
||||
return false;
|
||||
u8 *signature = (cert+sizeof(u32));
|
||||
u8 *data = (u8*)GetCertHdr(cert);
|
||||
u32 datasize = sizeof(cert_hdr) + GetCertPubkSectionSize(GetCertPubkType(cert));
|
||||
|
||||
|
||||
u8 *signature = (cert+4);
|
||||
u8 *data = (cert+4+SigSize+SigPadding);
|
||||
u32 datasize = sizeof(Cert_Struct) + GetCertPubkSectionSize(GetCertPubkType(cert));
|
||||
|
||||
int result = ctr_sig(data,datasize,signature,pubk,NULL,u8_to_u32(cert,BE),CTR_RSA_VERIFY);
|
||||
|
||||
if(result == 0) return true;
|
||||
else return false;
|
||||
return RsaSignVerify(data,datasize,signature,pubk,NULL,u8_to_u32(cert,BE),CTR_RSA_VERIFY);
|
||||
}
|
||||
+14
-15
@@ -2,41 +2,40 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 Issuer[0x40];
|
||||
u8 KeyType[4];
|
||||
u8 Name[0x40];
|
||||
u8 Unknown[4];
|
||||
} Cert_Struct;
|
||||
u8 issuer[0x40];
|
||||
u8 keyType[4];
|
||||
u8 name[0x40];
|
||||
u8 id[4];
|
||||
} cert_hdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 Modulus[0x200];
|
||||
u8 PubExponent[4];
|
||||
u8 Padding[0x34];
|
||||
u8 modulus[0x200];
|
||||
u8 pubExponent[4];
|
||||
u8 padding[0x34];
|
||||
} rsa_4096_pubk_struct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 Modulus[0x100];
|
||||
u8 PubExponent[4];
|
||||
u8 Padding[0x34];
|
||||
u8 modulus[0x100];
|
||||
u8 pubExponent[4];
|
||||
u8 padding[0x34];
|
||||
} rsa_2048_pubk_struct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 PubK[0x3C];
|
||||
u8 Padding[0x3C];
|
||||
u8 pubK[0x3C];
|
||||
u8 padding[0x3C];
|
||||
} ecc_pubk_struct;
|
||||
|
||||
// Cert Sizes
|
||||
u32 GetCertSize(u8 *cert);
|
||||
void GetCertSigSectionSizes(u32 *SigSize, u32 *SigPadding, u8 *cert);
|
||||
u32 GetCertPubkSectionSize(pubk_types type);
|
||||
|
||||
// Issuer/Name Functions
|
||||
u8 *GetCertIssuer(u8 *cert);
|
||||
u8 *GetCertName(u8 *cert);
|
||||
int GenCertChildIssuer(u8 *dest, u8 *cert);
|
||||
void GenCertChildIssuer(u8 *dest, u8 *cert);
|
||||
|
||||
// Pubk
|
||||
pubk_types GetCertPubkType(u8 *cert);
|
||||
|
||||
+10
-16
@@ -17,7 +17,6 @@ const int CIA_ALIGN_SIZE = 0x40;
|
||||
const int CIA_CONTENT_ALIGN = 0x10;
|
||||
|
||||
// Private Prototypes
|
||||
void InitCiaSettings(cia_settings *set);
|
||||
void FreeCiaSettings(cia_settings *set);
|
||||
int GetCiaSettings(cia_settings *ciaset, user_settings *usrset);
|
||||
|
||||
@@ -53,7 +52,6 @@ int build_CIA(user_settings *usrset)
|
||||
}
|
||||
|
||||
// Get Settings
|
||||
InitCiaSettings(ciaset);
|
||||
result = GetCiaSettings(ciaset,usrset);
|
||||
if(result) goto finish;
|
||||
|
||||
@@ -96,11 +94,6 @@ finish:
|
||||
return result;
|
||||
}
|
||||
|
||||
void InitCiaSettings(cia_settings *set)
|
||||
{
|
||||
memset(set,0,sizeof(cia_settings));
|
||||
}
|
||||
|
||||
void FreeCiaSettings(cia_settings *set)
|
||||
{
|
||||
if(set->content.filePtrs){
|
||||
@@ -198,8 +191,7 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset)
|
||||
|
||||
ciaset->tik.formatVersion = 1;
|
||||
|
||||
int result = GenCertChildIssuer(ciaset->tik.issuer,ciaset->keys->certs.xsCert);
|
||||
if(result) return result;
|
||||
GenCertChildIssuer(ciaset->tik.issuer,ciaset->keys->certs.xsCert);
|
||||
|
||||
// Tmd Stuff
|
||||
if(usrset->cia.contentId[0] > MAX_U32)
|
||||
@@ -209,7 +201,7 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset)
|
||||
|
||||
ciaset->tmd.formatVersion = 1;
|
||||
ciaset->tmd.accessRights = 0;
|
||||
result = GenCertChildIssuer(ciaset->tmd.issuer,ciaset->keys->certs.cpCert);
|
||||
GenCertChildIssuer(ciaset->tmd.issuer,ciaset->keys->certs.cpCert);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -293,14 +285,16 @@ int GetTmdDataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *
|
||||
|
||||
if(IsPatch(GetTidCategory(ciaset->common.titleId))||ciaset->content.IsCfa)
|
||||
ciaset->tmd.savedataSize = 0;
|
||||
else if(ciaset->content.keyNotFound && ciaset->rsf->SystemControlInfo.SaveDataSize){ // if it's a title which can have save data, but save data size could not be read from exhdr
|
||||
else if(!ciaset->content.keyNotFound)
|
||||
ciaset->tmd.savedataSize = (u32)(GetSaveDataSize_frm_exhdr(exhdr) & MAX_U32);
|
||||
else if(ciaset->rsf->SystemControlInfo.SaveDataSize){ // if it's a title which can have save data, but save data size could not be read from exhdr
|
||||
u64 size = 0;
|
||||
GetSaveDataSizeFromString(&size,ciaset->rsf->SystemControlInfo.SaveDataSize,"CIA");
|
||||
ciaset->tmd.savedataSize = (u32)(size & MAX_U32);
|
||||
}
|
||||
else
|
||||
ciaset->tmd.savedataSize = (u32)(GetSaveDataSize_frm_exhdr(exhdr) & MAX_U32);
|
||||
|
||||
else
|
||||
ciaset->tmd.savedataSize = 0;
|
||||
|
||||
if(ciaset->content.IsCfa||ciaset->content.keyNotFound){
|
||||
if(ciaset->common.titleVersion[VER_MAJOR] == MAX_U16){ // '-major' wasn't set
|
||||
if(ciaset->content.IsCfa){ // Is a CFA and can be decrypted
|
||||
@@ -569,7 +563,7 @@ u16 SetupVersion(u16 major, u16 minor, u16 micro)
|
||||
void GetContentHashes(cia_settings *ciaset)
|
||||
{
|
||||
for(int i = 0; i < ciaset->content.count; i++)
|
||||
ctr_sha(ciaset->ciaSections.content.buffer+ciaset->content.offset[i],ciaset->content.size[i],ciaset->content.hash[i],CTR_SHA_256);
|
||||
ShaCalc(ciaset->ciaSections.content.buffer+ciaset->content.offset[i],ciaset->content.size[i],ciaset->content.hash[i],CTR_SHA_256);
|
||||
}
|
||||
|
||||
void EncryptContent(cia_settings *ciaset)
|
||||
@@ -653,7 +647,7 @@ int CryptContent(u8 *input, u8 *output, u64 size, u8 *title_key, u16 index, u8 m
|
||||
iv[0] = (index >> 8) & 0xff;
|
||||
iv[1] = index & 0xff;
|
||||
//Crypting content
|
||||
AesCbc(title_key,iv,input,output,size,mode);
|
||||
AesCbcCrypt(title_key,iv,input,output,size,mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+114
-134
@@ -1,14 +1,24 @@
|
||||
#include "lib.h"
|
||||
#include "crypto.h"
|
||||
|
||||
const u8 RSA_PUB_EXP[0x3] = {0x01,0x00,0x01};
|
||||
const int HASH_MAX_LEN = 0x20;
|
||||
|
||||
int ctr_rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
|
||||
int mode,
|
||||
int hash_id,
|
||||
unsigned int hashlen,
|
||||
const unsigned char *hash,
|
||||
unsigned char *sig );
|
||||
|
||||
bool VerifySha256(void *data, u64 size, u8 hash[32])
|
||||
{
|
||||
u8 calchash[32];
|
||||
ctr_sha(data, size, calchash, CTR_SHA_256);
|
||||
ShaCalc(data, size, calchash, CTR_SHA_256);
|
||||
return memcmp(hash,calchash,32) == 0;
|
||||
}
|
||||
|
||||
void ctr_sha(void *data, u64 size, u8 *hash, int mode)
|
||||
void ShaCalc(void *data, u64 size, u8 *hash, int mode)
|
||||
{
|
||||
switch(mode){
|
||||
case(CTR_SHA_1): sha1((u8*)data, size, hash); break;
|
||||
@@ -21,7 +31,7 @@ void SetAesCtrOffset(u8 *ctr, u64 offset)
|
||||
u64_to_u8(ctr+8,u8_to_u64(ctr+8,BE)|align(offset,16)/16,BE);
|
||||
}
|
||||
|
||||
void AesCtr(u8 *key, u8 *ctr, u8 *input, u8 *output, u64 length, u64 offset)
|
||||
void AesCtrCrypt(u8 *key, u8 *ctr, u8 *input, u8 *output, u64 length, u64 offset)
|
||||
{
|
||||
u8 stream[16];
|
||||
aes_context aes;
|
||||
@@ -37,7 +47,7 @@ void AesCtr(u8 *key, u8 *ctr, u8 *input, u8 *output, u64 length, u64 offset)
|
||||
return;
|
||||
}
|
||||
|
||||
void AesCbc(u8 *key, u8 *iv, u8 *input, u8 *output, u64 length, u8 mode)
|
||||
void AesCbcCrypt(u8 *key, u8 *iv, u8 *input, u8 *output, u64 length, u8 mode)
|
||||
{
|
||||
aes_context aes;
|
||||
clrmem(&aes,sizeof(aes_context));
|
||||
@@ -56,168 +66,138 @@ void AesCbc(u8 *key, u8 *iv, u8 *input, u8 *output, u64 length, u8 mode)
|
||||
}
|
||||
}
|
||||
|
||||
void ctr_rsa_free(ctr_rsa_context* ctx)
|
||||
{
|
||||
rsa_free(&ctx->rsa);
|
||||
}
|
||||
|
||||
int ctr_rsa_init(ctr_rsa_context* ctx, u8 *modulus, u8 *private_exp, u8 *exponent, u8 rsa_type, u8 mode)
|
||||
bool RsaKeyInit(rsa_context* ctx, u8 *modulus, u8 *private_exp, u8 *exponent, u8 rsa_type)
|
||||
{
|
||||
// Sanity Check
|
||||
if(ctx == NULL || modulus == NULL ||(private_exp == NULL && mode == RSAKEY_PRIV) || (exponent == NULL && mode == RSAKEY_PUB))
|
||||
return Fail;
|
||||
rsa_init(&ctx->rsa, RSA_PKCS_V15, 0);
|
||||
if(!ctx)
|
||||
return false;
|
||||
|
||||
rsa_init(ctx, RSA_PKCS_V15, 0);
|
||||
|
||||
u16 n_size = 0;
|
||||
u16 d_size = 0;
|
||||
u16 e_size = 0;
|
||||
|
||||
switch(rsa_type){
|
||||
case RSA_2048:
|
||||
ctx->rsa.len = 0x100;
|
||||
ctx->len = 0x100;
|
||||
n_size = 0x100;
|
||||
d_size = 0x100;
|
||||
e_size = 3;
|
||||
break;
|
||||
case RSA_4096:
|
||||
ctx->rsa.len = 0x200;
|
||||
ctx->len = 0x200;
|
||||
n_size = 0x200;
|
||||
d_size = 0x200;
|
||||
e_size = 3;
|
||||
break;
|
||||
default: return Fail;
|
||||
}
|
||||
|
||||
switch(mode){
|
||||
case(RSAKEY_PUB):
|
||||
if (mpi_read_binary(&ctx->rsa.N, modulus, n_size))
|
||||
goto clean;
|
||||
if (mpi_read_binary(&ctx->rsa.E, exponent, e_size))
|
||||
goto clean;
|
||||
break;
|
||||
case(RSAKEY_PRIV):
|
||||
if (mpi_read_binary(&ctx->rsa.N, modulus, n_size))
|
||||
goto clean;
|
||||
if (mpi_read_binary(&ctx->rsa.D, private_exp, d_size))
|
||||
goto clean;
|
||||
break;
|
||||
default: return Fail;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
if (modulus && mpi_read_binary(&ctx->N, modulus, n_size))
|
||||
goto clean;
|
||||
if (exponent && mpi_read_binary(&ctx->E, exponent, e_size))
|
||||
goto clean;
|
||||
if (private_exp && mpi_read_binary(&ctx->D, private_exp, d_size))
|
||||
goto clean;
|
||||
|
||||
|
||||
return Good;
|
||||
return true;
|
||||
clean:
|
||||
ctr_rsa_free(ctx);
|
||||
return Fail;
|
||||
rsa_free(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ctr_sig(void *data, u64 size, u8 *signature, u8 *modulus, u8 *private_exp, u32 type, u8 mode)
|
||||
u8 GetRsaType(u32 sig_type)
|
||||
{
|
||||
int result = 0;
|
||||
int hashtype, hashlen, sigtype;
|
||||
if(data == NULL || signature == NULL || modulus == NULL ||(private_exp == NULL && mode == CTR_RSA_SIGN))
|
||||
return Fail;
|
||||
|
||||
switch(type){
|
||||
switch(sig_type){
|
||||
case RSA_4096_SHA1:
|
||||
hashtype = CTR_SHA_1;
|
||||
hashlen = 0x14;
|
||||
sigtype = RSA_4096;
|
||||
case RSA_4096_SHA256:
|
||||
hashtype = CTR_SHA_256;
|
||||
hashlen = 0x20;
|
||||
sigtype = RSA_4096;
|
||||
break;
|
||||
return RSA_4096;
|
||||
case RSA_2048_SHA1:
|
||||
hashtype = CTR_SHA_1;
|
||||
hashlen = 0x14;
|
||||
sigtype = RSA_2048;
|
||||
case RSA_2048_SHA256:
|
||||
hashtype = CTR_SHA_256;
|
||||
hashlen = 0x20;
|
||||
sigtype = RSA_2048;
|
||||
break;
|
||||
case ECC_SHA1:
|
||||
hashtype = CTR_SHA_1;
|
||||
hashlen = 0x14;
|
||||
sigtype = ECC;
|
||||
case ECC_SHA256:
|
||||
hashtype = CTR_SHA_256;
|
||||
hashlen = 0x20;
|
||||
sigtype = ECC;
|
||||
break;
|
||||
default: return Fail;
|
||||
return RSA_2048;
|
||||
}
|
||||
|
||||
u8 hash[hashlen];
|
||||
memset(hash,0,hashlen);
|
||||
ctr_sha(data,size,hash,hashtype);
|
||||
//memdump(stdout,"Data: ",data,size);
|
||||
//memdump(stdout,"HashFor Sig: ",hash,hashlen);
|
||||
|
||||
if(sigtype == RSA_2048 || sigtype == RSA_4096)
|
||||
result = ctr_rsa(hash,signature,modulus,private_exp,type,mode);
|
||||
else if(sigtype == ECC){
|
||||
printf("[!] ECC is not yet implemented\n");
|
||||
result = Fail;
|
||||
}
|
||||
return result;
|
||||
return INVALID_SIG_TYPE;
|
||||
}
|
||||
|
||||
int ctr_rsa(u8 *hash, u8 *signature, u8 *modulus, u8 *private_exp, u32 type, u8 mode)
|
||||
u32 GetSigHashType(u32 sig_type)
|
||||
{
|
||||
int result = 0;
|
||||
// Sanity Check
|
||||
if(hash == NULL || signature == NULL || modulus == NULL ||(private_exp == NULL && mode == CTR_RSA_SIGN))
|
||||
return Fail;
|
||||
|
||||
// Getting details from sig type
|
||||
int hashtype;
|
||||
int hashlen;
|
||||
int sigtype;
|
||||
switch(type){
|
||||
case RSA_4096_SHA1:
|
||||
hashtype = SIG_RSA_SHA1;
|
||||
hashlen = 0x14;
|
||||
sigtype = RSA_4096;
|
||||
break;
|
||||
case RSA_4096_SHA256:
|
||||
hashtype = SIG_RSA_SHA256;
|
||||
hashlen = 0x14;
|
||||
sigtype = RSA_4096;
|
||||
break;
|
||||
case RSA_2048_SHA1:
|
||||
hashtype = SIG_RSA_SHA1;
|
||||
hashlen = 0x20;
|
||||
sigtype = RSA_2048;
|
||||
break;
|
||||
case RSA_2048_SHA256:
|
||||
hashtype = SIG_RSA_SHA256;
|
||||
hashlen = 0x20;
|
||||
sigtype = RSA_2048;
|
||||
break;
|
||||
default: return Fail;
|
||||
switch(sig_type){
|
||||
case RSA_4096_SHA1:
|
||||
case RSA_2048_SHA1:
|
||||
case ECC_SHA1:
|
||||
return CTR_SHA_1;
|
||||
case RSA_4096_SHA256:
|
||||
case RSA_2048_SHA256:
|
||||
case ECC_SHA256:
|
||||
return CTR_SHA_256;
|
||||
}
|
||||
|
||||
// Setting up
|
||||
ctr_rsa_context ctx;
|
||||
u8 exponent[3] = {0x01,0x00,0x01};
|
||||
switch(mode){
|
||||
case CTR_RSA_VERIFY:
|
||||
result = ctr_rsa_init(&ctx,modulus,NULL,(u8*)exponent,sigtype,RSAKEY_PUB);
|
||||
break;
|
||||
case CTR_RSA_SIGN:
|
||||
result = ctr_rsa_init(&ctx,modulus,private_exp,NULL,sigtype,RSAKEY_PRIV);
|
||||
break;
|
||||
}
|
||||
if(result)return result;
|
||||
|
||||
switch(mode){
|
||||
case CTR_RSA_VERIFY:
|
||||
return rsa_pkcs1_verify(&ctx.rsa,RSA_PUBLIC,hashtype,hashlen,hash,signature);
|
||||
case CTR_RSA_SIGN:
|
||||
return ctr_rsa_rsassa_pkcs1_v15_sign(&ctx.rsa,RSA_PRIVATE,hashtype,hashlen,hash,signature);
|
||||
}
|
||||
return Fail;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetRsaHashType(u32 sig_type)
|
||||
{
|
||||
switch(sig_type){
|
||||
case RSA_4096_SHA1:
|
||||
case RSA_2048_SHA1:
|
||||
return SIG_RSA_SHA1;
|
||||
case RSA_4096_SHA256:
|
||||
case RSA_2048_SHA256:
|
||||
return SIG_RSA_SHA256;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GetSigHashLen(u32 sig_type)
|
||||
{
|
||||
switch(sig_type){
|
||||
case RSA_4096_SHA1:
|
||||
return 0x14;
|
||||
case RSA_4096_SHA256:
|
||||
return 0x20;
|
||||
case RSA_2048_SHA1:
|
||||
return 0x14;
|
||||
case RSA_2048_SHA256:
|
||||
return 0x20;
|
||||
case ECC_SHA1:
|
||||
return 0x14;
|
||||
case ECC_SHA256:
|
||||
return 0x20;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CalcHashForSign(void *data, u64 len, u8 *hash, u32 sig_type)
|
||||
{
|
||||
if(GetSigHashType(sig_type) == 0)
|
||||
return false;
|
||||
|
||||
ShaCalc(data, len, hash, GetSigHashType(sig_type));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int RsaSignVerify(void *data, u64 len, u8 *sign, u8 *mod, u8 *priv_exp, u32 sig_type, u8 rsa_mode)
|
||||
{
|
||||
int rsa_result = 0;
|
||||
rsa_context ctx;
|
||||
u8 hash[HASH_MAX_LEN];
|
||||
|
||||
if(!RsaKeyInit(&ctx, mod, priv_exp, (u8*)RSA_PUB_EXP, GetRsaType(sig_type)))
|
||||
return -1;
|
||||
|
||||
if(!CalcHashForSign(data, len, hash, sig_type))
|
||||
return -1;
|
||||
|
||||
if(rsa_mode == CTR_RSA_VERIFY)
|
||||
rsa_result = rsa_pkcs1_verify(&ctx, RSA_PUBLIC, GetRsaHashType(sig_type), 0, hash, sign);
|
||||
else // CTR_RSA_SIGN
|
||||
rsa_result = ctr_rsa_rsassa_pkcs1_v15_sign(&ctx, RSA_PRIVATE, GetRsaHashType(sig_type), 0, hash, sign);
|
||||
|
||||
rsa_free(&ctx);
|
||||
return rsa_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hacked from rsa.c, polarssl doesn't like generating signatures when only D and N are present
|
||||
|
||||
+19
-38
@@ -14,25 +14,26 @@ typedef enum
|
||||
RSA_4096_SHA256 = 0x00010003,
|
||||
RSA_2048_SHA256 = 0x00010004,
|
||||
ECC_SHA256 = 0x00010005
|
||||
} sig_types;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RSA_2048 = 0,
|
||||
RSA_4096 = 1,
|
||||
ECC = 2,
|
||||
} ctr_sig_types;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CTR_RSA_VERIFY = 0,
|
||||
CTR_RSA_SIGN = 1,
|
||||
} ctr_rsa_functions;
|
||||
CTR_RSA_VERIFY,
|
||||
CTR_RSA_SIGN,
|
||||
} ctr_rsa_mode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CTR_SHA_1 = 1,
|
||||
CTR_SHA_256 = 256,
|
||||
RSA_4096,
|
||||
RSA_2048,
|
||||
ECC,
|
||||
INVALID_SIG_TYPE,
|
||||
} sig_types;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CTR_SHA_1,
|
||||
CTR_SHA_256,
|
||||
} ctr_sha_modes;
|
||||
|
||||
typedef enum
|
||||
@@ -46,42 +47,22 @@ typedef enum
|
||||
{
|
||||
ENC,
|
||||
DEC
|
||||
} aescbcmode;
|
||||
} aes_mode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RSAKEY_INVALID,
|
||||
RSAKEY_PRIV,
|
||||
RSAKEY_PUB
|
||||
} rsakeytype;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rsa_context rsa;
|
||||
} ctr_rsa_context;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// SHA
|
||||
bool VerifySha256(void *data, u64 size, u8 hash[32]);
|
||||
void ctr_sha(void *data, u64 size, u8 *hash, int mode);
|
||||
void ShaCalc(void *data, u64 size, u8 *hash, int mode);
|
||||
// AES
|
||||
void AesCtr(u8 *key, u8 *ctr, u8 *input, u8 *output, u64 length, u64 offset);
|
||||
void AesCbc(u8 *key, u8 *iv, u8 *input, u8 *output, u64 length, u8 mode);
|
||||
void AesCtrCrypt(u8 *key, u8 *ctr, u8 *input, u8 *output, u64 length, u64 offset);
|
||||
void AesCbcCrypt(u8 *key, u8 *iv, u8 *input, u8 *output, u64 length, u8 mode);
|
||||
// RSA
|
||||
void ctr_rsa_free(ctr_rsa_context* ctx);
|
||||
int ctr_rsa_init(ctr_rsa_context* ctx, u8 *modulus, u8 *private_exp, u8 *exponent, u8 rsa_type, u8 mode);
|
||||
int ctr_rsa(u8 *hash, u8 *signature, u8 *modulus, u8 *private_exp, u32 type, u8 mode);
|
||||
int ctr_rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
|
||||
int mode,
|
||||
int hash_id,
|
||||
unsigned int hashlen,
|
||||
const unsigned char *hash,
|
||||
unsigned char *sig );
|
||||
int RsaSignVerify(void *data, u64 len, u8 *sign, u8 *mod, u8 *priv_exp, u32 sig_type, u8 rsa_mode);
|
||||
|
||||
|
||||
// Signature Functions
|
||||
int ctr_sig(void *data, u64 size, u8 *signature, u8 *modulus, u8 *private_exp, u32 type, u8 mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ int GenerateExeFS_Header(exefs_buildctx *ctx, u8 *outbuff)
|
||||
memcpy(exefs->fileHdr[i].name,ctx->fileName[i],8);
|
||||
u32_to_u8(exefs->fileHdr[i].offset,ctx->fileOffset[i],LE);
|
||||
u32_to_u8(exefs->fileHdr[i].size,ctx->fileSize[i],LE);
|
||||
ctr_sha(ctx->file[i],ctx->fileSize[i],exefs->fileHashes[MAX_EXEFS_SECTIONS-1-i],CTR_SHA_256);
|
||||
ShaCalc(ctx->file[i],ctx->fileSize[i],exefs->fileHashes[MAX_EXEFS_SECTIONS-1-i],CTR_SHA_256);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+6
-6
@@ -53,16 +53,16 @@ int get_ExHeaderARM9AccessControlInfo(exhdr_ARM9AccessControlInfo *arm9, rsf_set
|
||||
/* ExHeader Signature Functions */
|
||||
int SignAccessDesc(access_descriptor *acexDesc, keys_struct *keys)
|
||||
{
|
||||
u8 *AccessDesc = (u8*) &acexDesc->ncchRsaPubKey;
|
||||
u8 *Signature = (u8*) &acexDesc->signature;
|
||||
return ctr_sig(AccessDesc,0x300,Signature,keys->rsa.acexPub,keys->rsa.acexPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
u8 *data = (u8*) &acexDesc->ncchRsaPubKey;
|
||||
u8 *sign = (u8*) &acexDesc->signature;
|
||||
return RsaSignVerify(data,0x300,sign,keys->rsa.acexPub,keys->rsa.acexPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
}
|
||||
|
||||
int CheckAccessDescSignature(access_descriptor *acexDesc, keys_struct *keys)
|
||||
{
|
||||
u8 *AccessDesc = (u8*) &acexDesc->ncchRsaPubKey;
|
||||
u8 *Signature = (u8*) &acexDesc->signature;
|
||||
return ctr_sig(AccessDesc,0x300,Signature,keys->rsa.acexPub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY);
|
||||
u8 *data = (u8*) &acexDesc->ncchRsaPubKey;
|
||||
u8 *sign = (u8*) &acexDesc->signature;
|
||||
return RsaSignVerify(data,0x300,sign,keys->rsa.acexPub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY);
|
||||
}
|
||||
|
||||
/* ExHeader Build Functions */
|
||||
|
||||
+9
-9
@@ -34,22 +34,22 @@ bool IsValidProductCode(char *ProductCode, bool FreeProductCode);
|
||||
// Code
|
||||
int SignCFA(ncch_hdr *hdr, keys_struct *keys)
|
||||
{
|
||||
return ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cciCfaPub,keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
return RsaSignVerify(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cciCfaPub,keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
}
|
||||
|
||||
int CheckCFASignature(ncch_hdr *hdr, keys_struct *keys)
|
||||
{
|
||||
return ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cciCfaPub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY);
|
||||
return RsaSignVerify(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cciCfaPub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY);
|
||||
}
|
||||
|
||||
int SignCXI(ncch_hdr *hdr, keys_struct *keys)
|
||||
{
|
||||
return ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cxiHdrPub,keys->rsa.cxiHdrPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
return RsaSignVerify(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cxiHdrPub,keys->rsa.cxiHdrPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
}
|
||||
|
||||
int CheckCXISignature(ncch_hdr *hdr, u8 *pubk)
|
||||
{
|
||||
int result = ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),pubk,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY);
|
||||
int result = RsaSignVerify(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),pubk,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -500,13 +500,13 @@ int FinaliseNcch(ncch_settings *set)
|
||||
|
||||
// Taking Hashes
|
||||
if(set->cryptoDetails.exhdrSize)
|
||||
ctr_sha(exhdr,set->cryptoDetails.exhdrSize,hdr->exhdrHash,CTR_SHA_256);
|
||||
ShaCalc(exhdr,set->cryptoDetails.exhdrSize,hdr->exhdrHash,CTR_SHA_256);
|
||||
if(set->cryptoDetails.logoSize)
|
||||
ctr_sha(logo,set->cryptoDetails.logoSize,hdr->logoHash,CTR_SHA_256);
|
||||
ShaCalc(logo,set->cryptoDetails.logoSize,hdr->logoHash,CTR_SHA_256);
|
||||
if(set->cryptoDetails.exefsHashDataSize)
|
||||
ctr_sha(exefs,set->cryptoDetails.exefsHashDataSize,hdr->exefsHash,CTR_SHA_256);
|
||||
ShaCalc(exefs,set->cryptoDetails.exefsHashDataSize,hdr->exefsHash,CTR_SHA_256);
|
||||
if(set->cryptoDetails.romfsHashDataSize)
|
||||
ctr_sha(romfs,set->cryptoDetails.romfsHashDataSize,hdr->romfsHash,CTR_SHA_256);
|
||||
ShaCalc(romfs,set->cryptoDetails.romfsHashDataSize,hdr->romfsHash,CTR_SHA_256);
|
||||
|
||||
// Signing NCCH
|
||||
int sig_result = Good;
|
||||
@@ -1048,6 +1048,6 @@ void CryptNcchRegion(u8 *buffer, u64 size, u64 src_pos, u64 titleId, u8 key[16],
|
||||
{
|
||||
u8 ctr[0x10];
|
||||
GetNcchAesCounter(ctr,titleId,type);
|
||||
AesCtr(key,ctr,buffer,buffer,size,src_pos);
|
||||
AesCtrCrypt(key,ctr,buffer,buffer,size,src_pos);
|
||||
return;
|
||||
}
|
||||
+5
-6
@@ -10,7 +10,6 @@
|
||||
#include "cardinfo.h"
|
||||
#include "titleid.h"
|
||||
|
||||
|
||||
const int NCCH0_OFFSET = 0x4000;
|
||||
const int CCI_BLOCK_SIZE = 0x200;
|
||||
|
||||
@@ -288,15 +287,15 @@ int ProcessCiaForCci(cci_settings *set)
|
||||
|
||||
int ImportCciNcch(cci_settings *set)
|
||||
{
|
||||
if(set->rsf->SystemControlInfo.SaveDataSize)
|
||||
GetSaveDataSizeFromString(&set->romInfo.saveSize,set->rsf->SystemControlInfo.SaveDataSize,"CCI");
|
||||
|
||||
if(set->content.dataType == infile_ncch)
|
||||
return ImportNcchForCci(set);
|
||||
else if(set->content.dataType == infile_cia)
|
||||
return ProcessCiaForCci(set);
|
||||
else
|
||||
fprintf(stderr,"[CCI ERROR] Unrecognised input data type\n");
|
||||
|
||||
if(set->rsf->SystemControlInfo.SaveDataSize)
|
||||
GetSaveDataSizeFromString(&set->romInfo.saveSize,set->rsf->SystemControlInfo.SaveDataSize,"CCI");
|
||||
fprintf(stderr,"[CCI ERROR] Unrecognised input data type\n");
|
||||
|
||||
return FAILED_TO_IMPORT_FILE;
|
||||
}
|
||||
@@ -594,7 +593,7 @@ int GenCciHdr(cci_settings *set)
|
||||
SetCciNcchInfo(hdr,set);
|
||||
|
||||
// Sign Header
|
||||
ctr_sig(&hdr->magic,sizeof(cci_hdr)-RSA_2048_KEY_SIZE,hdr->signature,set->keys->rsa.cciCfaPub,set->keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
RsaSignVerify(&hdr->magic,sizeof(cci_hdr)-RSA_2048_KEY_SIZE,hdr->signature,set->keys->rsa.cciCfaPub,set->keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1
-1
@@ -467,7 +467,7 @@ void GenIvfcHashTree(romfs_buildctx *ctx)
|
||||
for(u32 j = 0; j < numHashes; j++){
|
||||
u8 *datapos = (u8*)(ctx->level[i+1].pos + ROMFS_BLOCK_SIZE * j);
|
||||
u8 *hashpos = (u8*)(ctx->level[i].pos + 0x20 * j);
|
||||
ctr_sha(datapos, ROMFS_BLOCK_SIZE, hashpos, CTR_SHA_256);
|
||||
ShaCalc(datapos, ROMFS_BLOCK_SIZE, hashpos, CTR_SHA_256);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -15,9 +15,8 @@ int CryptTitleKey(u8 *input, u8 *output, u8 *titleId, keys_struct *keys, u8 mode
|
||||
|
||||
int BuildTicket(cia_settings *set)
|
||||
{
|
||||
int result = 0;
|
||||
result = SetupTicketBuffer(set);
|
||||
if(result) return result;
|
||||
if(SetupTicketBuffer(set))
|
||||
return MEM_ERROR;
|
||||
|
||||
// Setting Ticket Struct Ptrs
|
||||
buffer_struct *tik = &set->ciaSections.tik;
|
||||
@@ -31,8 +30,7 @@ int BuildTicket(cia_settings *set)
|
||||
SetContentIndexHeader(idxHdr,set);
|
||||
SetContentIndexData(idxData,set);
|
||||
|
||||
result = SignTicketHeader(tik,set->keys);
|
||||
return 0;
|
||||
return SignTicketHeader(tik,set->keys);
|
||||
}
|
||||
|
||||
int SetupTicketBuffer(cia_settings *set)
|
||||
@@ -83,7 +81,7 @@ int SignTicketHeader(buffer_struct *tik, keys_struct *keys)
|
||||
clrmem(sig,sizeof(tik_signature));
|
||||
u32_to_u8(sig->sigType,RSA_2048_SHA256,BE);
|
||||
|
||||
return ctr_sig(data,len,sig->data,keys->rsa.xsPub,keys->rsa.xsPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
return RsaSignVerify(data,len,sig->data,keys->rsa.xsPub,keys->rsa.xsPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
}
|
||||
|
||||
int CryptTitleKey(u8 *input, u8 *output, u8 *titleId, keys_struct *keys, u8 mode)
|
||||
@@ -94,7 +92,7 @@ int CryptTitleKey(u8 *input, u8 *output, u8 *titleId, keys_struct *keys, u8 mode
|
||||
memcpy(iv,titleId,0x8);
|
||||
|
||||
//Crypting TitleKey
|
||||
AesCbc(keys->aes.commonKey[keys->aes.currentCommonKey],iv,input,output,0x10,mode);
|
||||
AesCbcCrypt(keys->aes.commonKey[keys->aes.currentCommonKey],iv,input,output,0x10,mode);
|
||||
|
||||
// Return
|
||||
return 0;
|
||||
|
||||
+4
-3
@@ -62,7 +62,7 @@ int SetupTMDHeader(tmd_hdr *hdr, tmd_content_info_record *info_record, cia_setti
|
||||
u32_to_u8(hdr->accessRights,ciaset->tmd.accessRights,BE);
|
||||
u16_to_u8(hdr->titleVersion,ciaset->tmd.version,BE);
|
||||
u16_to_u8(hdr->contentCount,ciaset->content.count,BE);
|
||||
ctr_sha(info_record,sizeof(tmd_content_info_record)*64,hdr->infoRecordHash,CTR_SHA_256);
|
||||
ShaCalc(info_record,sizeof(tmd_content_info_record)*64,hdr->infoRecordHash,CTR_SHA_256);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,8 @@ int SignTMDHeader(tmd_hdr *hdr, tmd_signature *sig, keys_struct *keys)
|
||||
{
|
||||
clrmem(sig,sizeof(tmd_signature));
|
||||
u32_to_u8(sig->sigType,RSA_2048_SHA256,BE);
|
||||
return ctr_sig((u8*)hdr,sizeof(tmd_hdr),sig->data,keys->rsa.cpPub,keys->rsa.cpPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
|
||||
return RsaSignVerify((u8*)hdr,sizeof(tmd_hdr),sig->data,keys->rsa.cpPub,keys->rsa.cpPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
|
||||
}
|
||||
|
||||
int SetupTMDInfoRecord(tmd_content_info_record *info_record, u8 *content_record, u16 ContentCount)
|
||||
@@ -78,7 +79,7 @@ int SetupTMDInfoRecord(tmd_content_info_record *info_record, u8 *content_record,
|
||||
clrmem(info_record,sizeof(tmd_content_info_record)*0x40);
|
||||
u16_to_u8(info_record->contentIndexOffset,0x0,BE);
|
||||
u16_to_u8(info_record->contentCommandCount,ContentCount,BE);
|
||||
ctr_sha(content_record,sizeof(tmd_content_chunk)*ContentCount,info_record->contentChunkHash,CTR_SHA_256);
|
||||
ShaCalc(content_record,sizeof(tmd_content_chunk)*ContentCount,info_record->contentChunkHash,CTR_SHA_256);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user