/
hash.c
114 lines (95 loc) · 3.51 KB
/
hash.c
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
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* hash.c - Hashing routines using sceChnnlsv
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: hash.c 1560 2005-12-10 01:16:32Z jim $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "chnnlsv.h"
#include "hash.h"
#include "psf.h"
static inline int align16(unsigned int v)
{
return ((v + 0xF) >> 4) << 4;
}
/* Update the hashes in the param.sfo data, using
the given file hash, and by computing the param.sfo hashes.
filehash must be a multiple of 16 bytes, and is reused to
store other hashes. The filename is e.g. "DATA.BIN". */
int update_hashes(unsigned char *data, int len, const char *filename,
unsigned char *filehash, int encryptmode)
{
int alignedLen = align16(len);
unsigned char *datafile, *savedata_params;
int listLen, paramsLen;
int ret;
/* Locate SAVEDATA_PARAM section in the param.sfo. */
if ((ret = find_psf_section("SAVEDATA_PARAMS", data, 0x1330,
&savedata_params, ¶msLen)) < 0)
return ret - 100;
/* Locate the pointer for this DATA.BIN equivalent */
if ((ret = find_psf_section("SAVEDATA_FILE_LIST", data, 0x1330, &datafile,
&listLen)) < 0)
return ret - 200;
if ((ret = find_psf_datafile(filename, datafile, listLen, &datafile)) < 0)
return ret - 300;
/* Check minimum sizes based on where we want to write */
if ((listLen < 0x20) || (paramsLen < 0x80))
return -1;
/* Clear params and insert file hash */
memset(savedata_params, 0, paramsLen);
memcpy(datafile + 0x0D, filehash, 0x10);
/* Compute 11D0 hash over entire file */
if ((ret = build_hash(filehash, data, len, alignedLen,
(encryptmode & 2) ? 4 : 2, NULL)) < 0) /* Not sure about "2" */
return ret - 400;
/* Copy 11D0 hash to param.sfo and set flag indicating it's there */
memcpy(savedata_params + 0x20, filehash, 0x10);
*savedata_params |= 0x01;
/* If new encryption mode, compute and insert the 1220 hash. */
if (encryptmode & 2) {
/* Enable the hash bit first */
*savedata_params |= 0x20;
if ((ret = build_hash(filehash, data, len, alignedLen, 3, 0)) < 0)
return ret - 500;
memcpy(savedata_params + 0x70, filehash, 0x10);
}
/* Compute and insert the 11C0 hash. */
if ((ret = build_hash(filehash, data, len, alignedLen, 1, 0)) < 0)
return ret - 600;
memcpy(savedata_params + 0x10, filehash, 0x10);
/* All done. */
return 0;
}
/* Build a single hash using the given data and mode.
data and alignedLen must be multiples of 0x10.
cryptkey is NULL for savedata. */
int build_hash(unsigned char *output, unsigned char *data, unsigned int len,
unsigned int alignedLen, int mode, unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(output, 0, 0x10);
memset(data + len, 0, alignedLen - len);
/* Perform the magic */
if (sceSdSetIndex_(&ctx1, mode & 0xFF) < 0)
return -1;
if (sceSdRemoveValue_(&ctx1, data, alignedLen) < 0)
return -2;
if (sceSdGetLastIndex_(&ctx1, output, cryptkey) < 0) {
// Got here since Kirk CMD5 missing, return random value;
memset(output, 0x1, 0x10);
return 0;
}
/* All done. */
return 0;
}