chovy-sign/PspCrypto/AMCTRL.cs

711 lines
20 KiB
C#

using System;
using System.Runtime.InteropServices;
namespace PspCrypto
{
public class AMCTRL
{
static readonly Memory<byte> kirk_buf = new byte[0x0814];
static readonly Memory<byte> kirk_buf2 = new byte[0x8014];
// AMCTRL keys.
static readonly byte[] amctrl_key1 = { 0xE3, 0x50, 0xED, 0x1D, 0x91, 0x0A, 0x1F, 0xD0, 0x29, 0xBB, 0x1C, 0x3E, 0xF3, 0x40, 0x77, 0xFB };
static readonly byte[] amctrl_key2 = { 0x13, 0x5F, 0xA4, 0x7C, 0xAB, 0x39, 0x5B, 0xA4, 0x76, 0xB8, 0xCC, 0xA9, 0x8F, 0x3A, 0x04, 0x45 };
static readonly byte[] amctrl_key3 = { 0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E };
public unsafe struct MAC_KEY
{
public int type;
private fixed byte _key[16];
public Span<byte> key
{
get
{
fixed (byte* ptr = _key)
{
return new Span<byte>(ptr, 16);
}
}
}
private fixed byte _pad[16];
public Span<byte> pad
{
get
{
fixed (byte* ptr = _pad)
{
return new Span<byte>(ptr, 16);
}
}
}
public int pad_size;
}
public unsafe struct CIPHER_KEY
{
public int type;
public int seed;
fixed byte _key[16];
public Span<byte> key
{
get
{
fixed (byte* ptr = _key)
{
return new Span<byte>(ptr, 16);
}
}
}
}
/*
* KIRK wrapper functions.
*/
static int Kirk4(Span<byte> buf, int size, int type)
{
int retv;
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
hdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;
hdr.keyseed = type;
hdr.data_size = size;
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_ENCRYPT_IV_0);
if (retv != 0)
return -2142174447; // 0x80510311;
return 0;
}
static int Kirk5(Span<byte> buf, int size)
{
int retv;
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
hdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;
hdr.keyseed = 0x0100;
hdr.data_size = size;
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_ENCRYPT_IV_FUSE);
if (retv != 0)
return -2142174446; // 0x80510312;
return 0;
}
static int Kirk7(Span<byte> buf, int size, int type)
{
int retv;
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC;
hdr.keyseed = type;
hdr.data_size = size;
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_DECRYPT_IV_0);
if (retv != 0)
return -2142174447; // 0x80510311;
return 0;
}
static int Kirk8(Span<byte> buf, int size)
{
int retv;
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC;
hdr.keyseed = 0x0100;
hdr.data_size = size;
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_DECRYPT_IV_FUSE);
if (retv != 0)
return -2142174446; // 0x80510312;
return 0;
}
static int Kirk14(Span<byte> buf)
{
int retv;
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, 0x14, null, 0, KIRKEngine.KIRK_CMD_PRNG);
if (retv != 0)
return -2142174443; // 0x80510315;
return 0;
}
static int encrypt_buf(Span<byte> buf, int size, Span<byte> key, int key_type)
{
int i, retv;
for (i = 0; i < 16; i++)
{
buf[0x14 + i] ^= key[i];
}
unsafe
{
fixed (byte* ptr = buf)
{
}
}
retv = Kirk4(buf, size, key_type);
if (retv != 0)
return retv;
buf.Slice(size + 4, 16).CopyTo(key);
return 0;
}
static int decrypt_buf(Span<byte> buf, int size, Span<byte> key, int key_type)
{
int i, retv;
Span<byte> tmp = stackalloc byte[16];
buf.Slice(size + 0x14 - 16, 16).CopyTo(tmp);
retv = Kirk7(buf, size, key_type);
if (retv != 0)
return retv;
for (i = 0; i < 16; i++)
{
buf[i] ^= key[i];
}
tmp.CopyTo(key);
return 0;
}
static int cipher_buf(Span<byte> kbuf, Span<byte> dbuf, int size, ref CIPHER_KEY ckey)
{
int i, retv;
Span<byte> tmp1 = stackalloc byte[16], tmp2 = stackalloc byte[16];
ckey.key.CopyTo(kbuf[0x14..]);
for (i = 0; i < 16; i++)
{
kbuf[0x14 + i] ^= amctrl_key3[i];
}
if (ckey.type == 2)
retv = Kirk8(kbuf, 16);
else
retv = Kirk7(kbuf, 16, 0x39);
if (retv != 0)
return retv;
for (i = 0; i < 16; i++)
{
kbuf[i] ^= amctrl_key2[i];
}
kbuf.Slice(0, 0x10).CopyTo(tmp2);
if (ckey.seed == 1)
{
tmp1.Fill(0);
}
else
{
tmp2.CopyTo(tmp1);
var tmp = ckey.seed - 1;
MemoryMarshal.Write(tmp1[0x0c..], ref tmp);
}
for (i = 0; i < size; i += 16)
{
tmp2[..12].CopyTo(kbuf[(0x14 + i)..]);
MemoryMarshal.Write(kbuf[(0x14 + i + 12)..], ref ckey.seed);
ckey.seed += 1;
}
retv = decrypt_buf(kbuf, size, tmp1, 0x63);
if (retv != 0)
return retv;
for (i = 0; i < size; i++)
{
dbuf[i] ^= kbuf[i];
}
return 0;
}
public static int sceDrmBBMacInit(Span<byte> mkey, int type)
{
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
macKey.type = type;
macKey.key.Clear();
macKey.pad.Clear();
return 0;
}
public static int sceDrmBBMacUpdate(Span<byte> mkey, ReadOnlySpan<byte> buf, int size)
{
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
int retv = 0, ksize, p, type;
int kbuf;
if (macKey.pad_size > 16)
{
retv = -2142174462; // 0x80510302
return retv;
}
if (macKey.pad_size + size <= 16)
{
buf[..size].CopyTo(macKey.pad[macKey.pad_size..]);
macKey.pad_size += size;
retv = 0;
}
else
{
kbuf = 0x14;
macKey.pad[..macKey.pad_size].CopyTo(kirk_buf[0x14..].Span);
p = macKey.pad_size;
macKey.pad_size += size;
macKey.pad_size &= 0x0f;
if (macKey.pad_size == 0)
macKey.pad_size = 16;
size -= macKey.pad_size;
buf.Slice(size, macKey.pad_size).CopyTo(macKey.pad);
type = (macKey.type == 2) ? 0x3A : 0x38;
int offset = 0;
while (size > 0)
{
ksize = (size + p >= 0x0800) ? 0x0800 : size + p;
buf.Slice(offset, ksize - p).CopyTo(kirk_buf[(kbuf + p)..].Span);
retv = encrypt_buf(kirk_buf.Span, ksize, macKey.key, type);
if (retv != 0)
return retv;
size -= (ksize - p);
offset += ksize - p;
p = 0;
}
}
return retv;
}
public static int sceDrmBBMacUpdate2(Span<byte> mkey, Span<byte> buf, int size)
{
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
int retv = 0, ksize, p, type;
int kbuf;
if (macKey.pad_size > 16)
{
retv = -2142174462; // 0x80510302
return retv;
}
if (macKey.pad_size + size <= 16)
{
buf.Slice(0, size).CopyTo(macKey.pad.Slice(macKey.pad_size));
macKey.pad_size += size;
retv = 0;
}
else
{
kbuf = 0x14;
macKey.pad.Slice(0, macKey.pad_size).CopyTo(kirk_buf.Slice(0x14).Span);
p = macKey.pad_size;
macKey.pad_size += (size & 0x0f);
//mkey.pad_size &= 0x0f;
if (macKey.pad_size == 0)
macKey.pad_size = 16;
size -= macKey.pad_size;
buf.Slice(size, macKey.pad_size).CopyTo(macKey.pad);
type = (macKey.type == 2) ? 0x3A : 0x38;
int idx = 0;
ksize = size + p;
int offset = 0;
if (size + p >= 0x8001)
{
;
buf.Slice(offset, 0x8000 - p).CopyTo(kirk_buf2.Slice(kbuf + p).Span);
retv = encrypt_buf(kirk_buf2.Span, 0x8000, macKey.key, type);
idx = 0x8000 - p;
var fix = -p;
while (retv == 0)
{
if (size <= 0x10000 - fix)
{
p = 0;
ksize = size;
break;
}
buf.Slice(offset + idx, 0x8000).CopyTo(kirk_buf2.Slice(kbuf).Span);
retv = encrypt_buf(kirk_buf2.Span, 0x8000, macKey.key, type);
fix = idx;
idx += 0x8000;
}
if (retv != 0)
{
return retv;
}
}
buf.Slice(offset + idx, size - idx).CopyTo(kirk_buf2.Slice(kbuf + p).Span);
retv = encrypt_buf(kirk_buf2.Span, ksize - idx, macKey.key, type);
}
return retv;
}
public static int sceDrmBBMacFinal(Span<byte> mkey, Span<byte> buf, ReadOnlySpan<byte> vkey)
{
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
int i, retv, code;
Span<byte> tmp = stackalloc byte[16], tmp1 = stackalloc byte[16];
int kbuf;
uint t0, v0, v1;
if (macKey.pad_size > 16)
return -2142174462; //0x80510302;
code = (macKey.type == 2) ? 0x3A : 0x38;
kbuf = 0x14;
kirk_buf.Slice(kbuf, 16).Span.Fill(0);
retv = Kirk4(kirk_buf.Span, 16, code);
if (retv != 0)
{
return retv;
}
kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp);
t0 = ((tmp[0] & 0x80) > 0) ? 0x87u : 0;
for (i = 0; i < 15; i++)
{
v1 = tmp[i + 0];
v0 = tmp[i + 1];
v1 <<= 1;
v0 >>= 7;
v0 |= v1;
tmp[i + 0] = (byte)v0;
}
v0 = tmp[15];
v0 <<= 1;
v0 ^= t0;
tmp[15] = (byte)v0;
if (macKey.pad_size < 16)
{
t0 = ((tmp[0] & 0x80) > 0) ? 0x87u : 0;
for (i = 0; i < 15; i++)
{
v1 = tmp[i + 0];
v0 = tmp[i + 1];
v1 <<= 1;
v0 >>= 7;
v0 |= v1;
tmp[i + 0] = (byte)v0;
}
v0 = tmp[15];
v0 <<= 1;
v0 ^= t0;
tmp[15] = (byte)v0;
macKey.pad[macKey.pad_size] = 0x80;
if (macKey.pad_size + 1 < 16)
{
macKey.pad.Slice(macKey.pad_size + 1, 16 - macKey.pad_size - 1).Fill(0);
}
}
for (i = 0; i < 16; i++)
{
macKey.pad[i] ^= tmp[i];
}
macKey.pad.CopyTo(kirk_buf.Slice(kbuf).Span);
macKey.key.CopyTo(tmp1);
retv = encrypt_buf(kirk_buf.Span, 0x10, tmp1, code);
if (retv != 0)
return retv;
for (i = 0; i < 0x10; i++)
{
tmp1[i] ^= amctrl_key1[i];
}
if (macKey.type == 2)
{
tmp1.CopyTo(kirk_buf.Slice(kbuf).Span);
retv = Kirk5(kirk_buf.Span, 0x10);
if (retv != 0)
return retv;
retv = Kirk4(kirk_buf.Span, 0x10, code);
if (retv != 0)
return retv;
kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp1);
}
if (vkey != null)
{
for (i = 0; i < 0x10; i++)
{
tmp1[i] ^= vkey[i];
}
tmp1.CopyTo(kirk_buf.Slice(kbuf).Span);
retv = Kirk4(kirk_buf.Span, 0x10, code);
if (retv != 0)
return retv;
kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp1);
}
tmp1.CopyTo(buf);
macKey.key.Fill(0);
macKey.pad.Fill(0);
macKey.pad_size = 0;
macKey.type = 0;
retv = 0;
return retv;
}
public static int bbmac_getkey(Span<byte> mkey, ReadOnlySpan<byte> bbmac, Span<byte> vkey)
{
int i, retv, type, code;
Span<byte> tmp = stackalloc byte[16], tmp1 = stackalloc byte[16];
int kbuf;
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
type = macKey.type;
retv = sceDrmBBMacFinal(mkey, tmp, null);
if (retv != 0)
return retv;
kbuf = 0x14;
if (type == 3)
{
bbmac[..0x10].CopyTo(kirk_buf[kbuf..].Span);
Kirk7(kirk_buf.Span, 0x10, 0x63);
}
else
{
bbmac[..0x10].CopyTo(kirk_buf.Span);
}
kirk_buf[..16].Span.CopyTo(tmp1);
tmp1.CopyTo(kirk_buf[kbuf..].Span);
code = (type == 2) ? 0x3A : 0x38;
Kirk7(kirk_buf.Span, 0x10, code);
for (i = 0; i < 0x10; i++)
{
vkey[i] = (byte)(tmp[i] ^ kirk_buf.Span[i]);
}
return 0;
}
public static int sceDrmBBMacFinal2(Span<byte> mkey, ReadOnlySpan<byte> hash, ReadOnlySpan<byte> vkey)
{
int retv, type;
byte[] tmp = new byte[16];
int kbuf;
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
type = macKey.type;
retv = sceDrmBBMacFinal(mkey, tmp, vkey);
if (retv != 0)
return retv;
kbuf = 0x14;
if (type == 3)
{
hash[..0x10].CopyTo(kirk_buf[kbuf..].Span);
Kirk7(kirk_buf.Span, 0x10, 0x63);
}
else
{
hash[..0x10].CopyTo(kirk_buf.Span);
}
retv = 0;
if (!kirk_buf.Span[..0x10].SequenceEqual(tmp))
{
retv = -2142174464; //0x80510300;
}
//for (i = 0; i < 0x10; i++)
//{
// if (kirk_buf.Span[i] != tmp[i])
// {
// retv = -2142174464; //0x80510300;
// break;
// }
//}
return retv;
}
/*
BBCipher functions.
*/
public static int sceDrmBBCipherInit(out CIPHER_KEY ckey, int type, int mode, ReadOnlySpan<byte> header_key, ReadOnlySpan<byte> version_key, int seed)
{
int i, retv;
int kbuf;
kbuf = 0x14;
ckey = new CIPHER_KEY { type = type };
if (mode == 2)
{
ckey.seed = seed + 1;
for (i = 0; i < 16; i++)
{
ckey.key[i] = header_key[i];
}
if (version_key != null)
{
for (i = 0; i < 16; i++)
{
ckey.key[i] ^= version_key[i];
}
}
retv = 0;
}
else if (mode == 1)
{
ckey.seed = 1;
retv = Kirk14(kirk_buf.Span);
if (retv != 0)
return retv;
kirk_buf.Slice(0, 0x10).CopyTo(kirk_buf.Slice(kbuf));
kirk_buf.Slice(kbuf + 0xC, 4).Span.Fill(0);
if (ckey.type == 2)
{
for (i = 0; i < 16; i++)
{
kirk_buf.Span[i + kbuf] ^= amctrl_key2[i];
}
retv = Kirk5(kirk_buf.Span, 0x10);
for (i = 0; i < 16; i++)
{
kirk_buf.Span[i + kbuf] ^= amctrl_key3[i];
}
}
else
{
for (i = 0; i < 16; i++)
{
kirk_buf.Span[i + kbuf] ^= amctrl_key2[i];
}
retv = Kirk4(kirk_buf.Span, 0x10, 0x39);
for (i = 0; i < 16; i++)
{
kirk_buf.Span[i + kbuf] ^= amctrl_key3[i];
}
}
if (retv != 0)
return retv;
kirk_buf.Slice(kbuf, 0x10).Span.CopyTo(ckey.key);
// kirk_buf.Slice(kbuf, 0x10).Span.CopyTo(header_key);
if (version_key != null)
{
for (i = 0; i < 16; i++)
{
ckey.key[i] ^= version_key[i];
}
}
}
else
{
retv = 0;
}
return retv;
}
public static int sceDrmBBCipherUpdate(ref CIPHER_KEY ckey, Span<byte> data, int size)
{
int p, retv, dsize;
retv = 0;
p = 0;
while (size > 0)
{
dsize = (size >= 0x0800) ? 0x0800 : size;
retv = cipher_buf(kirk_buf.Span, data.Slice(p), dsize, ref ckey);
if (retv != 0)
break;
size -= dsize;
p += dsize;
}
return retv;
}
public static int sceDrmBBCipherFinal(ref CIPHER_KEY ckey)
{
ckey.key.Fill(0);
ckey.type = 0;
ckey.seed = 0;
return 0;
}
}
}