Add NpUmdImg

This commit is contained in:
Li 2023-04-16 05:22:43 +12:00
parent 7b6830a40b
commit 562016688a
22 changed files with 607 additions and 162 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
.vs/*
*.7z
*thumbs.db
PbpResign/bin/*
PbpResign/obj/*

View File

@ -533,11 +533,11 @@ namespace PbpResign
Span<byte> table = new byte[tablesize];
var tp = MemoryMarshal.Cast<byte, uint>(table);
input.Read(table);
// Decrypt Table
for (int i = 0; i < totalBlocks; i++)
{
XorTable(tp[(i * 8)..]);
}
var blocks = MemoryMarshal.Cast<byte, NpBlock>(table);
for (int i = 0; i < blocks.Length; i++)
@ -578,9 +578,7 @@ namespace PbpResign
// Encrypt Table
for (int i = 0; i < totalBlocks; i++)
{
XorTable(tp[(i * 8)..]);
}
output.Seek(entityOff, SeekOrigin.Begin);
output.Write(table);
@ -1073,6 +1071,17 @@ namespace PbpResign
return false;
}
type = 0;
Console.WriteLine("VersionKey: " + BitConverter.ToString(NewVersionKey.ToArray()));
NpUmdImg npumd = new NpUmdImg(new NpDrmInfo(NewVersionKey.ToArray(), CId, npHdr.NpFlags),
"fft.iso", "ULUS10297", File.ReadAllBytes("TEST\\PARAM.SFO"), false);
npumd.CreatePsar();
byte[] paramFile = File.ReadAllBytes("TEST\\PARAM.SFO");
PbpBuilder.CreatePbp(paramFile, File.ReadAllBytes("TEST\\ICON0.PNG"), null, File.ReadAllBytes("TEST\\PIC0.PNG"), File.ReadAllBytes("TEST\\PIC1.PNG"), null, npumd, "FFT.PBP");
return CopyNpUmdImg(input, output, pbpHdr, psarBuff, npHdr);
}
@ -1086,7 +1095,7 @@ namespace PbpResign
return false;
}
type = 1;
DiscInfo[] discs = new DiscInfo[2];
/*DiscInfo[] discs = new DiscInfo[2];
discs[0] = new DiscInfo("ABEE\\D1.CUE", "Oddworld: Abe's Exoddus", "SLES01480");
discs[1] = new DiscInfo("ABEE\\D2.CUE", "Oddworld: Abe's Exoddus", "SLES11480");
PsTitleImg title = new PsTitleImg(NewVersionKey.ToArray(), CId, discs);
@ -1098,7 +1107,7 @@ namespace PbpResign
// File.ReadAllBytes("TEST\\PARAM.SFO"), File.ReadAllBytes("TEST\\ICON0.PNG"), null,
// File.ReadAllBytes("TEST\\PIC0.PNG"), File.ReadAllBytes("TEST\\PIC1.PNG"), null);
//File.WriteAllBytes("TEST.BIN", i.GetIsoHeader());
//File.WriteAllBytes("TEST.ISOc", i.GetIso());
//File.WriteAllBytes("TEST.ISOc", i.GetIso());*/
return CopyPsIsoImg(input, output, pbpHdr);

View File

@ -75,7 +75,7 @@ namespace PopsBuilder.Pops
int headerSize = DNASHelper.CalculateSize(isoHdr.Length, 0x400);
byte[] headerEnc = new byte[headerSize];
int sz = DNASHelper.Encrypt(headerEnc, isoHdr, srcImg.VersionKey, isoHdr.Length, 1, 1, blockSize: 0x400);
int sz = DNASHelper.Encrypt(headerEnc, isoHdr, srcImg.DrmInfo.VersionKey, isoHdr.Length, srcImg.DrmInfo.KeyType, 1, blockSize: 0x400);
byte[] isoHdrPgd = headerEnc.ToArray();
Array.Resize(ref isoHdrPgd, sz);
@ -155,7 +155,6 @@ namespace PopsBuilder.Pops
private void writeCompressedCDATracks()
{
Random rng = new Random();
IsoHeader.Seek(0x800, SeekOrigin.Begin); // CDA Entries
@ -168,7 +167,7 @@ namespace PopsBuilder.Pops
using (CueStream audioStream = cue.OpenTrack(i))
{
uint key = Convert.ToUInt32(rng.NextInt64(0, uint.MaxValue));
uint key = Rng.RandomUInt();
Atrac3ToolEncoder enc = new Atrac3ToolEncoder();
@ -202,7 +201,7 @@ namespace PopsBuilder.Pops
AMCTRL.sceDrmBBMacInit(mkey, 3);
AMCTRL.sceDrmBBMacUpdate(mkey, data, data.Length);
Span<byte> checksum = new byte[20 + 0x10];
AMCTRL.sceDrmBBMacFinal(mkey, checksum[20..], srcImg.VersionKey);
AMCTRL.sceDrmBBMacFinal(mkey, checksum[20..], srcImg.DrmInfo.VersionKey);
ref var aesHdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(checksum);
aesHdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;

View File

@ -12,27 +12,22 @@ namespace PopsBuilder.Pops
{
public class PopsImg : NpDrmPsar
{
public PopsImg(byte[] versionKey, string contentId) : base(versionKey, contentId)
public PopsImg(NpDrmInfo versionKey) : base(versionKey)
{
startDat = new MemoryStream();
startDatUtil = new StreamUtil(startDat);
simple = new MemoryStream();
simpleUtil = new StreamUtil(simple);
createStartDat();
StartDat = NpDrmPsar.CreateStartDat(Resources.STARTDATPOPS);
createSimpleDat();
SimplePgd = generateSimplePgd();
}
internal MemoryStream startDat;
internal StreamUtil startDatUtil;
private MemoryStream simple;
private StreamUtil simpleUtil;
public byte[] StartDat;
public byte[] SimplePgd;
internal Random rng = new Random();
private void createSimpleDat()
{
simpleUtil.WriteStr("SIMPLE ");
@ -45,20 +40,7 @@ namespace PopsBuilder.Pops
simpleUtil.WriteBytes(Resources.SIMPLE);
}
private void createStartDat()
{
startDatUtil.WriteStr("STARTDAT");
startDatUtil.WriteInt32(0x1);
startDatUtil.WriteInt32(0x1);
startDatUtil.WriteInt32(0x50);
startDatUtil.WriteInt32(Resources.STARTDAT.Length);
startDatUtil.WriteInt32(0x0);
startDatUtil.WriteInt32(0x0);
startDatUtil.WritePadding(0, 0x30);
startDatUtil.WriteBytes(Resources.STARTDAT);
}
private byte[] generateSimplePgd()
{
@ -69,7 +51,7 @@ namespace PopsBuilder.Pops
byte[] simpleEnc = new byte[simpleSz];
// get pgd
int sz = DNASHelper.Encrypt(simpleEnc, simpleData, VersionKey, simpleData.Length, 1, 1, blockSize: 0x400);
int sz = DNASHelper.Encrypt(simpleEnc, simpleData, DrmInfo.VersionKey, simpleData.Length, DrmInfo.KeyType, 1, blockSize: 0x400);
byte[] pgd = simpleEnc.ToArray();
Array.Resize(ref pgd, sz);
@ -77,7 +59,7 @@ namespace PopsBuilder.Pops
}
public byte[] GenerateDataPsp()
public override byte[] GenerateDataPsp()
{
Span<byte> loaderEnc = new byte[0x9B13];
@ -95,7 +77,7 @@ namespace PopsBuilder.Pops
Array.ConstrainedCopy(lowBits, 0, dataPspElf, 0x68C, 0x2);
Array.ConstrainedCopy(highBits, 0, dataPspElf, 0x694, 0x2);
SceMesgLed.Encrypt(loaderEnc, dataPspElf, 0x0DAA06F0, SceExecFileDecryptMode.DECRYPT_MODE_POPS_EXEC, VersionKey, ContentId, Resources.DATAPSPSDCFG);
SceMesgLed.Encrypt(loaderEnc, dataPspElf, 0x0DAA06F0, SceExecFileDecryptMode.DECRYPT_MODE_POPS_EXEC, DrmInfo.VersionKey, DrmInfo.ContentId, Resources.DATAPSPSDCFG);
return loaderEnc.ToArray();
}

View File

@ -1,6 +1,7 @@
using Org.BouncyCastle.Crypto.Paddings;
using PopsBuilder.Atrac3;
using PopsBuilder.Cue;
using PopsBuilder.Psp;
using PspCrypto;
using System;
using System.Net;
@ -11,24 +12,24 @@ namespace PopsBuilder.Pops
{
public class PsIsoImg : PopsImg
{
internal PsIsoImg(byte[] versionkey, string contentId, DiscCompressor discCompressor) : base(versionkey, contentId)
internal PsIsoImg(NpDrmInfo versionKey, DiscCompressor discCompressor) : base(versionKey)
{
this.compressor = discCompressor;
}
public PsIsoImg(byte[] versionkey, string contentId, DiscInfo disc, IAtracEncoderBase encoder) : base(versionkey, contentId)
public PsIsoImg(NpDrmInfo versionKey, DiscInfo disc, IAtracEncoderBase encoder) : base(versionKey)
{
this.compressor = new DiscCompressor(this, disc, encoder);
}
public PsIsoImg(byte[] versionkey, string contentId, DiscInfo disc) : base(versionkey, contentId)
public PsIsoImg(NpDrmInfo versionKey, DiscInfo disc) : base(versionKey)
{
this.compressor = new DiscCompressor(this, disc, new Atrac3ToolEncoder());
}
public void CreatePsar(bool isPartOfMultiDisc=false)
{
compressor.GenerateIsoHeaderAndCompress();
if (!isPartOfMultiDisc) compressor.WriteSimpleDatLocation((compressor.IsoOffset + compressor.CompressedIso.Length) + startDat.Length);
if (!isPartOfMultiDisc) compressor.WriteSimpleDatLocation((compressor.IsoOffset + compressor.CompressedIso.Length) + StartDat.Length);
psarUtil.WriteStr("PSISOIMG0000");
psarUtil.WriteInt64(0x00); // location of STARTDAT
@ -47,8 +48,7 @@ namespace PopsBuilder.Pops
// write STARTDAT
Int64 startDatLocation = Psar.Position;
startDat.Seek(0x00, SeekOrigin.Begin);
startDat.CopyTo(Psar);
psarUtil.WriteBytes(StartDat);
// write pgd
psarUtil.WriteBytes(this.SimplePgd);

View File

@ -1,4 +1,5 @@
using PopsBuilder.Atrac3;
using PopsBuilder.Psp;
using PspCrypto;
using System;
using System.Collections.Generic;
@ -13,7 +14,7 @@ namespace PopsBuilder.Pops
{
const int MAX_DISCS = 5;
const int PSISO_ALIGN = 0x8000;
public PsTitleImg(byte[] versionKey, string contentId, DiscInfo[] discs) : base(versionKey, contentId)
public PsTitleImg(NpDrmInfo drmInfo, DiscInfo[] discs) : base(drmInfo)
{
if (discs.Length > MAX_DISCS) throw new Exception("Sorry, multi disc games only support up to 5 discs... (i dont make the rules)");
this.compressors = new DiscCompressor[MAX_DISCS];
@ -42,7 +43,7 @@ namespace PopsBuilder.Pops
psarUtil.WriteStr("PSTITLEIMG000000");
psarUtil.WriteInt64(PSISO_ALIGN+isoPart.Length); // location of STARTDAT
psarUtil.WriteRandom(0x10); // dunno what this is
psarUtil.WriteBytes(Rng.RandomBytes(0x10)); // dunno what this is
psarUtil.WritePadding(0x00, 0x1D8);
byte[] isoMap = generateIsoMapPgd();
@ -52,8 +53,7 @@ namespace PopsBuilder.Pops
isoPart.Seek(0x00, SeekOrigin.Begin);
isoPart.CopyTo(Psar);
startDat.Seek(0x00, SeekOrigin.Begin);
startDat.CopyTo(Psar);
psarUtil.WriteBytes(StartDat);
psarUtil.WriteBytes(SimplePgd);
}
@ -66,7 +66,7 @@ namespace PopsBuilder.Pops
PspCrypto.AMCTRL.sceDrmBBMacInit(mkey, 3);
PspCrypto.AMCTRL.sceDrmBBMacUpdate(mkey, header, header.Length /*0xb3c80*/);
Span<byte> newKey = new byte[20 + 0x10];
PspCrypto.AMCTRL.sceDrmBBMacFinal(mkey, newKey[20..], VersionKey);
PspCrypto.AMCTRL.sceDrmBBMacFinal(mkey, newKey[20..], DrmInfo.VersionKey);
ref var aesHdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(newKey);
aesHdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;
aesHdr.keyseed = 0x63;
@ -86,7 +86,7 @@ namespace PopsBuilder.Pops
int encryptedSz = DNASHelper.CalculateSize(isoMapBuf.Length, 1024);
var isoMapEnc = new byte[encryptedSz];
DNASHelper.Encrypt(isoMapEnc, isoMapBuf, VersionKey, isoMapBuf.Length, 1, 1);
DNASHelper.Encrypt(isoMapEnc, isoMapBuf, DrmInfo.VersionKey, isoMapBuf.Length, DrmInfo.KeyType, 1);
return isoMapEnc;
}
@ -101,7 +101,7 @@ namespace PopsBuilder.Pops
int padLen = Convert.ToInt32(PSISO_ALIGN - (isoPart.Position % PSISO_ALIGN));
isoPartUtil.WritePadding(0x00, padLen);
using (PsIsoImg psIsoImg = new PsIsoImg(this.VersionKey, this.ContentId, compressors[i]))
using (PsIsoImg psIsoImg = new PsIsoImg(this.DrmInfo, compressors[i]))
{
isoMapUtil.WriteUInt32(Convert.ToUInt32(PSISO_ALIGN + isoPart.Position));
@ -127,8 +127,8 @@ namespace PopsBuilder.Pops
isoMapUtil.WriteBytes(checksums);
isoMapUtil.WriteStrWithPadding(discs.First().DiscIdHdr, 0x00, 0x20);
isoMapUtil.WriteInt64(Convert.ToInt64(PSISO_ALIGN + isoPart.Length + startDat.Length));
isoMapUtil.WriteRandom(0x80);
isoMapUtil.WriteInt64(Convert.ToInt64(PSISO_ALIGN + isoPart.Length + StartDat.Length));
psarUtil.WriteBytes(Rng.RandomBytes(0x80));
isoMapUtil.WriteStrWithPadding(discs.First().DiscName, 0x00, 0x80);
isoMapUtil.WriteInt32(MAX_DISCS);
isoMapUtil.WritePadding(0x00, 0x70);

View File

@ -20,7 +20,7 @@
<ItemGroup>
<EmbeddedResource Update="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PopsBuilder.Psp
{
public class NpDrmInfo
{
public string ContentId;
public byte[] VersionKey;
public int KeyType;
public NpDrmInfo(byte[] versionKey, string contentId, int keyType)
{
this.VersionKey = versionKey;
this.KeyType = keyType;
this.ContentId = contentId;
}
}
}

View File

@ -9,22 +9,43 @@ using System.Threading.Tasks;
namespace PopsBuilder.Psp
{
public class NpDrmPsar : IDisposable
public abstract class NpDrmPsar : IDisposable
{
public NpDrmPsar(byte[] versionKey, string contentId)
public NpDrmPsar(NpDrmInfo npDrmInfo)
{
VersionKey = versionKey;
ContentId = contentId;
DrmInfo = npDrmInfo;
Psar = new MemoryStream();
psarUtil = new StreamUtil(Psar);
}
public byte[] VersionKey;
public string ContentId;
public NpDrmInfo DrmInfo;
public MemoryStream Psar;
internal StreamUtil psarUtil;
public abstract byte[] GenerateDataPsp();
public static byte[] CreateStartDat(byte[] image)
{
using(MemoryStream startDatStream = new MemoryStream())
{
StreamUtil startDatUtil = new StreamUtil(startDatStream);
startDatUtil.WriteStr("STARTDAT");
startDatUtil.WriteInt32(0x1);
startDatUtil.WriteInt32(0x1);
startDatUtil.WriteInt32(0x50);
startDatUtil.WriteInt32(image.Length);
startDatUtil.WriteInt32(0x0);
startDatUtil.WriteInt32(0x0);
startDatUtil.WritePadding(0, 0x30);
startDatUtil.WriteBytes(image);
startDatStream.Seek(0x00, SeekOrigin.Begin);
return startDatStream.ToArray();
}
}
public virtual void Dispose()
{

291
PopsBuilder/Psp/NpUmdImg.cs Normal file
View File

@ -0,0 +1,291 @@
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Ocsp;
using PopsBuilder.Pops;
using PspCrypto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace PopsBuilder.Psp
{
public class NpUmdImg : NpDrmPsar
{
const int RATIO_LIMIT = 90;
const int BLOCK_BASIS = 0x10;
const int SECTOR_SZ = 2048;
const int BLOCK_SZ = BLOCK_BASIS * SECTOR_SZ;
public NpUmdImg(NpDrmInfo drmInfo, string iso, string discId, byte[] paramSfo, bool compress) : base(drmInfo)
{
this.isoStream = File.OpenRead(iso);
this.compress = compress;
this.npHdr = new MemoryStream();
this.npHdrUtil = new StreamUtil(npHdr);
this.npHdrBody = new MemoryStream();
this.npHdrBodyUtil = new StreamUtil(npHdrBody);
this.npTbl = new MemoryStream();
this.npTblUtil = new StreamUtil(npTbl);
this.isoData = new MemoryStream();
this.isoDataUtil = new StreamUtil(isoData);
this.headerKey = Rng.RandomBytes(0x10);
this.discId = discId.ToUpperInvariant().Replace("-", "").Replace("_", "");
this.paramSfo = paramSfo;
isoBlocks = Convert.ToInt64((isoStream.Length + BLOCK_SZ - 1) / BLOCK_SZ);
}
private void createNpHdr()
{
npHdrUtil.WriteStr("NPUMDIMG");
npHdrUtil.WriteInt32(DrmInfo.KeyType);
npHdrUtil.WriteInt32(BLOCK_BASIS);
npHdrUtil.WriteStrWithPadding(DrmInfo.ContentId, 0x00, 0x30);
createNpUmdBody();
byte[] npumdDec = npHdrBody.ToArray();
byte[] npumdEnc = encryptHeader(npumdDec);
npHdrUtil.WriteBytes(npumdEnc);
npHdrUtil.WriteBytes(this.headerKey);
npHdrUtil.WriteBytes(this.dataKey);
byte[] npumdhdr = npHdr.ToArray();
byte[] npumdheaderHash = hashBlock(npumdhdr);
npHdrUtil.WriteBytes(npumdheaderHash);
npHdrUtil.WriteBytes(Rng.RandomBytes(0x8)); // padding
npHdrUtil.PadUntil(0x00, 0x100);
}
public void CreatePsar()
{
createNpUmdTbl();
byte[] tbl = encryptTable();
this.dataKey = hashBlock(tbl);
createNpHdr();
byte[] npHdrBuf = npHdr.ToArray();
ECDsaHelper.SignNpImageHeader(npHdrBuf);
psarUtil.WriteBytes(npHdrBuf);
psarUtil.WriteBytes(tbl);
isoData.Seek(0x00, SeekOrigin.Begin);
isoData.CopyTo(Psar);
}
public byte[] signParamSfo(byte[] paramSfo)
{
int paramSfoLen = paramSfo.Length;
byte[] contentIdBytes = Encoding.UTF8.GetBytes(DrmInfo.ContentId);
Array.Resize(ref paramSfo, paramSfoLen + 0x30);
Array.ConstrainedCopy(contentIdBytes, 0, paramSfo, paramSfoLen, contentIdBytes.Length);
byte[] signature = new byte[0x30];
ECDsaHelper.SignParamSfo(paramSfo, signature);
return signature;
}
public override byte[] GenerateDataPsp()
{
bool minis = false; // TODO: read minis flag from param.sfo
byte[] startDat = CreateStartDat(minis ? Resources.STARTDATMINIS : Resources.STARTDATPSP);
using (MemoryStream dataPsp = new MemoryStream())
{
StreamUtil dataPspUtil = new StreamUtil(dataPsp);
byte[] signature = signParamSfo(paramSfo);
dataPspUtil.WriteBytes(signature);
dataPspUtil.WritePadding(0x00, 0x530);
dataPspUtil.WriteStrWithPadding(DrmInfo.ContentId, 0x00, 0x30);
dataPspUtil.WriteInt32BE(DrmInfo.KeyType);
dataPspUtil.WriteInt32(0);
dataPspUtil.WriteInt32(0);
dataPspUtil.WriteInt32(0);
dataPspUtil.WriteBytes(startDat);
return dataPsp.ToArray();
}
}
private void createNpUmdTbl()
{
Int64 tableSz = isoBlocks * 0x20;
Int64 isoSz = this.isoStream.Length;
int wsize = 0;
Int64 isoOffset = 0x100 + tableSz;
for (int i = 0; i < isoBlocks; i++)
{
byte[] isoBuf = new byte[BLOCK_SZ];
wsize = isoStream.Read(isoBuf, 0x00, BLOCK_SZ);
byte[] wbuf = isoBuf;
if (this.compress) // Compress data.
{
byte[] lzRcBuf = Lz.compress(isoBuf, true);
//memset(lzrc_buf + lzrc_size, 0, 16);
//
int ratio = (lzRcBuf.Length * 100) / BLOCK_SZ;
if (ratio < RATIO_LIMIT)
{
wbuf = lzRcBuf;
wsize = (lzRcBuf.Length + 15) & ~15;
Array.Resize(ref lzRcBuf, wsize);
}
}
int unpaddedSz = wsize;
wsize = (wsize + 15) & ~15;
Array.Resize(ref wbuf, wsize);
encryptBlock(wbuf, Convert.ToInt32(isoOffset));
byte[] hash = hashBlock(wbuf);
npTblUtil.WriteBytes(hash);
npTblUtil.WriteUInt32(Convert.ToUInt32(isoOffset));
npTblUtil.WriteUInt32(Convert.ToUInt32(unpaddedSz));
npTblUtil.WriteInt32(0);
npTblUtil.WriteInt32(0);
isoData.Write(wbuf, 0, wsize);
isoOffset += wsize;
Console.Write(Convert.ToInt32(Math.Floor((Convert.ToDouble(isoStream.Position) / Convert.ToDouble(isoStream.Length)) * 100.0)) + "%\r");
}
}
private byte[] encryptTable()
{
byte[] table = npTbl.ToArray();
// Encrypt Table
var tp = MemoryMarshal.Cast<byte, uint>(table);
for (int i = 0; i < (table.Length / 0x20); i++)
XorTable(tp[(i * 8)..]);
var tpbyt = MemoryMarshal.Cast<uint, byte>(tp);
return tpbyt.ToArray();
}
private static void XorTable(Span<uint> tp)
{
tp[4] ^= tp[3] ^ tp[2];
tp[5] ^= tp[2] ^ tp[1];
tp[6] ^= tp[0] ^ tp[3];
tp[7] ^= tp[1] ^ tp[0];
}
private byte[] encryptBlock(byte[] blockData, int offset)
{
AMCTRL.CIPHER_KEY ckey = new AMCTRL.CIPHER_KEY();
AMCTRL.sceDrmBBCipherInit(out ckey, 1, DrmInfo.KeyType, headerKey, DrmInfo.VersionKey, offset >> 4);
AMCTRL.sceDrmBBCipherUpdate(ref ckey, blockData, blockData.Length);
AMCTRL.sceDrmBBCipherFinal(ref ckey);
return blockData;
}
private byte[] hashBlock(byte[] blockData)
{
byte[] hash = new byte[0x10];
Span<byte> mkey = stackalloc byte[Marshal.SizeOf<PspCrypto.AMCTRL.MAC_KEY>()];
AMCTRL.sceDrmBBMacInit(mkey, 3);
AMCTRL.sceDrmBBMacUpdate(mkey, blockData, blockData.Length);
AMCTRL.sceDrmBBMacFinal(mkey, hash, DrmInfo.VersionKey);
Utils.BuildDrmBBMacFinal2(hash);
return hash;
}
private void createNpUmdBody()
{
npHdrBodyUtil.WriteUInt16(SECTOR_SZ); // sector_sz
if (isoStream.Length > 0x40000000)
npHdrBodyUtil.WriteUInt16(0xE001); // unk_2
else
npHdrBodyUtil.WriteUInt16(0xE000); //unk_2
npHdrBodyUtil.WriteUInt32(0); // unk_4
npHdrBodyUtil.WriteUInt32(0x1010); // unk_8
npHdrBodyUtil.WriteUInt32(0); // unk_12
npHdrBodyUtil.WriteUInt32(0); // unk_16
npHdrBodyUtil.WriteUInt32(0x00); // LBA START
npHdrBodyUtil.WriteUInt32(0); // unk_24
npHdrBodyUtil.WriteUInt32(Math.Min(Convert.ToUInt32((isoBlocks * BLOCK_BASIS) - 1), 0x6C0BF)); // nsectors
npHdrBodyUtil.WriteUInt32(0); // unk_32
npHdrBodyUtil.WriteUInt32(Convert.ToUInt32((isoBlocks * BLOCK_BASIS) - 1));
npHdrBodyUtil.WriteUInt32(0x01003FFE); // unk_40
npHdrBodyUtil.WriteUInt32(0x100); // block_entry_offset
npHdrBodyUtil.WriteStrWithPadding(this.discId.Substring(0, 4) + "-" + this.discId.Substring(4, 5), 0x00, 0x10);
npHdrBodyUtil.WriteInt32(0); // header_start_offset
npHdrBodyUtil.WriteInt32(0); // unk_68
npHdrBodyUtil.WriteByte(0x00); // unk_72
npHdrBodyUtil.WriteByte(0x00); // bbmac param
npHdrBodyUtil.WriteByte(0x00); // unk_74
npHdrBodyUtil.WriteByte(0x00); // unk_75
npHdrBodyUtil.WriteInt32(0); // unk_76
npHdrBodyUtil.WriteInt32(0); // unk_80
npHdrBodyUtil.WriteInt32(0); // unk_84
npHdrBodyUtil.WriteInt32(0); // unk_88
npHdrBodyUtil.WriteInt32(0); // unk_92
}
private byte[] encryptHeader(byte[] headerBytes)
{
AMCTRL.CIPHER_KEY ckey = new AMCTRL.CIPHER_KEY();
AMCTRL.sceDrmBBCipherInit(out ckey, 1, DrmInfo.KeyType, headerKey, DrmInfo.VersionKey, 0);
AMCTRL.sceDrmBBCipherUpdate(ref ckey, headerBytes, headerBytes.Length);
AMCTRL.sceDrmBBCipherFinal(ref ckey);
return headerBytes;
}
private Int64 isoBlocks;
private bool compress;
private string discId;
private byte[] paramSfo;
private byte[] headerKey;
private byte[] dataKey;
private FileStream isoStream;
private MemoryStream npHdr;
private StreamUtil npHdrUtil;
private MemoryStream npHdrBody;
private StreamUtil npHdrBodyUtil;
private MemoryStream isoData;
private StreamUtil isoDataUtil;
private MemoryStream npTbl;
private StreamUtil npTblUtil;
}
}

View File

@ -10,14 +10,19 @@ namespace PopsBuilder.Psp
{
public static void CreatePbp(byte[]? paramSfo, byte[]? icon0Png, byte[]? icon1Png,
byte[]? pic0Png, byte[]? pic1Png, byte[]? snd0At3,
byte[] dataPsp, NpDrmPsar dataPsar, string outputFile)
NpDrmPsar dataPsar, string outputFile, short version = 1)
{
using (FileStream pbpStream = File.Open(outputFile, FileMode.Create))
{
byte[] dataPsp = dataPsar.GenerateDataPsp();
int padLen = Convert.ToInt32(0x100 - (dataPsp.Length % 0x100));
Array.Resize(ref dataPsp, dataPsp.Length + padLen);
StreamUtil pbpUtil = new StreamUtil(pbpStream);
pbpUtil.WriteByte(0x00);
pbpUtil.WriteStrWithPadding("PBP", 0x00, 0x5);
pbpUtil.WriteStr("PBP");
pbpUtil.WriteInt16(version);
pbpUtil.WriteInt16(1);
// param location

29
PopsBuilder/Psp/Rng.cs Normal file
View File

@ -0,0 +1,29 @@
using PspCrypto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PopsBuilder.Psp
{
public static class Rng
{
public static byte[] RandomBytes(int length)
{
byte[] randomBytes = new byte[length];
KIRKEngine.sceUtilsBufferCopyWithRange(randomBytes, randomBytes.Length, null, 0, KIRKEngine.KIRK_CMD_PRNG);
return randomBytes;
}
public static uint RandomUInt()
{
byte[] uintBytes = RandomBytes(0x4);
return BitConverter.ToUInt32(uintBytes);
}
public static int RandomInt()
{
byte[] intBytes = RandomBytes(0x4);
return BitConverter.ToInt32(intBytes);
}
}
}

View File

@ -22,7 +22,7 @@ namespace PopsBuilder {
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
public class Resources {
private static global::System.Resources.ResourceManager resourceMan;
@ -36,7 +36,7 @@ namespace PopsBuilder {
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PopsBuilder.Resources", typeof(Resources).Assembly);
@ -51,7 +51,7 @@ namespace PopsBuilder {
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
@ -63,7 +63,7 @@ namespace PopsBuilder {
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] DATAPSPSD {
public static byte[] DATAPSPSD {
get {
object obj = ResourceManager.GetObject("DATAPSPSD", resourceCulture);
return ((byte[])(obj));
@ -73,7 +73,7 @@ namespace PopsBuilder {
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] DATAPSPSDCFG {
public static byte[] DATAPSPSDCFG {
get {
object obj = ResourceManager.GetObject("DATAPSPSDCFG", resourceCulture);
return ((byte[])(obj));
@ -83,7 +83,7 @@ namespace PopsBuilder {
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] SIMPLE {
public static byte[] SIMPLE {
get {
object obj = ResourceManager.GetObject("SIMPLE", resourceCulture);
return ((byte[])(obj));
@ -93,9 +93,29 @@ namespace PopsBuilder {
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] STARTDAT {
public static byte[] STARTDATMINIS {
get {
object obj = ResourceManager.GetObject("STARTDAT", resourceCulture);
object obj = ResourceManager.GetObject("STARTDATMINIS", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
public static byte[] STARTDATPOPS {
get {
object obj = ResourceManager.GetObject("STARTDATPOPS", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
public static byte[] STARTDATPSP {
get {
object obj = ResourceManager.GetObject("STARTDATPSP", resourceCulture);
return ((byte[])(obj));
}
}

View File

@ -127,7 +127,13 @@
<data name="SIMPLE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\SIMPLE.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="STARTDAT" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\STARTDAT.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<data name="STARTDATMINIS" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\STARTDATMINIS.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="STARTDATPOPS" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\STARTDATPOPS.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="STARTDATPSP" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\STARTDATPSP.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

View File

@ -1,4 +1,5 @@
using System;
using PspCrypto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -9,11 +10,9 @@ namespace PopsBuilder
public class StreamUtil
{
private Stream s;
private Random rng;
public StreamUtil(Stream s)
{
this.s = s;
rng = new Random();
}
public void WriteStrWithPadding(string str, byte b, int len)
@ -30,13 +29,6 @@ namespace PopsBuilder
WritePadding(b, (len - sdata.Length));
}
}
public void WriteRandom(int len)
{
byte[] randomBytes = new byte[len];
rng.NextBytes(randomBytes);
this.WriteBytes(randomBytes);
}
public byte[] ReadBytes(int len)
{
byte[] data = new byte[len];
@ -80,7 +72,10 @@ namespace PopsBuilder
{
WriteBytes(BitConverter.GetBytes(v));
}
public void WriteInt32BE(Int32 v)
{
WriteBytes(BitConverter.GetBytes(v).Reverse().ToArray());
}
public void WriteInt32(Int32 v)
{
WriteBytes(BitConverter.GetBytes(v));
@ -98,6 +93,11 @@ namespace PopsBuilder
}
}
public void AlignTo(byte padByte, int align)
{
int padAmt = Convert.ToInt32(align - (s.Position % align));
this.WritePadding(padByte, padAmt);
}
public void PadUntil(byte b, int len)
{
int remain = Convert.ToInt32(len - s.Length);

View File

@ -10,7 +10,7 @@ namespace PspCrypto
{
public class Lz
{
public static byte[] compress(byte[] in_buf)
public static byte[] compress(byte[] in_buf, bool np9660=false)
{
//Decoder decoder = new Decoder();
//using var inStream = new MemoryStream(@in);
@ -20,22 +20,21 @@ namespace PspCrypto
//decoder.SetDecoderProperties(properties);
//decoder.Code(inStream, outStream, insize, size, null);
//return 0;
var lzrc = new Lzrc();
var lzrc = new Lzrc(np9660);
// create a buffer hopefully big enough to hold compression result
byte[] compression_result = new byte[in_buf.Length + 0xffff]; // in worst case (i.e random data),
// compression makes the data larger
// so have to make sure theres extra space ..
// create a buffer big enough to hold compression result
byte[] compression_result = new byte[in_buf.Length];
// (this could get resized by the compression code, if its too small)
// compress data, and get the compressed data length
int compressed_length = lzrc.lzrc_compress(compression_result, compression_result.Length, in_buf, in_buf.Length);
int compressed_length = lzrc.lzrc_compress(ref compression_result, compression_result.Length, in_buf, in_buf.Length);
// resize array to actual compressed length ...
Array.Resize(ref compression_result, compressed_length);
return compression_result;
}
public static int decompress(byte[] @out, byte[] @in, int size, int insize)
public static int decompress(byte[] @out, byte[] @in, int size, int insize, bool np9660=false)
{
//Decoder decoder = new Decoder();
//using var inStream = new MemoryStream(@in);
@ -45,7 +44,7 @@ namespace PspCrypto
//decoder.SetDecoderProperties(properties);
//decoder.Code(inStream, outStream, insize, size, null);
//return 0;
var lzrc = new Lzrc();
var lzrc = new Lzrc(np9660);
lzrc.lzrc_decompress(@out, size, @in, insize);
return 0;
}

View File

@ -7,6 +7,8 @@ namespace PspCrypto
{
public class Lzrc
{
private bool np9660;
private byte[] input;
private int in_ptr;
private int in_len;
@ -19,11 +21,11 @@ namespace PspCrypto
private uint code;
private uint out_code;
private byte lc;
private byte[][] bm_literal = new byte[8][];
private byte[][] bm_dist_bits = new byte[8][];
private byte[][] bm_dist = new byte[16][];
private byte[][] bm_match = new byte[8][];
private byte[][] bm_len = new byte[8][];
private byte[][] bm_literal;
private byte[][] bm_dist_bits;
private byte[][] bm_dist;
private byte[][] bm_match;
private byte[][] bm_len;
const int max_tbl_sz = 65280;
const int tbl_sz = 65536;
@ -35,6 +37,28 @@ namespace PspCrypto
static int[] prev = new int[tbl_sz], next = new int[tbl_sz];
static int[] root = new int[tbl_sz];
public Lzrc(bool np9660 = false)
{
this.np9660 = np9660;
if (np9660)
{
this.bm_literal = new byte[8][];
this.bm_dist_bits = new byte[8][];
this.bm_dist = new byte[18][];
this.bm_match = new byte[8][];
this.bm_len = new byte[8][];
}
else
{
this.bm_literal = new byte[8][];
this.bm_dist_bits = new byte[8][];
this.bm_dist = new byte[16][];
this.bm_match = new byte[8][];
this.bm_len = new byte[8][];
}
}
static void Init(byte[][] arr, byte value, int length)
{
for (int i = 0; i < arr.Length; i++)
@ -85,19 +109,23 @@ namespace PspCrypto
re_putbyte(lc);
#if NP9660
Init(bm_literal, 0x80, 2048);
Init(bm_dist_bits, 0x80, 312);
Init(bm_dist, 0x80, 144);
Init(bm_match, 0x80, 64);
Init(bm_len, 0x80, 248);
#else
Init(bm_literal, 0x80, 256); // 2048 2680 2656
Init(bm_dist_bits, 0x80, 23); // 184
Init(bm_dist, 0x80, 8); // 128
Init(bm_match, 0x80, 8); // 64
Init(bm_len, 0x80, 32); // 256
#endif
if (this.np9660)
{
Init(bm_literal, 0x80, 256);
Init(bm_dist_bits, 0x80, 39);
Init(bm_dist, 0x80, 8);
Init(bm_match, 0x80, 8);
Init(bm_len, 0x80, 31);
}
else
{
Init(bm_literal, 0x80, 256); // 2048 2680 2656
Init(bm_dist_bits, 0x80, 23); // 184
Init(bm_dist, 0x80, 8); // 128
Init(bm_match, 0x80, 8); // 64
Init(bm_len, 0x80, 32); // 256
}
//memset(re->bm_literal, 0x80, 2048);
//memset(re->bm_dist_bits, 0x80, 312);
//memset(re->bm_dist, 0x80, 144);
@ -122,12 +150,25 @@ namespace PspCrypto
(rc_getbyte() << 8) |
rc_getbyte());
out_code = 0xffffffff;
if (this.np9660)
{
Init(bm_literal, 0x80, 256);
Init(bm_dist_bits, 0x80, 39);
Init(bm_dist, 0x80, 8);
Init(bm_match, 0x80, 8);
Init(bm_len, 0x80, 31);
}
else
{
Init(bm_literal, 0x80, 256); // 2048 2680 2656
Init(bm_dist_bits, 0x80, 23); // 184
Init(bm_dist, 0x80, 8); // 128
Init(bm_match, 0x80, 8); // 64
Init(bm_len, 0x80, 32); // 256
}
Init(bm_literal, 0x80, 256); // 2048 2680 2656
Init(bm_dist_bits, 0x80, 23); // 184
Init(bm_dist, 0x80, 8); // 128
Init(bm_match, 0x80, 8); // 64
Init(bm_len, 0x80, 32); // 256
}
void normalize()
@ -335,16 +376,16 @@ namespace PspCrypto
match_len = t_len;
match_dist = t_pos;
if (in_ptr == in_len)
if (in_ptr >= in_len)
{
match_len = 256;
return 0;
}
if (in_ptr == (in_len - 1))
if (in_ptr >= (in_len - 1))
return 0;
t = text_buf[pos+0];
t = text_buf[pos];
t = (t << 8) | text_buf[pos+1];
if (root[t] == -1)
{
@ -395,6 +436,14 @@ namespace PspCrypto
p = next[p];
}
if (this.np9660)
{
// have we calculated match_dist of 256 when its not the end?
if (t_len == 256 && in_ptr < in_len)
return 1;
}
if (t_pos < 0) throw new Exception("t_pos was < 0 :?"); // TODO: figure out why this happens on np9660.
match_len = t_len;
match_dist = t_pos;
@ -447,14 +496,12 @@ namespace PspCrypto
do
{
tmp = number >> n;
bit = (number >> (n - 1)) & 1;
re_bit(ref probs, index + tmp, bit);
n -= 1;
} while (n > 0);
//number = (res_number - limit);
}
void re_bit(ref byte[] prob, int index, int bit)
@ -520,7 +567,8 @@ namespace PspCrypto
{
if (out_ptr == out_len)
{
throw new Exception("Output overflow!");
out_len += 0x100;
Array.Resize(ref output, out_len);
}
output[out_ptr++] = out_byte;
@ -589,7 +637,7 @@ namespace PspCrypto
re_putbyte((byte)((code >> 8) & 0xff));
re_putbyte((byte)((code >> 0) & 0xff));
}
public int lzrc_compress(byte[] out_buf, int out_len, byte[] in_buf, int in_len)
public int lzrc_compress(ref byte[] out_buf, int out_len, byte[] in_buf, int in_len)
{
int match_step, re_state, len_state, dist_state;
int i, cur_byte, last_byte;
@ -610,6 +658,8 @@ namespace PspCrypto
last_byte = 0;
match_len = 0;
match_dist = 0;
bool flg = false;
while (true)
{
@ -621,19 +671,24 @@ namespace PspCrypto
if (match_len < 256)
{
#if NP9660
if (match_len < 4 && match_dist > 255)
#else
if (match_len <= 4 && match_dist > 255)
#endif
// condition is different if np9660 vs pops
if (this.np9660)
flg = (match_len < 4 && match_dist > 255);
else
flg = (match_len <= 4 && match_dist > 255);
if(flg) // if (condition)
match_len = 1;
update_tree(match_len);
}
#if NP9660
if ((match_len == 1 || (match_len < 4 && match_dist > 255)))
#else
if ((match_len == 1 || (match_len <= 4 && match_dist > 255)))
#endif
// condition is different if np9660 vs pops
if (this.np9660)
flg = (match_len == 1 || (match_len < 4 && match_dist > 255));
else
flg = (match_len == 1 || (match_len <= 4 && match_dist > 255));
if (flg)
{
re_bit(ref bm_match[re_state], match_step, 0);
@ -643,7 +698,7 @@ namespace PspCrypto
cur_byte = re_getbyte();
re_bittree(ref bm_literal[((last_byte >> lc) & 0x07)], 0, 0x100, cur_byte);
if (in_ptr == in_len)
if (in_ptr >= in_len)
{
re_normalize();
re_flush();
@ -665,44 +720,51 @@ namespace PspCrypto
len_bits += 1;
}
if (i != 8)
{
re_bit(ref bm_match[re_state], match_step, 0);
}
if (len_bits > 0)
{
len_state = ((len_bits - 1) << 2) + ((in_ptr << (len_bits - 1)) & 0x03);
re_number(ref bm_len[re_state], len_state, len_bits, (match_len - 1));
if (in_ptr == in_len)
if (this.np9660)
flg = (match_len == 256);
else
flg = (in_ptr >= in_len);
if (flg)
{
re_normalize();
re_flush();
return out_ptr;
}
}
// determine limit ...
dist_state = 0;
limit = 8;
#if NP9660
if ( match_len > 3)
#else
if( (match_len) > 4 )
#endif
// condition is different if np9660 vs pops
if (this.np9660)
flg = (match_len > 3);
else
flg = (match_len > 4);
if (flg) // if (condition)
{
dist_state += 7;
#if NP9660
limit = 44;
#else
limit = 16;
#endif
if (this.np9660)
limit = 44;
else
limit = 16;
}
// find total 1s in the match_dist
dist_bits = 0;
if(match_dist != 0) {
if(match_dist > 0) {
while ((match_dist >> dist_bits) != 1)
dist_bits += 1;
}
@ -714,9 +776,7 @@ namespace PspCrypto
re_bittree(ref bm_dist_bits[len_bits], dist_state, limit, dist_bits);
if (dist_bits > 0)
{
re_number(ref bm_dist[dist_bits], 0, dist_bits, match_dist);
}
in_ptr += match_len;
@ -736,15 +796,16 @@ namespace PspCrypto
int match_src;
int round = -1;
bool flg = false;
len_state = 0;
rc_init(out_buf, out_len, in_buf, in_len);
if ((lc & 0x80) != 0)
/*if ((lc & 0x80) != 0)
{
Buffer.BlockCopy(in_buf, 5, out_buf, 0, (int)code);
return (int)code;
}
}*/
rc_state = 0;
last_byte = 0;
@ -758,9 +819,7 @@ namespace PspCrypto
if (bit == 0)
{
if (rc_state > 0)
{
rc_state -= 1;
}
cur_byte = rc_bittree(bm_literal[(((out_ptr & 7) << 8) + last_byte >> lc) & 0x07], 0, 0x100);
@ -789,29 +848,31 @@ namespace PspCrypto
{
len_state = ((len_bits - 1) << 2) + ((out_ptr << (len_bits - 1)) & 0x03);
match_len = rc_number(bm_len[rc_state], len_state, len_bits);
//if ((match_len == 0xFF || match_len == 0xFE) && out_ptr == out_len)
//{
// return out_ptr;
//}
if (this.np9660 && match_len == 0xFF)
return out_ptr;
}
dist_state = 0;
limit = 8;
if (match_len > 3)
if (this.np9660)
flg = (match_len > 2);
else
flg = (match_len > 3);
if (flg)
{
dist_state += 7;
limit = 16;
if (this.np9660)
limit = 44;
else
limit = 16;
}
dist_bits = rc_bittree(bm_dist_bits[len_bits], dist_state, limit);
if (dist_bits > 0)
{
match_dist = rc_number(bm_dist[dist_bits], 0, dist_bits);
}
else
{
match_dist = 1;
}
match_src = out_ptr - match_dist;
if (match_dist > out_ptr || match_dist < 0)