Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
core/crypto/crypto.cpp
ShadPKG / core / crypto / crypto.cpp
1// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3 
4#include <array>
5 
6#include "crypto.h"
7 
8CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
9 CryptoPP::InvertibleRSAFunction params;
10 params.SetPrime1(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime1, 0x80));
11 params.SetPrime2(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime2, 0x80));
12 
13 params.SetPublicExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PublicExponent, 4));
14 params.SetPrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PrivateExponent, 0x100));
15 
16 params.SetModPrime1PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent1, 0x80));
17 params.SetModPrime2PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent2, 0x80));
18 
19 params.SetModulus(CryptoPP::Integer(PkgDerivedKey3Keyset::Modulus, 0x100));
20 params.SetMultiplicativeInverseOfPrime2ModPrime1(
21 CryptoPP::Integer(PkgDerivedKey3Keyset::Coefficient, 0x80));
22 
23 CryptoPP::RSA::PrivateKey privateKey(params);
24 
25 return privateKey;
26}
27 
28CryptoPP::RSA::PrivateKey Crypto::FakeKeyset_keyset_init() {
29 CryptoPP::InvertibleRSAFunction params;
30 params.SetPrime1(CryptoPP::Integer(FakeKeyset::Prime1, 0x80));
31 params.SetPrime2(CryptoPP::Integer(FakeKeyset::Prime2, 0x80));
32 
33 params.SetPublicExponent(CryptoPP::Integer(FakeKeyset::PublicExponent, 4));
34 params.SetPrivateExponent(CryptoPP::Integer(FakeKeyset::PrivateExponent, 0x100));
35 
36 params.SetModPrime1PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent1, 0x80));
37 params.SetModPrime2PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent2, 0x80));
38 
39 params.SetModulus(CryptoPP::Integer(FakeKeyset::Modulus, 0x100));
40 params.SetMultiplicativeInverseOfPrime2ModPrime1(
41 CryptoPP::Integer(FakeKeyset::Coefficient, 0x80));
42 
43 CryptoPP::RSA::PrivateKey privateKey(params);
44 
45 return privateKey;
46}
47 
48CryptoPP::RSA::PrivateKey Crypto::DebugRifKeyset_init() {
49 CryptoPP::InvertibleRSAFunction params;
50 params.SetPrime1(CryptoPP::Integer(DebugRifKeyset::Prime1, sizeof(DebugRifKeyset::Prime1)));
51 params.SetPrime2(CryptoPP::Integer(DebugRifKeyset::Prime2, sizeof(DebugRifKeyset::Prime2)));
52 
53 params.SetPublicExponent(
54 CryptoPP::Integer(DebugRifKeyset::PublicExponent, sizeof(DebugRifKeyset::PublicExponent)));
55 params.SetPrivateExponent(CryptoPP::Integer(DebugRifKeyset::PrivateExponent,
56 sizeof(DebugRifKeyset::PrivateExponent)));
57 
58 params.SetModPrime1PrivateExponent(
59 CryptoPP::Integer(DebugRifKeyset::Exponent1, sizeof(DebugRifKeyset::Exponent1)));
60 params.SetModPrime2PrivateExponent(
61 CryptoPP::Integer(DebugRifKeyset::Exponent2, sizeof(DebugRifKeyset::Exponent2)));
62 
63 params.SetModulus(CryptoPP::Integer(DebugRifKeyset::Modulus, sizeof(DebugRifKeyset::Modulus)));
64 params.SetMultiplicativeInverseOfPrime2ModPrime1(
65 CryptoPP::Integer(DebugRifKeyset::Coefficient, sizeof(DebugRifKeyset::Coefficient)));
66 
67 CryptoPP::RSA::PrivateKey privateKey(params);
68 
69 return privateKey;
70}
71 
72void Crypto::RSA2048Decrypt(std::span<CryptoPP::byte, 32> dec_key,
73 std::span<const CryptoPP::byte, 256> ciphertext,
74 bool is_dk3) { // RSAES_PKCS1v15_
75 // Create an RSA decryptor
76 CryptoPP::RSA::PrivateKey privateKey;
77 if (is_dk3) {
78 privateKey = key_pkg_derived_key3_keyset_init();
79 } else {
80 privateKey = FakeKeyset_keyset_init();
81 }
82 
83 CryptoPP::RSAES_PKCS1v15_Decryptor rsaDecryptor(privateKey);
84 
85 // Allocate memory for the decrypted data
86 std::array<CryptoPP::byte, 256> decrypted;
87 
88 // Perform the decryption
89 CryptoPP::AutoSeededRandomPool rng;
90 CryptoPP::DecodingResult result =
91 rsaDecryptor.Decrypt(rng, ciphertext.data(), decrypted.size(), decrypted.data());
92 std::copy(decrypted.begin(), decrypted.begin() + dec_key.size(), dec_key.begin());
93}
94 
95void Crypto::ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
96 std::span<CryptoPP::byte, 32> ivkey_result) {
97 CryptoPP::SHA256 sha256;
98 std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> hashResult;
99 auto array_sink = new CryptoPP::ArraySink(hashResult.data(), CryptoPP::SHA256::DIGESTSIZE);
100 auto filter = new CryptoPP::HashFilter(sha256, array_sink);
101 CryptoPP::ArraySource r(cipher_input.data(), cipher_input.size(), true, filter);
102 std::copy(hashResult.begin(), hashResult.begin() + ivkey_result.size(), ivkey_result.begin());
103}
104 
105void Crypto::aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
106 std::span<const CryptoPP::byte, 256> ciphertext,
107 std::span<CryptoPP::byte, 256> decrypted) {
108 std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
109 std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
110 
111 std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
112 std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
113 
114 CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
115 CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
116 
117 for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
118 cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
119 CryptoPP::AES::BLOCKSIZE);
120 }
121}
122 
123void Crypto::aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
124 std::span<CryptoPP::byte> ciphertext,
125 std::span<CryptoPP::byte> decrypted) {
126 std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
127 std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
128 
129 std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
130 std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
131 
132 CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
133 CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
134 
135 for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
136 cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
137 CryptoPP::AES::BLOCKSIZE);
138 }
139}
140 
141void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
142 std::span<CryptoPP::byte, 16> NPcommID,
143 std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
144 std::span<CryptoPP::byte> decrypted) {
145 
146 // step 1: Encrypt NPcommID
147 CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
148 
149 std::vector<CryptoPP::byte> trophyIv(16, 0);
150 std::vector<CryptoPP::byte> trpKey(16);
151 
152 encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
153 encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
154 
155 // step 2: decrypt efsm.
156 CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
157 decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
158 
159 for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
160 decrypt.ProcessData(decrypted.data() + i, ciphertext.data() + i, CryptoPP::AES::BLOCKSIZE);
161 }
162}
163 
164void Crypto::PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
165 std::span<const CryptoPP::byte, 16> seed,
166 std::span<CryptoPP::byte, 16> dataKey,
167 std::span<CryptoPP::byte, 16> tweakKey) {
168 CryptoPP::HMAC<CryptoPP::SHA256> hmac(ekpfs.data(), ekpfs.size());
169 
170 CryptoPP::SecByteBlock d(20); // Use Crypto++ SecByteBlock for better memory management
171 
172 // Copy the bytes of 'index' to the 'd' array
173 uint32_t index = 1;
174 std::memcpy(d, &index, sizeof(uint32_t));
175 
176 // Copy the bytes of 'seed' to the 'd' array starting from index 4
177 std::memcpy(d + sizeof(uint32_t), seed.data(), seed.size());
178 
179 // Allocate memory for 'u64' using new
180 std::vector<CryptoPP::byte> data_tweak_key(hmac.DigestSize());
181 
182 // Calculate the HMAC
183 hmac.CalculateDigest(data_tweak_key.data(), d, d.size());
184 std::copy(data_tweak_key.begin(), data_tweak_key.begin() + dataKey.size(), tweakKey.begin());
185 std::copy(data_tweak_key.begin() + tweakKey.size(),
186 data_tweak_key.begin() + tweakKey.size() + dataKey.size(), dataKey.begin());
187}
188 
189void Crypto::decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
190 std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
191 std::span<CryptoPP::byte> dst_image, u64 sector) {
192 // Start at 0x10000 to keep the header when decrypting the whole pfs_image.
193 for (int i = 0; i < src_image.size(); i += 0x1000) {
194 const u64 current_sector = sector + (i / 0x1000);
195 CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption encrypt(tweakKey.data(), tweakKey.size());
196 CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption decrypt(dataKey.data(), dataKey.size());
197 
198 std::array<CryptoPP::byte, 16> tweak{};
199 std::array<CryptoPP::byte, 16> encryptedTweak;
200 std::array<CryptoPP::byte, 16> xorBuffer;
201 std::memcpy(tweak.data(), &current_sector, sizeof(u64));
202 
203 // Encrypt the tweak for each sector.
204 encrypt.ProcessData(encryptedTweak.data(), tweak.data(), 16);
205 
206 for (int plaintextOffset = 0; plaintextOffset < 0x1000; plaintextOffset += 16) {
207 xtsXorBlock(xorBuffer.data(), src_image.data() + i + plaintextOffset,
208 encryptedTweak.data()); // x, c, t
209 decrypt.ProcessData(xorBuffer.data(), xorBuffer.data(), 16); // x, x
210 xtsXorBlock(dst_image.data() + i + plaintextOffset, xorBuffer.data(),
211 encryptedTweak.data()); //(p) c, x , t
212 xtsMult(encryptedTweak);
213 }
214 }
215}
216