-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathPfsKeyGenerator.cpp
145 lines (109 loc) · 4.65 KB
/
PfsKeyGenerator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "PfsKeyGenerator.h"
#include <string>
#include <cstring>
#include <stdexcept>
#include "PfsKeys.h"
#include "IcvPrimitives.h"
#include "PfsCryptEngine.h"
#include "SecretGenerator.h"
#include "FlagOperations.h"
//[TESTED]
//this function can be used both for gamedata and savedata
int generate_enckeys(std::shared_ptr<ICryptoOperations> cryptops, unsigned char* dec_key, unsigned char* tweak_enc_key, const unsigned char* klicensee, std::uint32_t icv_salt)
{
int saltin[2] = {0};
unsigned char base0[0x14] = {0};
unsigned char base1[0x14] = {0};
unsigned char drvkey[0x14] = {0};
icv_set_sw(cryptops, base0, klicensee, 0x10); //calculate hash of klicensee
saltin[0] = icv_salt;
// derive key 0
saltin[1] = 1;
icv_set_sw(cryptops, base1, (unsigned char *)saltin, 8); //calculate hash of salt 0
icv_contract(cryptops, drvkey, base0, base1); //calculate hash from combination of salt 0 hash and klicensee hash
memcpy(dec_key, drvkey, 0x10); //copy derived key
// derive key 1
saltin[1] = 2;
icv_set_sw(cryptops, base1, (unsigned char*)saltin, 8); //calculate hash of salt 1
icv_contract(cryptops, drvkey, base0, base1); //calculate hash from combination of salt 1 hash and klicensee hash
memcpy(tweak_enc_key, drvkey, 0x10); //copy derived key
return 0;
}
//[TESTED both branches]
//this function is used only for gamedata with icv_version <= 1
//files_salt is not empty starting from FILES_EXPECTED_VERSION_4
int gen_iv(std::shared_ptr<ICryptoOperations> cryptops, unsigned char* tweak_enc_key, std::uint32_t files_salt, std::uint32_t icv_salt)
{
unsigned char drvkey[0x14] = {0};
if(files_salt == 0)
{
int saltin0[1] = {0};
saltin0[0] = icv_salt;
icv_set_hmac_sw(cryptops, drvkey, hmac_key0, (unsigned char*)saltin0, 4); // derive key with one salt
}
else
{
int saltin1[2] = {0};
saltin1[0] = files_salt;
saltin1[1] = icv_salt;
icv_set_hmac_sw(cryptops, drvkey, hmac_key0, (unsigned char*)saltin1, 8); // derive key with two salts
}
memcpy(tweak_enc_key, drvkey, 0x10); //copy derived key
return 0;
}
//---------------------
//[TESTED]
//this function is used for savedata
int scePfsUtilGetSDKeys(std::shared_ptr<ICryptoOperations> cryptops, unsigned char* dec_key, unsigned char* tweak_enc_key, const unsigned char* klicensee, std::uint32_t files_salt, std::uint32_t icv_salt)
{
//files_salt is ignored
return generate_enckeys(cryptops, dec_key, tweak_enc_key, klicensee, icv_salt);
}
//[TESTED one branch]
//this function is used for gamedata with icv_version <= 1
int scePfsUtilGetGDKeys(std::shared_ptr<ICryptoOperations> cryptops, unsigned char* dec_key, unsigned char* tweak_enc_key, const unsigned char* klicensee, std::uint32_t files_salt, std::uint16_t crypto_engine_flag, std::uint32_t icv_salt)
{
if(crypto_engine_flag & CRYPTO_ENGINE_CRYPTO_USE_KEYGEN)
{
memcpy(dec_key, klicensee, 0x10);
return gen_iv(cryptops, tweak_enc_key, files_salt, icv_salt);
}
else
{
throw std::runtime_error("Untested branch in scePfsUtilGetGDKeys");
return generate_enckeys(cryptops, dec_key, tweak_enc_key, klicensee, icv_salt);
}
}
//[TESTED]
//this function is used for gamedata with icv_version > 1
int scePfsUtilGetGDKeys2(std::shared_ptr<ICryptoOperations> cryptops, unsigned char* dec_key, unsigned char* tweak_enc_key, const unsigned char* klicensee, const unsigned char* dbseed, std::uint32_t dbseed_len)
{
unsigned char drvkey[0x14] = {0};
icv_set_hmac_sw(cryptops, drvkey, hmac_key0, dbseed, dbseed_len);
memcpy(dec_key, klicensee, 0x10);
memcpy(tweak_enc_key, drvkey, 0x10);
return 0;
}
//---------------------
//[TESTED]
//this function is used to derive keys for gamedata and savedata
int setup_crypt_packet_keys(std::shared_ptr<ICryptoOperations> cryptops, std::shared_ptr<IF00DKeyEncryptor> iF00D, CryptEngineData* data, const derive_keys_ctx* drv_ctx)
{
if(is_gamedata(data->mode_index))
{
if(has_dbseed(drv_ctx->db_type, drv_ctx->icv_version))
{
// only ro db with version > 1
scePfsUtilGetGDKeys2(cryptops, data->dec_key, data->tweak_enc_key, data->klicensee, drv_ctx->dbseed, 0x14);
}
else
{
scePfsUtilGetGDKeys(cryptops, data->dec_key, data->tweak_enc_key, data->klicensee, data->files_salt, data->crypto_engine_flag, data->icv_salt);
}
}
else
{
scePfsUtilGetSDKeys(cryptops, data->dec_key, data->tweak_enc_key, data->klicensee, data->files_salt, data->icv_salt);
}
return scePfsUtilGetSecret(cryptops, iF00D, data->secret, data->klicensee, data->files_salt, data->crypto_engine_flag, data->icv_salt, data->key_id);
}