173 lines
5.5 KiB
C#
173 lines
5.5 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
using System.Security.Cryptography;
|
|||
|
using System.Text;
|
|||
|
|
|||
|
namespace PspCrypto
|
|||
|
{
|
|||
|
using PgdHeader = DNASStream.PgdHeader;
|
|||
|
using PgdDesc = DNASStream.PgdDesc;
|
|||
|
|
|||
|
public static class DNASHelper
|
|||
|
{
|
|||
|
public static int CalculateSize(int dataSize, int blockSize)
|
|||
|
{
|
|||
|
int alignSize = (dataSize + 15) & ~15;
|
|||
|
int tableSize = ((alignSize + blockSize - 1) & ~(blockSize - 1)) / (blockSize / 16);
|
|||
|
int pgdSize = 0x90 + alignSize + tableSize;
|
|||
|
return pgdSize;
|
|||
|
}
|
|||
|
|
|||
|
public static int Encrypt(Span<byte> pgdData, ReadOnlySpan<byte> data, ReadOnlySpan<byte> key, int dataSize, int keyIndex, int drmType, int flag = 2, int blockSize = 0x400)
|
|||
|
{
|
|||
|
// Additional size variables.
|
|||
|
var dataOffset = 0x90;
|
|||
|
var alignSize = (dataSize + 15) & ~15;
|
|||
|
var tableOffset = dataOffset + alignSize;
|
|||
|
var tableSize = ((alignSize + blockSize - 1) & ~(blockSize - 1)) / (blockSize / 16);
|
|||
|
var pgdSize = 0x90 + alignSize + tableSize;
|
|||
|
|
|||
|
if (pgdData.Length < pgdSize)
|
|||
|
{
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
data[..dataSize].CopyTo(pgdData[dataOffset..]);
|
|||
|
|
|||
|
ref var pgdHdr = ref MemoryMarshal.AsRef<PgdHeader>(pgdData);
|
|||
|
pgdHdr.Magic = 0x44475000;
|
|||
|
pgdHdr.KeyIndex = keyIndex;
|
|||
|
pgdHdr.DrmType = drmType;
|
|||
|
|
|||
|
// Select the hashing, crypto and open modes.
|
|||
|
int macType;
|
|||
|
int cipherType;
|
|||
|
var openFlag = flag;
|
|||
|
if (drmType == 1)
|
|||
|
{
|
|||
|
macType = 1;
|
|||
|
cipherType = 1;
|
|||
|
openFlag |= 4;
|
|||
|
if (keyIndex > 1)
|
|||
|
{
|
|||
|
macType = 3;
|
|||
|
openFlag |= 0xc;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
macType = 2;
|
|||
|
cipherType = 2;
|
|||
|
}
|
|||
|
|
|||
|
// Select the fixed DNAS key.
|
|||
|
|
|||
|
|
|||
|
byte[] dnasKey = null;
|
|||
|
|
|||
|
if ((openFlag & 2) != 0)
|
|||
|
{
|
|||
|
dnasKey = DNASStream.DnasKey1;
|
|||
|
}
|
|||
|
else if ((openFlag & 1) != 0)
|
|||
|
{
|
|||
|
dnasKey = DNASStream.DnasKey2;
|
|||
|
}
|
|||
|
|
|||
|
if (dnasKey == null)
|
|||
|
{
|
|||
|
throw new Exception();
|
|||
|
}
|
|||
|
|
|||
|
// Set the decryption parameters in the decrypted header.
|
|||
|
ref var pgdDesc = ref MemoryMarshal.AsRef<PgdDesc>(pgdHdr.PgdDesc);
|
|||
|
pgdDesc.DataSize = dataSize;
|
|||
|
pgdDesc.BlockSize = blockSize;
|
|||
|
pgdDesc.DataOffset = dataOffset;
|
|||
|
|
|||
|
// Generate random header and data keys.
|
|||
|
RandomNumberGenerator.Fill(pgdData.Slice(0x10, 0x30));
|
|||
|
|
|||
|
// Encrypt the data.
|
|||
|
DNASStream.DoBBCipher(pgdData[dataOffset..], alignSize, 0, key, pgdDesc.Key, cipherType);
|
|||
|
|
|||
|
// Build data MAC hash.
|
|||
|
var tableNum = tableSize / 16;
|
|||
|
for (int i = 0; i < tableNum; i++)
|
|||
|
{
|
|||
|
int rsize = alignSize - i * blockSize;
|
|||
|
if (rsize > blockSize)
|
|||
|
rsize = blockSize;
|
|||
|
if (keyIndex < 3)
|
|||
|
{
|
|||
|
BuildBBMac(pgdData[(dataOffset + i * blockSize)..], rsize, key,
|
|||
|
pgdData[(tableOffset + i * 16)..],
|
|||
|
macType);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
BuildBBMac(pgdData[(dataOffset + i * blockSize)..], rsize, key,
|
|||
|
pgdData[(tableOffset + i * 16)..],
|
|||
|
macType);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Build table MAC hash.
|
|||
|
BuildBBMac(pgdData.Slice(tableOffset), tableSize, key, pgdHdr.MacTableHash, macType);
|
|||
|
|
|||
|
// Encrypt the PGD header block (0x30 bytes).
|
|||
|
DNASStream.DoBBCipher(pgdHdr.PgdDesc, 0x30, 0, key, pgdHdr.DescKey, cipherType);
|
|||
|
|
|||
|
// Build MAC hash at 0x70 (key hash).
|
|||
|
BuildBBMac(pgdData, 0x70, key, pgdHdr.Hash70, macType);
|
|||
|
|
|||
|
// Build MAC hash at 0x80 (DNAS hash).
|
|||
|
BuildBBMac(pgdData, 0x80, dnasKey, pgdHdr.Hash80, macType);
|
|||
|
|
|||
|
return pgdSize;
|
|||
|
}
|
|||
|
|
|||
|
static int BuildBBMac(ReadOnlySpan<byte> data, int size, ReadOnlySpan<byte> key, Span<byte> hash, int macType, int seed = 0)
|
|||
|
{
|
|||
|
Span<byte> mkey = stackalloc byte[Marshal.SizeOf<AMCTRL.MAC_KEY>()];
|
|||
|
Span<byte> tmpKey = stackalloc byte[0x10];
|
|||
|
int ret = unchecked((int)0x80510201);
|
|||
|
if (hash != null)
|
|||
|
{
|
|||
|
ret = AMCTRL.sceDrmBBMacInit(mkey, macType);
|
|||
|
if (ret != 0)
|
|||
|
{
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, size);
|
|||
|
if (ret != 0)
|
|||
|
{
|
|||
|
return ret;
|
|||
|
}
|
|||
|
key.CopyTo(tmpKey);
|
|||
|
if (seed != 0)
|
|||
|
{
|
|||
|
var tmpXor = MemoryMarshal.Cast<byte, int>(tmpKey);
|
|||
|
tmpXor[0] ^= seed;
|
|||
|
}
|
|||
|
|
|||
|
ret = AMCTRL.sceDrmBBMacFinal(mkey, hash, tmpKey);
|
|||
|
if (ret != 0)
|
|||
|
{
|
|||
|
ret = unchecked((int)0x80510207);
|
|||
|
}
|
|||
|
|
|||
|
if (macType == 3)
|
|||
|
{
|
|||
|
Utils.BuildDrmBBMacFinal2(hash);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|