Skip to content

Commit f8a659f

Browse files
author
plutoo
committed
Initial commit
0 parents  commit f8a659f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+6000
-0
lines changed

amiibo_crypto.c

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Amiibo crypto
2+
// -- plutoo 2015
3+
4+
#include <openssl/hmac.h>
5+
#include <openssl/sha.h>
6+
#include <openssl/aes.h>
7+
#include <string.h>
8+
9+
typedef unsigned long long int u64;
10+
typedef unsigned int uint;
11+
typedef unsigned char u8;
12+
13+
#define DEBUG_KEYS
14+
15+
u8 random_key[16] = {
16+
0xC1, /* Censored. */
17+
};
18+
19+
u8 random_iv[16] = {
20+
0x4F, /* Censored. */
21+
};
22+
23+
u8 amiibo_constant0[14] = {
24+
#ifdef DEBUG_KEYS
25+
0xDB, /* Censored. */
26+
#else
27+
0x52, /* Censored. */
28+
#endif
29+
};
30+
31+
u8 amiibo_constant1[16] = {
32+
#ifdef DEBUG_KEYS
33+
0xFD, /* Censored. */
34+
#else
35+
0x4C, /* Censored. */
36+
#endif
37+
};
38+
39+
u8 hmac_key0[16] = {
40+
#ifdef DEBUG_KEYS
41+
0x1D, /* Censored. */
42+
#else
43+
0xED, /* Censored. */
44+
#endif
45+
};
46+
47+
u8 hmac_key1[16] = {
48+
#ifdef DEBUG_KEYS
49+
0x7F, /* Censored. */
50+
#else
51+
0x83, /* Censored. */
52+
#endif
53+
};
54+
55+
u8 type_string0[] = "unfixed infos\x00";
56+
u8 type_string1[] = "locked secret\x00";
57+
58+
59+
void sha256_hmac(u8* key, uint keylen, u8* in, uint inlen, u8* out) {
60+
HMAC_CTX ctx, *c=&ctx;
61+
uint outlen = 0x20;
62+
HMAC_CTX_init(c);
63+
HMAC_Init(c, key, keylen, EVP_sha256());
64+
HMAC_Update(c, in, inlen);
65+
HMAC_Final(c, out, &outlen);
66+
HMAC_CTX_cleanup(c);
67+
}
68+
69+
void sha256(u8* in, uint inlen, u8* out) {
70+
SHA256_CTX ctx;
71+
SHA256_Init(&ctx);
72+
SHA256_Update(&ctx, in, inlen);
73+
SHA256_Final(out, &ctx);
74+
}
75+
76+
void aes128(u8* key, u8* in, u8* out) {
77+
u8 iv[16];
78+
AES_KEY aes_key;
79+
memset(iv, 0, 16);
80+
AES_set_encrypt_key(key, 128, &aes_key);
81+
AES_cbc_encrypt(in, out, 16, &aes_key, iv, AES_ENCRYPT);
82+
}
83+
84+
void aes128_ctr(u8* key, u8* iv, u8* in_out, uint len) {
85+
u8 buf[16], out[16];
86+
memcpy(buf, iv, 16);
87+
88+
uint i;
89+
for(i=0; i<len/16; i++) {
90+
aes128(key, buf, out);
91+
92+
uint j;
93+
for(j=0; j<16; j++)
94+
in_out[i*16 + j] ^= out[j];
95+
96+
for(j=0; j<16; j++) {
97+
uint old = buf[15-j] + 1;
98+
buf[15-j] = old;
99+
if(old < 0x100)
100+
break;
101+
}
102+
}
103+
}
104+
105+
void amiibo_hmac_scramble(u8* hmac_key, u8* type_str/*len=0xE*/, u8* seeds/*len=0x40*/, u8* out) {
106+
u8 data[0x50];
107+
memcpy(data+2, type_str, 14);
108+
memcpy(data+2+14, seeds, 0x40);
109+
data[0] = 0; data[1] = 0;
110+
sha256_hmac(hmac_key, 0x10, data, 0x50, out);
111+
data[0] = 0; data[1] = 1;
112+
sha256_hmac(hmac_key, 0x10, data, 0x50, out+0x20);
113+
}
114+
115+
void generate_seeds1(int type, u8* seed1/*len=0x10 or 8*/, u8* randomseed, u8* out/*len=0x40*/) {
116+
memcpy(out, amiibo_constant1, 16);
117+
if(type == 0)
118+
memcpy(out+16, seed1, 16);
119+
else {
120+
memcpy(out+16, seed1, 8);
121+
memcpy(out+16+8, seed1, 8);
122+
}
123+
memcpy(out+32, randomseed, 32);
124+
}
125+
126+
void generate_seeds0(int type, u8* seed0/*len=2*/, u8* seed1, u8* randomseed, u8* out/*len=0x40*/) {
127+
memcpy(out, seed0, 2);
128+
memcpy(out+2, amiibo_constant0, 14);
129+
if(type == 0)
130+
memcpy(out+16, seed1, 16);
131+
else {
132+
memcpy(out+16, seed1, 8);
133+
memcpy(out+16+8, seed1, 8);
134+
}
135+
memcpy(out+32, randomseed, 32);
136+
}
137+
138+
void hexdump(u8* a, uint len) {
139+
uint i;
140+
for(i=0; i<len; i++) {
141+
printf("%02x", a[i]);
142+
if(((i+1) % 16) == 0)
143+
printf("\n");
144+
}
145+
}
146+
147+
void encrypt_zeroes(u8* key, u8* iv) {
148+
u8 out[16];
149+
memset(out, 0, 0x10);
150+
aes128_ctr(key, iv, out, 16);
151+
hexdump(out, 0x10);
152+
}
153+
154+
int main() {
155+
u8 randomseed[0x20];
156+
u8 seed0[2];
157+
u8 seed1[0x10]; // For type2, this is 8-bytes.
158+
159+
memset(randomseed, 0, 0x20);
160+
memset(seed0, 0, 2);
161+
memset(seed1, 0, 0x10);
162+
163+
#define TYPE 2
164+
aes128_ctr(random_key, random_iv, randomseed, 0x20);
165+
//hexdump(randomseed, 0x20);
166+
167+
u8 seeds[0x40];
168+
u8 hmac[0x20];
169+
generate_seeds0(TYPE, seed0, seed1, randomseed, seeds);
170+
amiibo_hmac_scramble(hmac_key0, type_string0, seeds, hmac);
171+
172+
printf("Per-key0: ");
173+
hexdump(hmac, 0x10);
174+
printf("Per-iv0: ");
175+
hexdump(hmac+0x10, 0x10);
176+
printf("(Zeroes:) ");
177+
encrypt_zeroes(hmac, hmac+0x10);
178+
printf("Per-hmac-key0: ");
179+
hexdump(hmac+0x20, 0x10);
180+
181+
generate_seeds1(TYPE, seed1, randomseed, seeds);
182+
amiibo_hmac_scramble(hmac_key1, type_string1, seeds, hmac);
183+
184+
printf("Per-key1: ");
185+
hexdump(hmac, 0x10);
186+
printf("Per-iv1: ");
187+
hexdump(hmac+0x10, 0x10);
188+
printf("(Zeroes:) ");
189+
encrypt_zeroes(hmac, hmac+0x10);
190+
printf("Per-hmac-key1: ");
191+
hexdump(hmac+0x20, 0x10);
192+
193+
return 0;
194+
}
195+
196+
// __ Keychunk: __
197+
// type_str = "unfixed infos" (flag != 0)
198+
// type_str = "locked secret" (flag == 0)
199+
// offset 0x0E size 0x0E (amiibo_constant flag != 0)
200+
// offset 0x1C size 0x10 (hmac-key flag != 0)
201+
// offset 0x3A size 0x10 (amiibo_constant flag == 0)
202+
// offset 0x4A size 0x10 (hmac-key flag == 0)

common.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import urllib
2+
import sys
3+
import os
4+
import struct
5+
from Crypto.Cipher import AES
6+
import hashlib
7+
8+
def be32(s):
9+
return struct.unpack('>I', s)[0]
10+
def be16(s):
11+
return struct.unpack('>H', s)[0]
12+
13+
def get_key(name):
14+
try:
15+
return open(os.environ['WIIU']+'/keys/'+name,'rb').read()
16+
except:
17+
print 'Key \'%s\' not found..' % name
18+
print 'You need to set WIIU environment variable.'
19+
sys.exit(1)
20+
21+
def aes_cbc_dec_file(inf, outf, key, iv, offset=0):
22+
in_file = open(inf, 'rb')
23+
out_file = open(outf, 'wb')
24+
25+
in_file.seek(offset)
26+
27+
while True:
28+
cipher = AES.new(key, AES.MODE_CBC, iv)
29+
30+
enc = in_file.read(16)
31+
if len(enc) == 0:
32+
break
33+
if len(enc) < 16:
34+
break
35+
36+
dec = cipher.decrypt(enc)
37+
out_file.write(dec)
38+
39+
iv = enc
40+
41+
in_file.close()
42+
out_file.close()
43+
44+
def aes_cbc_dec(inb, key, iv='\x00'*16):
45+
return AES.new(key, AES.MODE_CBC, iv).decrypt(inb)
46+
47+
def aes_cbc_enc(inb, key, iv='\x00'*16):
48+
return AES.new(key, AES.MODE_CBC, iv).encrypt(inb)
49+
50+
def sha1(buf):
51+
m = hashlib.sha1()
52+
m.update(buf)
53+
return m.digest()

dec_ancast.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/python2
2+
# dec_ancast.py -- Decrypt Wii U ancast images
3+
# plutoo, nwert
4+
5+
import sys
6+
import struct
7+
from common import *
8+
import hashlib
9+
10+
def rsa_verify(sig, hdr, N):
11+
e = 0x10001
12+
sig = int(sig.encode("hex"), 16)
13+
p = "{0:X}".format(pow(sig, rsa_e, N))
14+
p = ("0" if len(p)%2 else "") + p
15+
p = p.decode("hex")
16+
return p[0xEB:] == hashlib.sha1(hdr).digest()
17+
18+
if len(sys.argv) != 2:
19+
print '%s file.img' % sys.argv[0]
20+
sys.exit(1)
21+
22+
in_file = sys.argv[1]
23+
out_file = in_file + '.bin'
24+
25+
header = open(in_file, 'rb').read(0x200)
26+
27+
magic = be32(header[0:4])
28+
if magic != 0xEFA282D9:
29+
print 'Bad magic!'
30+
sys.exit(1)
31+
32+
sig_type = be32(header[0x20:0x24])
33+
34+
if sig_type == 1:
35+
offset = 0x100
36+
elif sig_type == 2:
37+
offset = 0x200
38+
else:
39+
print 'Unknown signature type %x..' % sig_type
40+
sys.exit(1)
41+
42+
types = {0x11: 'ppc_wiiu', 0x13: 'ppc_vwii', 0x21: 'arm'}
43+
type_raw = be32(header[offset-0x5C:offset-0x58])
44+
45+
if type_raw not in types:
46+
print 'Unknown type %x..' % type
47+
sys.exit(1)
48+
49+
type = types[type_raw]
50+
if type == 'arm':
51+
if be32(header[offset-0x54:offset-0x50]) in [0xE000, 0xC000]:
52+
type += '_boot1'
53+
else:
54+
type += '_iosu'
55+
56+
btypes = {1: 'debug', 2: 'retail'}
57+
btype_raw = be32(header[offset-0x58:offset-0x54])
58+
type += '_'+btypes[btype_raw]
59+
60+
print 'Type:', type
61+
62+
#print "Signature verified:", rsa_verify(header[0x24:0x124], header[0x1A0:0x200], Ns[btype])
63+
64+
key = get_key('ancast_%s_key' % type)
65+
iv = get_key('ancast_%s_iv' % type)
66+
67+
aes_cbc_dec_file(in_file, out_file, key, iv, offset)
68+
69+
out = open(out_file, 'rb').read()
70+
elf_pos = out.find('\x7FELF')
71+
72+
if elf_pos != -1:
73+
elf_file = in_file + '.elf'
74+
elf = open(elf_file, 'wb')
75+
elf.write(out[elf_pos:])

0 commit comments

Comments
 (0)