int SetCardInfoNotes(cardinfo_hdr *hdr, cci_settings *set) { u64_to_u8(hdr->notes.mediaSizeUsed,set->romInfo.usedSize,LE); u32_to_u8(hdr->notes.unknown,0,LE); if(set->options.tmdHdr){ u64_to_u8(hdr->notes.cverTitleId,GetTmdTitleId(set->options.tmdHdr),LE); u16_to_u8(hdr->notes.cverTitleId,GetTmdVersion(set->options.tmdHdr),LE); } return 0; }
int GenCciHdr(cci_settings *set) { set->headers.ccihdr.size = sizeof(cci_hdr); set->headers.ccihdr.buffer = calloc(1,set->headers.ccihdr.size); if(!set->headers.ccihdr.buffer){ set->headers.ccihdr.size = 0; fprintf(stderr,"[CCI ERROR] Not enough memory\n"); return MEM_ERROR; } cci_hdr *hdr = (cci_hdr*)set->headers.ccihdr.buffer; // Magic & TitleId memcpy(hdr->magic,"NCSD",4); u64_to_u8(hdr->titleId,set->content.titleId[0],LE); if(SetMediaSize(hdr->mediaSize,set)) return GEN_HDR_FAIL; if(SetCciFlags(hdr->flags,set)) return GEN_HDR_FAIL; SetCciNcchInfo(hdr,set); // Sign Header 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; }
void GetNewNcchIdForCci(u8 *newTid, u8 *srcTid, u8 index, tmd_hdr *tmdHdr) { u64 titleId = u8_to_u64(srcTid,LE) & 0xffffffffffff; if(tmdHdr && index == 7) titleId |= (u64)(GetTmdVersion(tmdHdr)) << 48; else titleId |= (u64)(index+4) << 48; u64_to_u8(newTid,titleId,LE); }
int SetupTMDContentRecord(u8 *content_record, cia_settings *ciaset) { for(int i = 0; i < ciaset->content.count; i++){ tmd_content_chunk *ptr = (tmd_content_chunk*)(content_record+sizeof(tmd_content_chunk)*i); u32_to_u8(ptr->contentID,ciaset->content.id[i],BE); u16_to_u8(ptr->contentIndex,ciaset->content.index[i],BE); u16_to_u8(ptr->contentFlags,ciaset->content.flags[i],BE); u64_to_u8(ptr->contentSize,ciaset->content.size[i],BE); memcpy(ptr->contentHash,ciaset->content.hash[i],0x20); } return 0; }
void SetCciNcchInfo(cci_hdr *hdr, cci_settings *set) { u64 ncchSize,ncchOffset; ncchOffset = NCCH0_OFFSET; for(int i = 0; i < CCI_MAX_CONTENT; i++){ if(set->content.active[i]){ set->content.cOffset[i] = ncchOffset; ncchSize = align(set->content.dSize[i],set->romInfo.blockSize); u32_to_u8(hdr->offset_sizeTable[i].offset,(ncchOffset/set->romInfo.blockSize),LE); u32_to_u8(hdr->offset_sizeTable[i].size,(ncchSize/set->romInfo.blockSize),LE); u64_to_u8(hdr->ncchIdTable[i],set->content.titleId[i],LE); ncchOffset += ncchSize; } } set->romInfo.usedSize = ncchOffset; return; }
void SetAesCtrOffset(u8 *ctr, u64 offset) { u64_to_u8(ctr+8,u8_to_u64(ctr+8,BE)|align(offset,16)/16,BE); }
int SetCommonHeaderBasicData(ncch_settings *set, ncch_hdr *hdr) { /* NCCH Magic */ memcpy(hdr->magic,"NCCH",4); /* NCCH Format Version */ if(!set->options.IsCfa) u16_to_u8(hdr->formatVersion,0x2,LE); /* Setting ProgramId/TitleId */ u64 programId = 0; int result = GetProgramID(&programId,set->rsfSet,false); if(result) return result; u64_to_u8(hdr->programId,programId,LE); u64_to_u8(hdr->titleId,programId,LE); /* Get Product Code and Maker Code */ if(set->rsfSet->BasicInfo.ProductCode){ if(!IsValidProductCode((char*)set->rsfSet->BasicInfo.ProductCode,set->options.FreeProductCode)){ fprintf(stderr,"[NCCH ERROR] Invalid Product Code\n"); return NCCH_BAD_RSF_SET; } memcpy(hdr->productCode,set->rsfSet->BasicInfo.ProductCode,strlen((char*)set->rsfSet->BasicInfo.ProductCode)); } else memcpy(hdr->productCode,"CTR-P-CTAP",10); if(set->rsfSet->BasicInfo.CompanyCode){ if(strlen((char*)set->rsfSet->BasicInfo.CompanyCode) != 2){ fprintf(stderr,"[NCCH ERROR] CompanyCode length must be 2\n"); return NCCH_BAD_RSF_SET; } memcpy(hdr->makerCode,set->rsfSet->BasicInfo.CompanyCode,2); } else memcpy(hdr->makerCode,"00",2); // Setting Encryption Settings if(!set->options.Encrypt) hdr->flags[ncchflag_OTHER_FLAG] = (otherflag_NoCrypto|otherflag_FixedCryptoKey); else if(set->options.useSecCrypto){ hdr->flags[ncchflag_OTHER_FLAG] = otherflag_Clear; hdr->flags[ncchflag_CONTENT_KEYX] = set->options.keyXID; } else hdr->flags[ncchflag_OTHER_FLAG] = otherflag_FixedCryptoKey; if(!SetNcchKeys(set->keys,hdr) && set->options.Encrypt){ hdr->flags[ncchflag_OTHER_FLAG] = (otherflag_NoCrypto|otherflag_FixedCryptoKey); hdr->flags[ncchflag_CONTENT_KEYX] = 0; set->options.Encrypt = false; fprintf(stderr,"[NCCH WARNING] NCCH AES Key could not be loaded, NCCH will not be encrypted\n"); } /* Set ContentUnitSize */ hdr->flags[ncchflag_CONTENT_BLOCK_SIZE] = GetCtrBlockSizeFlag(set->options.blockSize); /* Setting ContentPlatform */ hdr->flags[ncchflag_CONTENT_PLATFORM] = 1; // CTR /* Setting OtherFlag */ if(!set->options.UseRomFS) hdr->flags[ncchflag_OTHER_FLAG] |= otherflag_NoMountRomFs; /* Setting ContentType */ hdr->flags[ncchflag_CONTENT_TYPE] = 0; if(set->options.UseRomFS) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Data; if(!set->options.IsCfa) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Executable; if(set->rsfSet->BasicInfo.ContentType){ if(strcmp(set->rsfSet->BasicInfo.ContentType,"Application") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= 0; else if(strcmp(set->rsfSet->BasicInfo.ContentType,"SystemUpdate") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_SystemUpdate; else if(strcmp(set->rsfSet->BasicInfo.ContentType,"Manual") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Manual; else if(strcmp(set->rsfSet->BasicInfo.ContentType,"Child") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Child; else if(strcmp(set->rsfSet->BasicInfo.ContentType,"Trial") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Trial; else{ fprintf(stderr,"[NCCH ERROR] Invalid ContentType '%s'\n",set->rsfSet->BasicInfo.ContentType); return NCCH_BAD_RSF_SET; } } return 0; }
void GetNcchAesCounter(u8 ctr[16], u64 titleId, u8 type) { clrmem(ctr,16); u64_to_u8(ctr,titleId,BE); ctr[8] = type; }