Add AACS wrapper and printing

This commit is contained in:
Matt Nadareski
2023-01-12 13:28:12 -08:00
parent a230871f75
commit 53b5a443fe
4 changed files with 295 additions and 7 deletions

View File

@@ -171,6 +171,9 @@ namespace BurnOutSharp.Builders
// TODO: Use marshalling here instead of building
var record = new ExplicitSubsetDifferenceRecord();
record.RecordType = type;
record.RecordLength = length;
// Cache the current offset
long initialOffset = data.Position - 4;
@@ -208,6 +211,9 @@ namespace BurnOutSharp.Builders
// TODO: Use marshalling here instead of building
var record = new MediaKeyDataRecord();
record.RecordType = type;
record.RecordLength = length;
// Cache the current offset
long initialOffset = data.Position - 4;
@@ -241,6 +247,9 @@ namespace BurnOutSharp.Builders
// TODO: Use marshalling here instead of building
var record = new SubsetDifferenceIndexRecord();
record.RecordType = type;
record.RecordLength = length;
// Cache the current offset
long initialOffset = data.Position - 4;
@@ -278,7 +287,7 @@ namespace BurnOutSharp.Builders
record.RecordType = type;
record.RecordLength = length;
record.MKBType = (MediaKeyBlockType)data.ReadUInt32BE();
record.MediaKeyBlockType = (MediaKeyBlockType)data.ReadUInt32BE();
record.VersionNumber = data.ReadUInt32BE();
return record;
@@ -298,6 +307,9 @@ namespace BurnOutSharp.Builders
// TODO: Use marshalling here instead of building
var record = new DriveRevocationListRecord();
record.RecordType = type;
record.RecordLength = length;
// Cache the current offset
long initialOffset = data.Position - 4;
@@ -354,6 +366,9 @@ namespace BurnOutSharp.Builders
// TODO: Use marshalling here instead of building
var record = new HostRevocationListRecord();
record.RecordType = type;
record.RecordLength = length;
// Cache the current offset
long initialOffset = data.Position - 4;

View File

@@ -17,7 +17,7 @@ namespace BurnOutSharp.Models.AACS
/// controlling access to AACS Content on pre- recorded media. In
/// this case, the device shall not use the KCD.
/// </summary>
public MediaKeyBlockType MKBType;
public MediaKeyBlockType MediaKeyBlockType;
/// <summary>
/// The Version Number is a 32-bit unsigned integer. Each time the

View File

@@ -0,0 +1,273 @@
using System;
using System.IO;
namespace BurnOutSharp.Wrappers
{
public class AACSMediaKeyBlock : WrapperBase
{
#region Pass-Through Properties
#region Records
/// <inheritdoc cref="Models.AACS.MediaKeyBlock.Records"/>
public Models.AACS.Record[] Records => _mediaKeyBlock.Records;
#endregion
#endregion
#region Instance Variables
/// <summary>
/// Internal representation of the AACS media key block
/// </summary>
private Models.AACS.MediaKeyBlock _mediaKeyBlock;
#endregion
#region Constructors
/// <summary>
/// Private constructor
/// </summary>
private AACSMediaKeyBlock() { }
/// <summary>
/// Create an AACS media key block from a byte array and offset
/// </summary>
/// <param name="data">Byte array representing the archive</param>
/// <param name="offset">Offset within the array to parse</param>
/// <returns>An AACS media key block wrapper on success, null on failure</returns>
public static AACSMediaKeyBlock Create(byte[] data, int offset)
{
// If the data is invalid
if (data == null)
return null;
// If the offset is out of bounds
if (offset < 0 || offset >= data.Length)
return null;
// Create a memory stream and use that
MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset);
return Create(dataStream);
}
/// <summary>
/// Create an AACS media key block from a Stream
/// </summary>
/// <param name="data">Stream representing the archive</param>
/// <returns>An AACS media key block wrapper on success, null on failure</returns>
public static AACSMediaKeyBlock Create(Stream data)
{
// If the data is invalid
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
return null;
var mediaKeyBlock = Builders.AACS.ParseMediaKeyBlock(data);
if (mediaKeyBlock == null)
return null;
var wrapper = new AACSMediaKeyBlock
{
_mediaKeyBlock = mediaKeyBlock,
_dataSource = DataSource.Stream,
_streamData = data,
};
return wrapper;
}
#endregion
#region Printing
/// <inheritdoc/>
public override void Print()
{
Console.WriteLine("AACS Media Key Block Information:");
Console.WriteLine("-------------------------");
Console.WriteLine();
PrintRecords();
}
/// <summary>
/// Print records information
/// </summary>
private void PrintRecords()
{
Console.WriteLine(" Records Information:");
Console.WriteLine(" -------------------------");
if (Records == null || Records.Length == 0)
{
Console.WriteLine(" No records");
}
else
{
for (int i = 0; i < Records.Length; i++)
{
var record = Records[i];
Console.WriteLine($" Record Entry {i}");
Console.WriteLine($" Record type: {record.RecordType} (0x{record.RecordType:X})");
Console.WriteLine($" Record length: {record.RecordLength} (0x{record.RecordLength:X})");
switch (record.RecordType)
{
case Models.AACS.RecordType.EndOfMediaKeyBlock:
var eomkb = record as Models.AACS.EndOfMediaKeyBlockRecord;
Console.WriteLine($" Signature data: {BitConverter.ToString(eomkb.SignatureData ?? new byte[0]).Replace('-', ' ')}");
break;
case Models.AACS.RecordType.ExplicitSubsetDifference:
var esd = record as Models.AACS.ExplicitSubsetDifferenceRecord;
Console.WriteLine($" Subset Differences:");
Console.WriteLine(" -------------------------");
if (esd.SubsetDifferences == null || esd.SubsetDifferences.Length == 0)
{
Console.WriteLine($" No subset differences");
}
else
{
for (int j = 0; j < esd.SubsetDifferences.Length; j++)
{
var sd = esd.SubsetDifferences[j];
Console.WriteLine($" Subset Difference {j}");
Console.WriteLine($" Mask: {sd.Mask} (0x{sd.Mask:X})");
Console.WriteLine($" Number: {sd.Number} (0x{sd.Number:X})");
}
}
break;
case Models.AACS.RecordType.MediaKeyData:
var mkd = record as Models.AACS.MediaKeyDataRecord;
Console.WriteLine($" Media Keys:");
Console.WriteLine(" -------------------------");
if (mkd.MediaKeyData == null || mkd.MediaKeyData.Length == 0)
{
Console.WriteLine($" No media keys");
}
else
{
for (int j = 0; j < mkd.MediaKeyData.Length; j++)
{
var mk = mkd.MediaKeyData[j];
Console.WriteLine($" Media key {j}: {BitConverter.ToString(mk ?? new byte[0]).Replace('-', ' ')}");
}
}
break;
case Models.AACS.RecordType.SubsetDifferenceIndex:
var sdi = record as Models.AACS.SubsetDifferenceIndexRecord;
Console.WriteLine($" Span: {sdi.Span} (0x{sdi.Span:X})");
Console.WriteLine($" Offsets:");
Console.WriteLine(" -------------------------");
if (sdi.Offsets == null || sdi.Offsets.Length == 0)
{
Console.WriteLine($" No offsets");
}
else
{
for (int j = 0; j < sdi.Offsets.Length; j++)
{
var offset = sdi.Offsets[j];
Console.WriteLine($" Offset {j}: {offset} (0x{offset:X})");
}
}
break;
case Models.AACS.RecordType.TypeAndVersion:
var tav = record as Models.AACS.TypeAndVersionRecord;
Console.WriteLine($" Media key block type: {tav.MediaKeyBlockType} (0x{tav.MediaKeyBlockType:X})");
Console.WriteLine($" Version number: {tav.VersionNumber} (0x{tav.VersionNumber:X})");
break;
case Models.AACS.RecordType.DriveRevocationList:
var drl = record as Models.AACS.DriveRevocationListRecord;
Console.WriteLine($" Total number of entries: {drl.TotalNumberOfEntries} (0x{drl.TotalNumberOfEntries:X})");
Console.WriteLine($" Signature Blocks:");
Console.WriteLine(" -------------------------");
if (drl.SignatureBlocks == null || drl.SignatureBlocks.Length == 0)
{
Console.WriteLine($" No signature blocks");
}
else
{
for (int j = 0; j < drl.SignatureBlocks.Length; j++)
{
var block = drl.SignatureBlocks[j];
Console.WriteLine($" Signature Block {j}");
Console.WriteLine($" Number of entries: {block.NumberOfEntries}");
Console.WriteLine($" Entry Fields:");
Console.WriteLine(" -------------------------");
if (block.EntryFields == null || block.EntryFields.Length == 0)
{
Console.WriteLine($" No entry fields");
}
else
{
for (int k = 0; k < block.EntryFields.Length; k++)
{
var ef = block.EntryFields[k];
Console.WriteLine($" Entry {k}");
Console.WriteLine($" Range: {ef.Range} (0x{ef.Range:X})");
Console.WriteLine($" Drive ID: {BitConverter.ToString(ef.DriveID ?? new byte[0]).Replace('-', ' ')}");
}
}
}
}
break;
case Models.AACS.RecordType.HostRevocationList:
var hrl = record as Models.AACS.HostRevocationListRecord;
Console.WriteLine($" Total number of entries: {hrl.TotalNumberOfEntries} (0x{hrl.TotalNumberOfEntries:X})");
Console.WriteLine($" Signature Blocks:");
Console.WriteLine(" -------------------------");
if (hrl.SignatureBlocks == null || hrl.SignatureBlocks.Length == 0)
{
Console.WriteLine($" No signature blocks");
}
else
{
for (int j = 0; j < hrl.SignatureBlocks.Length; j++)
{
var block = hrl.SignatureBlocks[j];
Console.WriteLine($" Signature Block {j}");
Console.WriteLine($" Number of entries: {block.NumberOfEntries}");
Console.WriteLine($" Entry Fields:");
Console.WriteLine(" -------------------------");
if (block.EntryFields == null || block.EntryFields.Length == 0)
{
Console.WriteLine($" No entry fields");
}
else
{
for (int k = 0; k < block.EntryFields.Length; k++)
{
var ef = block.EntryFields[k];
Console.WriteLine($" Entry {k}");
Console.WriteLine($" Range: {ef.Range} (0x{ef.Range:X})");
Console.WriteLine($" Host ID: {BitConverter.ToString(ef.HostID ?? new byte[0]).Replace('-', ' ')}");
}
}
}
}
break;
case Models.AACS.RecordType.VerifyMediaKey:
var vmk = record as Models.AACS.VerifyMediaKeyRecord;
Console.WriteLine($" Ciphertext value: {BitConverter.ToString(vmk.CiphertextValue ?? new byte[0]).Replace('-', ' ')}");
break;
case Models.AACS.RecordType.Copyright:
var c = record as Models.AACS.CopyrightRecord;
Console.WriteLine($" Copyright: {c.Copyright ?? "[NULL]"}");
break;
}
}
}
Console.WriteLine();
}
#endregion
}
}

View File

@@ -225,11 +225,11 @@ namespace BurnOutSharp.Wrappers
{
var entry = FileTable[i];
Console.WriteLine($" File Table Entry {i}");
Console.WriteLine($" Name size = {entry.NameSize} (0x{entry.NameSize:X})");
Console.WriteLine($" Name = {entry.Name}");
Console.WriteLine($" Uncompressed size = {entry.UncompressedSize} (0x{entry.UncompressedSize:X})");
Console.WriteLine($" Offset = {entry.Offset} (0x{entry.Offset:X})");
Console.WriteLine($" Compressed Size = {entry.CompressedSize} (0x{entry.CompressedSize:X})");
Console.WriteLine($" Name size: {entry.NameSize} (0x{entry.NameSize:X})");
Console.WriteLine($" Name: {entry.Name}");
Console.WriteLine($" Uncompressed size: {entry.UncompressedSize} (0x{entry.UncompressedSize:X})");
Console.WriteLine($" Offset: {entry.Offset} (0x{entry.Offset:X})");
Console.WriteLine($" Compressed Size: {entry.CompressedSize} (0x{entry.CompressedSize:X})");
}
}
Console.WriteLine();