CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Tools/SaveTool/encrypt.c
Views: 1401
1
/*
2
* PSP Software Development Kit - http://www.pspdev.org
3
* -----------------------------------------------------------------------
4
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
5
*
6
* encrypt.c - Encryption routines using sceChnnlsv
7
*
8
* Copyright (c) 2005 Jim Paris <[email protected]>
9
* Coypright (c) 2005 psp123
10
*
11
* $Id: encrypt.c 1560 2005-12-10 01:16:32Z jim $
12
*/
13
14
#include "encrypt.h"
15
#include "hash.h"
16
#include <stdio.h>
17
#include <stdlib.h>
18
#include <string.h>
19
#include <malloc.h>
20
#include <pspchnnlsv.h>
21
#include "kernelcall/kernelcall.h"
22
23
static inline int align16(unsigned int v)
24
{
25
return ((v + 0xF) >> 4) << 4;
26
}
27
28
int fopen_getsize(const char *filename, FILE **fd, int *size)
29
{
30
if ((*fd = fopen(filename, "r")) == NULL)
31
return -1;
32
33
fseek(*fd, 0, SEEK_END);
34
*size = ftell(*fd);
35
fseek(*fd, 0, SEEK_SET);
36
37
if (*size <= 0) {
38
fclose(*fd);
39
return -2;
40
}
41
42
return 0;
43
}
44
45
/* Encrypt the given plaintext file, and update the message
46
authentication hashes in the param.sfo. The data_filename is
47
usually the final component of encrypted_filename, e.g. "DATA.BIN".
48
See main.c for an example of usage. */
49
int encrypt_file(const char *plaintext_filename,
50
const char *encrypted_filename,
51
const char *data_filename,
52
const char *paramsfo_filename,
53
const char *paramsfo_filename_out,
54
const unsigned char *gamekey,
55
const int mainSdkVersion)
56
{
57
FILE *in = NULL, *out = NULL, *sfo = NULL;
58
unsigned char *data = NULL, *cryptkey = NULL, *hash = NULL;
59
unsigned char paramsfo[0x1330];
60
int len, aligned_len, tmp;
61
int retval;
62
63
/* Open plaintext and param.sfo files and get size */
64
65
if (fopen_getsize(plaintext_filename, &in, &len) < 0) {
66
retval = -1;
67
goto out;
68
}
69
70
if (fopen_getsize(paramsfo_filename, &sfo, &tmp) < 0) {
71
retval = -2;
72
goto out;
73
}
74
75
/* Verify size of param.sfo; all known saves use this size */
76
77
if (tmp != 0x1330) {
78
retval = -3;
79
goto out;
80
}
81
82
/* Allocate buffers. data has 0x10 bytes extra for the IV. */
83
84
aligned_len = align16(len);
85
86
if ((data =
87
(unsigned char *) memalign(0x10, aligned_len + 0x10)) == NULL) {
88
retval = -4;
89
goto out;
90
}
91
92
if ((cryptkey = (unsigned char *) memalign(0x10, 0x10)) == NULL) {
93
retval = -5;
94
goto out;
95
}
96
97
if ((hash = (unsigned char *) memalign(0x10, 0x10)) == NULL) {
98
retval = -6;
99
goto out;
100
}
101
102
/* Fill buffers. */
103
104
memset(data + len, 0, aligned_len - len);
105
if (fread(data, 1, len, in) != len) {
106
retval = -7;
107
goto out;
108
}
109
110
if (fread(paramsfo, 1, 0x1330, sfo) != 0x1330) {
111
retval = -8;
112
goto out;
113
}
114
115
if (gamekey != NULL)
116
memcpy(cryptkey, gamekey, 0x10);
117
118
/* Do the encryption */
119
120
if ((retval = encrypt_data( gamekey ? (mainSdkVersion >= 4 ? 5 : 3) : 1, // 5 for sdk >= 4, 3 otherwise
121
data,
122
&len, &aligned_len,
123
hash,
124
gamekey ? cryptkey : NULL)) < 0) {
125
retval -= 1000;
126
goto out;
127
}
128
129
/* Update the param.sfo hashes */
130
131
if ((retval = update_hashes(paramsfo, 0x1330,
132
data_filename, hash,
133
gamekey ? 3 : 1)) < 0) {
134
retval -= 2000;
135
goto out;
136
}
137
138
/* Write the data to the file. encrypt_data has already set len. */
139
140
if ((out = fopen(encrypted_filename, "w")) == NULL) {
141
retval = -9;
142
goto out;
143
}
144
145
if (fwrite(data, 1, len, out) != len) {
146
retval = -10;
147
goto out;
148
}
149
150
/* Reopen param.sfo, and write the updated copy out. */
151
152
fclose(sfo);
153
if ((sfo = fopen(paramsfo_filename_out, "w")) == NULL) {
154
retval = -11;
155
goto out;
156
}
157
158
if (fwrite(paramsfo, 1, 0x1330, sfo) != 0x1330) {
159
retval = -12;
160
goto out;
161
}
162
163
/* All done. Return file length. */
164
165
retval = len;
166
167
out:
168
if(out) fclose(out);
169
if(hash) free(hash);
170
if(cryptkey) free(cryptkey);
171
if(data) free(data);
172
if(sfo) fclose(sfo);
173
if(in) fclose(in);
174
175
return retval;
176
}
177
178
/* Do the actual hardware encryption.
179
mode is 3 for saves with a cryptkey, or 1 otherwise
180
data, dataLen, and cryptkey must be multiples of 0x10.
181
cryptkey is NULL if mode == 1.
182
*/
183
int encrypt_data(unsigned int mode,
184
unsigned char *data,
185
int *dataLen,
186
int *alignedLen,
187
unsigned char *hash,
188
unsigned char *cryptkey)
189
{
190
pspChnnlsvContext1 ctx1;
191
pspChnnlsvContext2 ctx2;
192
193
/* Make room for the IV in front of the data. */
194
memmove(data + 0x10, data, *alignedLen);
195
196
/* Set up buffers */
197
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
198
memset(&ctx2, 0, sizeof(pspChnnlsvContext2));
199
memset(hash, 0, 0x10);
200
memset(data, 0, 0x10);
201
202
/* Build the 0x10-byte IV and setup encryption */
203
if (sceChnnlsv_ABFDFC8B_(&ctx2, mode, 1, data, cryptkey) < 0)
204
return -1;
205
if (sceChnnlsv_E7833020_(&ctx1, mode) < 0)
206
return -2;
207
if (sceChnnlsv_F21A1FCA_(&ctx1, data, 0x10) < 0)
208
return -3;
209
if (sceChnnlsv_850A7FA1_(&ctx2, data + 0x10, *alignedLen) < 0)
210
return -4;
211
212
/* Clear any extra bytes left from the previous steps */
213
memset(data + 0x10 + *dataLen, 0, *alignedLen - *dataLen);
214
215
/* Encrypt the data */
216
if (sceChnnlsv_F21A1FCA_(&ctx1, data + 0x10, *alignedLen) < 0)
217
return -5;
218
219
/* Verify encryption */
220
if (sceChnnlsv_21BE78B4_(&ctx2) < 0)
221
return -6;
222
223
/* Build the file hash from this PSP */
224
if (sceChnnlsv_C4C494F8_(&ctx1, hash, cryptkey) < 0)
225
return -7;
226
227
/* Adjust sizes to account for IV */
228
*alignedLen += 0x10;
229
*dataLen += 0x10;
230
231
/* All done */
232
return 0;
233
}
234
235