1 // Copyright 2010 Sven Peter <svenpeter@gmail.com>
2 // Licensed under the terms of the GNU GPL, version 2
3 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
19 static u8 info0
[0x40];
20 static u8 info1
[0x40];
23 static u64 content_size_real
;
24 static u64 content_size_compressed
;
26 static u8 sce_hdr
[0x20];
27 static u8 meta_hdr
[0x2a0];
32 static void get_file(u8
*bfr
, const char *name
, u64 size
)
36 fp
= fopen(name
, "rb");
38 fail("fopen(%s) failed", name
);
40 fread(bfr
, size
, 1, fp
);
44 static void get_content(void)
51 base
= mmap_file("content");
53 if (stat("content", &st
) < 0)
54 fail("stat(content) failed");
56 content_size_real
= st
.st_size
;
57 content_size_compressed
= compressBound(content_size_real
);
58 size_zlib
= content_size_compressed
;
60 content
= malloc(content_size_compressed
);
62 fail("out of memory");
64 res
= compress(content
, &size_zlib
, base
, content_size_real
);
66 fail("compress returned %d", res
);
68 content_size_compressed
= size_zlib
;
69 content
= realloc(content
, content_size_compressed
);
71 fail("out of memory");
74 static void get_key(const char *suffix
)
76 if (key_get(KEY_PKG
, suffix
, &k
) < 0)
77 fail("key_get() failed");
80 fail("no public key available");
83 fail("no private key available");
85 if (ecdsa_set_curve(k
.ctype
) < 0)
86 fail("ecdsa_set_curve failed");
89 ecdsa_set_priv(k
.priv
);
92 static void build_sce_hdr(void)
94 memset(sce_hdr
, 0, sizeof sce_hdr
);
96 wbe32(sce_hdr
+ 0x00, 0x53434500); // magic
97 wbe32(sce_hdr
+ 0x04, 2); // version
98 wbe16(sce_hdr
+ 0x08, 0); // dunno, sdk type?
99 wbe16(sce_hdr
+ 0x0a, 3); // SCE header type; pkg
100 wbe32(sce_hdr
+ 0x0c, 0); // meta offset
101 wbe64(sce_hdr
+ 0x10, sizeof sce_hdr
+ sizeof meta_hdr
);
102 wbe64(sce_hdr
+ 0x18, 0x80 + content_size_real
);
105 static void build_meta_hdr(void)
109 memset(meta_hdr
, 0, sizeof meta_hdr
);
112 // keys for metadata encryptiomn
114 get_rand(ptr
+ 0x20, 0x10);
117 // area covered by the signature
118 wbe64(ptr
+ 0x00, sizeof sce_hdr
+ sizeof meta_hdr
- 0x30);
119 wbe32(ptr
+ 0x0c, 3); // number of encrypted headers
120 wbe32(ptr
+ 0x10, 3 * 8); // number of keys/hashes required
124 wbe64(ptr
+ 0x00, 0x2c0); // offset
125 wbe64(ptr
+ 0x08, 0x40); // size
126 wbe32(ptr
+ 0x10, 1); // unknown
127 wbe32(ptr
+ 0x14, 1); // index
128 wbe32(ptr
+ 0x18, 2); // unknown again
129 wbe32(ptr
+ 0x1c, 0); // sha index
130 wbe32(ptr
+ 0x20, 1); // no encryption
131 wbe32(ptr
+ 0x24, 0xffffffff); // key index
132 wbe32(ptr
+ 0x28, 0xffffffff); // iv index
133 wbe32(ptr
+ 0x2c, 0x1); // no compression
136 // second info header
137 wbe64(ptr
+ 0x00, 0x300); // offset
138 wbe64(ptr
+ 0x08, 0x40); // size
139 wbe32(ptr
+ 0x10, 2); // unknown
140 wbe32(ptr
+ 0x14, 2); // index
141 wbe32(ptr
+ 0x18, 2); // unknown again
142 wbe32(ptr
+ 0x1c, 8); // sha index
143 wbe32(ptr
+ 0x20, 1); // no encryption
144 wbe32(ptr
+ 0x24, 0xffffffff); // key index
145 wbe32(ptr
+ 0x28, 0xffffffff); // iv index
146 wbe32(ptr
+ 0x2c, 0x1); // no compression
150 wbe64(ptr
+ 0x00, 0x340); // offset
151 wbe64(ptr
+ 0x08, content_size_compressed
);
152 wbe32(ptr
+ 0x10, 3); // unknown
153 wbe32(ptr
+ 0x14, 3); // index
154 wbe32(ptr
+ 0x18, 2); // unknown again
155 wbe32(ptr
+ 0x1c, 16); // sha index
156 wbe32(ptr
+ 0x20, 3); // encrypted
157 wbe32(ptr
+ 0x24, 22); // key index
158 wbe32(ptr
+ 0x28, 23); // iv index
159 wbe32(ptr
+ 0x2c, 2); // compressed
162 // add keys/ivs and hmac keys
163 get_rand(ptr
, 3 * 8 * 0x10);
166 static void fix_info_hdr(void)
168 wbe64(info0
+ 0x18, content_size_real
);
169 wbe64(info0
+ 0x20, content_size_compressed
);
170 wbe64(info1
+ 0x20, content_size_compressed
);
173 static void build_pkg(void)
175 pkg_size
= sizeof sce_hdr
+ sizeof meta_hdr
+ 0x80;
176 pkg_size
+= content_size_compressed
;
177 pkg_size
= round_up(pkg_size
, 0x100);
179 pkg
= malloc(pkg_size
);
181 fail("out of memory");
183 memset(pkg
, 0xaa, pkg_size
);
184 memcpy(pkg
, sce_hdr
, 0x20);
185 memcpy(pkg
+ 0x20, meta_hdr
, 0x2a0);
186 memcpy(pkg
+ 0x2c0, info0
, 0x40);
187 memcpy(pkg
+ 0x300, info1
, 0x40);
188 memcpy(pkg
+ 0x340, content
, content_size_compressed
);
191 static void calculate_hash(u8
*data
, u64 len
, u8
*digest
)
193 memset(digest
, 0, 0x20);
194 sha1_hmac(digest
+ 0x20, data
, len
, digest
);
197 static void hash_pkg(void)
199 calculate_hash(pkg
+ 0x2c0, 0x40, pkg
+ 0x80 + 3*0x30);
200 calculate_hash(pkg
+ 0x300, 0x40, pkg
+ 0x80 + 3*0x30 + 8*0x10);
201 calculate_hash(pkg
+ 0x340, content_size_compressed
,
202 pkg
+ 0x80 + 3*0x30 + 16*0x10);
205 static void sign_pkg(void)
211 sig_len
= be64(pkg
+ 0x60);
215 sha1(pkg
, sig_len
, hash
);
217 ecdsa_sign(hash
, r
, s
);
220 int main(int argc
, char *argv
[])
223 fail("usage: pkg [key suffix] [contents] [filename.pkg]");
225 fp
= fopen(argv
[3], "wb");
227 fail("fopen(%s) failed", argv
[3]);
229 if (chdir(argv
[2]) < 0)
233 get_file(info0
, "info0", 0x40);
234 get_file(info1
, "info1", 0x40);
245 sce_encrypt_data(pkg
);
246 sce_encrypt_header(pkg
, &k
);
248 fwrite(pkg
, pkg_size
, 1, fp
);