Skip to content

Commit

Permalink
Added support for PS2KEYS.dat in the working path
Browse files Browse the repository at this point in the history
Fixed some segfault errors and minor warnings
Encryption: added check for block size bound to 8 and 16
  • Loading branch information
AKuHAK committed Mar 8, 2022
1 parent 1f684eb commit e0532cf
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 66 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,9 @@ ASALocalRun/
build/
.*
*.kelf
*.xlf
*.elf
*.KELF
*.XLF
*.ELF
PS2KEYS.dat
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ LDLIBS = -lcrypto

# next flags only for macos
# change paths to your location of [email protected]
OUTPUT_OPTION += -I/Users/user/usr/local/Cellar/[email protected]/1.1.1m/include
LDLIBS += -L/Users/user/usr/local/Cellar/[email protected]/1.1.1m/lib
# OUTPUT_OPTION += -I/usr/local/opt/[email protected]/include
# LDLIBS += -L/usr/local/opt/[email protected]/lib
# OUTPUT_OPTION += -I$(HOME)/usr/local/Cellar/[email protected]/1.1.1m/include
# LDLIBS += -L$(HOME)/usr/local/Cellar/[email protected]/1.1.1m/lib
OUTPUT_OPTION += -I/usr/local/opt/[email protected]/include
LDLIBS += -L/usr/local/opt/[email protected]/lib

objects = $(patsubst $(dir_source)/%.cpp, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.cpp))
Expand Down
122 changes: 81 additions & 41 deletions src/kelf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
#include <openssl/des.h>
#include <string.h>
#include <errno.h>

#include "kelf.h"

Expand Down Expand Up @@ -83,7 +84,7 @@ void xor_bit(const void *a, const void *b, void *Result, size_t Length)
}
}

int Kelf::LoadKelf(std::string filename)
int Kelf::LoadKelf(const std::string filename)
{
FILE *f = fopen(filename.c_str(), "rb");
if (f == NULL) {
Expand All @@ -95,9 +96,10 @@ int Kelf::LoadKelf(std::string filename)
fread(&header, sizeof(header), 1, f);

if (header.Flags & 1 || header.Flags & 0xf0000 || header.BitCount != 0) {
printf("This file is not supported yet and looked after.");
printf("Please upload it and post it under that issue:");
printf("https://github.com/xfwcfw/kelftool/issues/1");
// TODO: check more unknown bit flags
printf("This file is not supported yet and looked after.\n");
printf("Please upload it and post it under that issue:\n");
printf("https://github.com/xfwcfw/kelftool/issues/1\n");
// fclose(f);
// return KELF_ERROR_UNSUPPORTED_FILE;
}
Expand Down Expand Up @@ -153,24 +155,24 @@ int Kelf::LoadKelf(std::string filename)
break;
}
printf("header.Flags = %#X", header.Flags);
if (header.Flags == 0x22C)
if (header.Flags == 0x022c)
printf(" - kelf:");
else if (header.Flags == 0x22C)
else if (header.Flags == 0x021c)
printf(" - kirx:");
else
printf(" - unknown:");
if (header.Flags & HDR_BLACKLIST)
printf("HDR_BLACKLIST|");
if (header.Flags & HDR_WHITELIST)
printf("HDR_WHITELIST|");
if (header.Flags & HDR_FLAG0_BLACKLIST)
printf("HDR_FLAG0_BLACKLIST|");
if (header.Flags & HDR_FLAG1_WHITELIST)
printf("HDR_FLAG1_WHITELIST|");
if (header.Flags & HDR_FLAG2)
printf("HDR_FLAG2|");
if (header.Flags & HDR_FLAG3)
printf("HDR_FLAG3|");
if (header.Flags & HDR_1DES)
printf("HDR_1DES|");
if (header.Flags & HDR_3DES)
printf("HDR_3DES|");
if (header.Flags & HDR_FLAG4_1DES)
printf("HDR_FLAG4_1DES|");
if (header.Flags & HDR_FLAG4_3DES)
printf("HDR_FLAG4_3DES|");
if (header.Flags & HDR_FLAG6)
printf("HDR_FLAG6|");
if (header.Flags & HDR_FLAG7)
Expand Down Expand Up @@ -230,6 +232,7 @@ int Kelf::LoadKelf(std::string filename)
printf("HeaderSignature =");
for (size_t i = 0; i < 8; ++i)
printf(" %02X", (unsigned char)HeaderSignature[i]);
printf("\n");

if (HeaderSignature != GetHeaderSignature(header)) {
fclose(f);
Expand Down Expand Up @@ -341,7 +344,7 @@ int Kelf::LoadKelf(std::string filename)
return 0;
}

int Kelf::SaveKelf(std::string filename, int headerid)
int Kelf::SaveKelf(const std::string filename, int headerid)
{
FILE *f = fopen(filename.c_str(), "wb");
if (f == NULL) {
Expand Down Expand Up @@ -371,9 +374,10 @@ int Kelf::SaveKelf(std::string filename, int headerid)
header.HeaderSize = bitTable.HeaderSize; // header + header signature + kbit + kc + bittable + bittable signature + root signature
header.SystemType = SYSTEM_TYPE_PS2; // same for COH (arcade)
header.ApplicationType = 1; // 1 = xosdmain, 5 = dvdplayer kirx 7 = dvdplayer kelf 0xB - ?? 0x00 - ??
header.Flags = 0x022C; // ?? 00000010 00101100 binary, 0x021C for kirx
header.MGZones = 0xFF; // region bit, 1 - allowed
header.BitCount = 0;
// TODO: implement and check 3DES/1DES difference based on header.Flags. In both - encryption and decryption.
header.Flags = 0x022C; // ?? 00000010 00101100 binary, 0x021C for kirx
header.MGZones = 0xFF; // region bit, 1 - allowed
header.BitCount = 0;
// ?? balika, wisi: strange value, represents number of blacklisted iLinkID, ConsoleID
// iLinkID (8 bytes), consoleID (8 bytes) placed between header.MGZones and HeaderSignature
// it is part of header, so HeaderSignature and header.HeaderSize should be recalculated
Expand Down Expand Up @@ -404,7 +408,7 @@ int Kelf::SaveKelf(std::string filename, int headerid)
return 0;
}

int Kelf::LoadContent(std::string filename, int headerid)
int Kelf::LoadContent(const std::string filename, int headerid)
{
FILE *f = fopen(filename.c_str(), "rb");
if (f == NULL) {
Expand Down Expand Up @@ -438,6 +442,7 @@ int Kelf::LoadContent(std::string filename, int headerid)
Kc.resize(16);
// memset(Kc.data(), 0xBB, Kc.size());

// memcpy(Kbit.data(), USER_Kc_MBR, 16);
std::fill(Kc.data(), Kc.data() + 16, 0xBB);
std::fill(bitTable.gap, bitTable.gap + 3, 0);

Expand All @@ -459,15 +464,15 @@ int Kelf::LoadContent(std::string filename, int headerid)

// bitTable.BlockCount = 6;
// bitTable.Blocks[0].Size = 0x40;
// bitTable.Blocks[0].Flags = 0;
// bitTable.Blocks[1].Size = 0x8;
// bitTable.Blocks[0].Flags = 2;
// bitTable.Blocks[1].Size = 0x10;
// bitTable.Blocks[1].Flags = BIT_BLOCK_SIGNED | BIT_BLOCK_ENCRYPTED;
// bitTable.Blocks[2].Size = 0x100;
// bitTable.Blocks[2].Flags = BIT_BLOCK_ENCRYPTED;
// bitTable.Blocks[3].Size = 0x40;
// bitTable.Blocks[3].Flags = 0;
// bitTable.Blocks[4].Size = 0x8;
// bitTable.Blocks[4].Flags = BIT_BLOCK_SIGNED | BIT_BLOCK_ENCRYPTED;
// bitTable.Blocks[4].Size = 0x10;
// bitTable.Blocks[4].Flags = BIT_BLOCK_SIGNED;
// bitTable.Blocks[5].Size = 0x100;
// bitTable.Blocks[5].Flags = BIT_BLOCK_ENCRYPTED;

Expand All @@ -476,29 +481,33 @@ int Kelf::LoadContent(std::string filename, int headerid)
bitTable.Blocks[0].Size = Content.size();
bitTable.Blocks[0].Flags = 0;

int SizeLeft = Content.size();
uint32_t offset = 0;
for (int i = 0; i < bitTable.BlockCount; ++i) {
// ignore last block defined size, and just use the rest of elf
// the same if current block reaches end of file
if ((i == bitTable.BlockCount - 1) || (SizeLeft < bitTable.Blocks[i].Size)) {
bitTable.Blocks[i].Size = SizeLeft;
if ((i == bitTable.BlockCount - 1) || (offset + bitTable.Blocks[i].Size > Content.size())) {
bitTable.Blocks[i].Size = Content.size() - offset;
bitTable.BlockCount = i + 1;
// TODO: zero padding last block, 8 bytes if signed, 16 bytes if encrypted
}

memset(bitTable.Blocks[i].Signature, 0, 8);

// TODO: currently Sign without encryption doesnt work properly. Needs more investigation
// try to look at decryption function, it is doing something weird
if (bitTable.Blocks[i].Flags & BIT_BLOCK_SIGNED)
// Sign
if (bitTable.Blocks[i].Flags & BIT_BLOCK_SIGNED) {
if (!(bitTable.Blocks[i].Flags & BIT_BLOCK_ENCRYPTED)) {
printf("kelftool encryption currently is buggy with only BIT_BLOCK_SIGNED flag set. Aborted\n");
// TODO: fix BIT_BLOCK_SIGNED alone support
// TODO: implement 1DES/3DES difference
printf("bitTable.Blocks[%d].Flags = BIT_BLOCK_SIGNED is not implemented during encryption. Encryption aborted.\n", i);
fclose(f);
return KELF_ERROR_UNSUPPORTED_FILE;
}

// Sign
if (bitTable.Blocks[i].Flags & BIT_BLOCK_SIGNED) {
for (int j = 0; j < bitTable.Blocks[i].Size; j += 8)
if (bitTable.Blocks[i].Size % 0x8) {
printf("bitTable.Blocks[%d].Size = %08X is not bounded to 0x8 (BIT_BLOCK_SIGNED). Encryption aborted.\n", i, bitTable.Blocks[i].Size);
fclose(f);
return KELF_ERROR_UNSUPPORTED_FILE;
}
for (unsigned int j = 0; j < bitTable.Blocks[i].Size; j += 8)
xor_bit(&Content.data()[offset + j], bitTable.Blocks[i].Signature, bitTable.Blocks[i].Signature, 8);

uint8_t MG_SIG_MASTER_AND_HASH_KEY[16];
Expand All @@ -510,20 +519,23 @@ int Kelf::LoadContent(std::string filename, int headerid)

// Encrypt
if (bitTable.Blocks[i].Flags & BIT_BLOCK_ENCRYPTED) {
if (bitTable.Blocks[i].Size % 0x10) {
printf("bitTable.Blocks[%d].Size = %08X is not bounded to 0x10 (BIT_BLOCK_ENCRYPTED). Encryption aborted.\n", i, bitTable.Blocks[i].Size);
fclose(f);
return KELF_ERROR_UNSUPPORTED_FILE;
}
TdesCbcCfb64Encrypt(&Content.data()[offset], &Content.data()[offset], bitTable.Blocks[i].Size, Kc.data(), 2, ks.GetContentIV().data());
}

// if we reach the end of lelf
SizeLeft -= bitTable.Blocks[i].Size;
// if we reach the end of file
offset += bitTable.Blocks[i].Size;
}

bitTable.HeaderSize = sizeof(KELFHeader) + 8 + 16 + 16 + (bitTable.BlockCount * 2 + 1) * 8 + 8 + 8; // header + header signature + kbit + kc + bittable (2 blocks) + bittable signature + root signature

return 0;
}

int Kelf::SaveContent(std::string filename)
int Kelf::SaveContent(const std::string filename)
{
FILE *f = fopen(filename.c_str(), "wb");
if (f == NULL) {
Expand Down Expand Up @@ -565,7 +577,7 @@ std::string Kelf::DeriveKeyEncryptionKey(KELFHeader &header)
return std::string((char *)KEK, 16);
}

void Kelf::DecryptKeys(std::string KEK)
void Kelf::DecryptKeys(const std::string KEK)
{
TdesCbcCfb64Decrypt((uint8_t *)Kbit.data(), (uint8_t *)Kbit.data(), 8, (uint8_t *)KEK.data(), 2, MG_IV_NULL);
TdesCbcCfb64Decrypt((uint8_t *)Kbit.data() + 8, (uint8_t *)Kbit.data() + 8, 8, (uint8_t *)KEK.data(), 2, MG_IV_NULL);
Expand All @@ -574,7 +586,7 @@ void Kelf::DecryptKeys(std::string KEK)
TdesCbcCfb64Decrypt((uint8_t *)Kc.data() + 8, (uint8_t *)Kc.data() + 8, 8, (uint8_t *)KEK.data(), 2, MG_IV_NULL);
}

void Kelf::EncryptKeys(std::string KEK)
void Kelf::EncryptKeys(const std::string KEK)
{
TdesCbcCfb64Encrypt((uint8_t *)Kbit.data(), (uint8_t *)Kbit.data(), 8, (uint8_t *)KEK.data(), 2, MG_IV_NULL);
TdesCbcCfb64Encrypt((uint8_t *)Kbit.data() + 8, (uint8_t *)Kbit.data() + 8, 8, (uint8_t *)KEK.data(), 2, MG_IV_NULL);
Expand Down Expand Up @@ -656,13 +668,41 @@ int Kelf::VerifyContentSignature()
std::string SigMasterEnc;
SigMasterEnc.resize(bitTable.Blocks[i].Size);
TdesCbcCfb64Encrypt(SigMasterEnc.data(), &Content.data()[offset], bitTable.Blocks[i].Size, ks.GetSignatureMasterKey().data(), 1, MG_IV_NULL);
// printf("SigMasterEnc.data() = ");
// for (unsigned int j = 0; j < 8; ++j)
// printf(" %02X", (unsigned char)SigMasterEnc.data()[j]);
// printf("\n");

memcpy(signature, &SigMasterEnc.data()[bitTable.Blocks[i].Size - 8], 8);
// printf("signature = ");
// for (unsigned int j = 0; j < 8; ++j)
// printf(" %02X", (unsigned char)signature[j]);
// printf("\n");

TdesCbcCfb64Decrypt(signature, signature, 8, ks.GetSignatureHashKey().data(), 1, MG_IV_NULL);
// printf("signature = ");
// for (unsigned int j = 0; j < 8; ++j)
// printf(" %02X", (unsigned char)signature[j]);
// printf("\n");

TdesCbcCfb64Encrypt(signature, signature, 8, ks.GetSignatureMasterKey().data(), 1, MG_IV_NULL);
printf("signature = ");
for (unsigned int j = 0; j < 8; ++j)
printf(" %02X", (unsigned char)signature[j]);
printf("\n");
}

if (memcmp(bitTable.Blocks[i].Signature, signature, 8) != 0)
if (memcmp(bitTable.Blocks[i].Signature, signature, 8) != 0) {
printf("bitTable.Blocks[%u].Signature = ", i);
for (unsigned int j = 0; j < 8; ++j)
printf(" %02X", (unsigned char)bitTable.Blocks[i].Signature[j]);
printf("\n");
printf("Signature calculated = ");
for (unsigned int j = 0; j < 8; ++j)
printf(" %02X", (unsigned char)signature[j]);
printf("\n");
return KELF_ERROR_INVALID_CONTENT_SIGNATURE;
}
}

offset += bitTable.Blocks[i].Size;
Expand Down
36 changes: 19 additions & 17 deletions src/kelf.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ static uint8_t USER_HEADER_FMCB[16] = {0x01, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00,
static uint8_t USER_HEADER_FHDB[16] = {0x01, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x4A, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1B};
static uint8_t USER_HEADER_MBR[16] = {0x01, 0x00, 0x00, 0x04, 0x00, 0x02, 0x01, 0x57, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A};

// static uint8_t USER_Kc_MBR[16] = {0xD2 ,0xC6 ,0x8F ,0xC2 ,0xEB ,0xA0 ,0x5B ,0x63 ,0x3F ,0x0B ,0xF8 ,0x7B ,0x46 ,0x0E ,0x0D ,0x93};
// static uint8_t USER_Kbit_MBR[16] = {0x83 ,0x1E ,0x4E ,0x4B ,0x42 ,0xCA ,0x7F ,0x39 ,0x0C ,0xB7 ,0xC5 ,0xFB ,0x81 ,0xB1 ,0x10 ,0xDA};
static uint8_t USER_Kbit_MBR[16] = {0x82, 0xf0, 0x29, 0xad, 0xe9, 0x53, 0x23, 0xf5, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
static uint8_t USER_Kbit_FHDB[16] = {0x40, 0xe9, 0x80, 0x4d, 0x2e, 0x92, 0xb0, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
static uint8_t USER_Kbit_FMCB[16] = {0xd9, 0x4a, 0x2e, 0x56, 0x01, 0x6e, 0xa7, 0x31, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
Expand All @@ -58,22 +60,22 @@ struct KELFHeader
};

// possible BitBlock.Flags. Other bit flags should be unset
#define HDR_BLACKLIST 0x1 // Unset. if set then BitCount should be non-zero, and header will change its size
#define HDR_WHITELIST 0x2 // Unset. maybe whitelist? ICVPS2 ??
#define HDR_FLAG2 0x4 // Set. ??
#define HDR_FLAG3 0x8 // Set. ??
#define HDR_1DES 0x10 // Set in kirx. HDR_3DES should be unset. Represents Single DES encryption
#define HDR_3DES 0x20 // Set in kelf. HDR_1DES should be unset. Represents Single DES encryption
#define HDR_FLAG6 0x40 // Unset. ??
#define HDR_FLAG7 0x80 // Unset. ??
#define HDR_FLAG8 0x100 // Unset. ??
#define HDR_FLAG9 0x200 // Unset. ??
#define HDR_FLAG10 0x400 // Set. ??
#define HDR_FLAG11 0x800 // Unset. ??
#define HDR_FLAG12 0x1000 // Unset. ??
#define HDR_FLAG13 0x2000 // Unset. ??
#define HDR_FLAG14 0x4000 // Unset. ??
#define HDR_FLAG15 0x8000 // Unset. ??
#define HDR_FLAG0_BLACKLIST 0x1 // Unset. if set then BitCount should be non-zero, and header will change its size
#define HDR_FLAG1_WHITELIST 0x2 // Unset. maybe whitelist? ICVPS2 ??
#define HDR_FLAG2 0x4 // Set. ??
#define HDR_FLAG3 0x8 // Set. ??
#define HDR_FLAG4_1DES 0x10 // Set in kirx. HDR_FLAG4_3DES should be unset. Represents Single DES encryption
#define HDR_FLAG4_3DES 0x20 // Set in kelf. HDR_FLAG4_1DES should be unset. Represents Single DES encryption
#define HDR_FLAG6 0x40 // Unset. ??
#define HDR_FLAG7 0x80 // Unset. ??
#define HDR_FLAG8 0x100 // Unset. ??
#define HDR_FLAG9 0x200 // Unset. ??
#define HDR_FLAG10 0x400 // Set. ??
#define HDR_FLAG11 0x800 // Unset. ??
#define HDR_FLAG12 0x1000 // Unset. ??
#define HDR_FLAG13 0x2000 // Unset. ??
#define HDR_FLAG14 0x4000 // Unset. ??
#define HDR_FLAG15 0x8000 // Unset. ??

// MGZones region flags. If unset - blocked in that region
#define REGION_JP 0x1 // Japan
Expand Down Expand Up @@ -114,7 +116,7 @@ class Kelf
std::string Content;

public:
Kelf(KeyStore &_ks)
explicit Kelf(KeyStore &_ks)
: ks(_ks)
{
}
Expand Down
18 changes: 14 additions & 4 deletions src/kelftool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "keystore.h"
#include "kelf.h"

// TODO: implement load/save kelf header configuration for byte-perfect encryption, decryption

std::string getKeyStorePath()
{
#if defined(__linux__) || defined(__APPLE__)
Expand All @@ -39,8 +41,12 @@ int decrypt(int argc, char **argv)
KeyStore ks;
int ret = ks.Load(getKeyStorePath());
if (ret != 0) {
printf("Failed to load keystore: %d - %s\n", ret, KeyStore::getErrorString(ret).c_str());
return ret;
// try to load keys from working directory
ret = ks.Load("./PS2KEYS.dat");
if (ret != 0) {
printf("Failed to load keystore: %d - %s\n", ret, KeyStore::getErrorString(ret).c_str());
return ret;
}
}

Kelf kelf(ks);
Expand Down Expand Up @@ -87,8 +93,12 @@ int encrypt(int argc, char **argv)
KeyStore ks;
int ret = ks.Load(getKeyStorePath());
if (ret != 0) {
printf("Failed to load keystore: %d - %s\n", ret, KeyStore::getErrorString(ret).c_str());
return ret;
// try to load keys from working directory
ret = ks.Load("./PS2KEYS.dat");
if (ret != 0) {
printf("Failed to load keystore: %d - %s\n", ret, KeyStore::getErrorString(ret).c_str());
return ret;
}
}

Kelf kelf(ks);
Expand Down

0 comments on commit e0532cf

Please sign in to comment.