From b96329bd332b97b78af73ec4bca22d224562c2d1 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 12 Jan 2023 09:40:02 -0800 Subject: [PATCH] Add AACS media key block models --- .../AACS/EndOfMediaKeyBlockRecord.cs | 23 ++++++++++++++ BurnOutSharp.Models/AACS/Enums.cs | 12 ++++++++ .../AACS/ExplicitSubsetDifferenceRecord.cs | 11 +++++++ BurnOutSharp.Models/AACS/MediaKeyBlock.cs | 14 +++++++++ .../AACS/MediaKeyDataRecord.cs | 18 +++++++++++ BurnOutSharp.Models/AACS/Record.cs | 28 +++++++++++++++++ BurnOutSharp.Models/AACS/SubsetDifference.cs | 20 +++++++++++++ .../AACS/SubsetDifferenceIndexRecord.cs | 26 ++++++++++++++++ .../AACS/TypeAndVersionRecord.cs | 30 +++++++++++++++++++ .../AACS/VerifyMediaKeyRecord.cs | 24 +++++++++++++++ 10 files changed, 206 insertions(+) create mode 100644 BurnOutSharp.Models/AACS/EndOfMediaKeyBlockRecord.cs create mode 100644 BurnOutSharp.Models/AACS/Enums.cs create mode 100644 BurnOutSharp.Models/AACS/ExplicitSubsetDifferenceRecord.cs create mode 100644 BurnOutSharp.Models/AACS/MediaKeyBlock.cs create mode 100644 BurnOutSharp.Models/AACS/MediaKeyDataRecord.cs create mode 100644 BurnOutSharp.Models/AACS/Record.cs create mode 100644 BurnOutSharp.Models/AACS/SubsetDifference.cs create mode 100644 BurnOutSharp.Models/AACS/SubsetDifferenceIndexRecord.cs create mode 100644 BurnOutSharp.Models/AACS/TypeAndVersionRecord.cs create mode 100644 BurnOutSharp.Models/AACS/VerifyMediaKeyRecord.cs diff --git a/BurnOutSharp.Models/AACS/EndOfMediaKeyBlockRecord.cs b/BurnOutSharp.Models/AACS/EndOfMediaKeyBlockRecord.cs new file mode 100644 index 00000000..1646cccf --- /dev/null +++ b/BurnOutSharp.Models/AACS/EndOfMediaKeyBlockRecord.cs @@ -0,0 +1,23 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + /// A properly formatted MKB shall contain an End of Media Key Block Record. + /// When a device encounters this Record it stops processing the MKB, using + /// whatever Km value it has calculated up to that point as the final Km for + /// that MKB (pending possible checks for correctness of the key, as + /// described previously). + /// + /// + public sealed class EndOfMediaKeyBlockRecord : Record + { + /// + /// AACS LA’s signature on the data in the Media Key Block up to, + /// but not including, this record. Devices depending on the Version + /// Number in the Type and Version Record must verify the signature. + /// Other devices may ignore the signature data. If any device + /// determines that the signature does not verify or is omitted, it + /// must refuse to use the Media Key. + /// + public byte[] SignatureData; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/Enums.cs b/BurnOutSharp.Models/AACS/Enums.cs new file mode 100644 index 00000000..7403264c --- /dev/null +++ b/BurnOutSharp.Models/AACS/Enums.cs @@ -0,0 +1,12 @@ +namespace BurnOutSharp.Models.AACS +{ + public enum RecordType : byte + { + EndOfMediaKeyBlock = 0x02, + ExplicitSubsetDifference = 0x04, + MediaKeyData = 0x05, + SubsetDifferenceIndex = 0x07, + TypeAndVersion = 0x10, + VerifyMediaKey = 0x81, + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/ExplicitSubsetDifferenceRecord.cs b/BurnOutSharp.Models/AACS/ExplicitSubsetDifferenceRecord.cs new file mode 100644 index 00000000..1e638881 --- /dev/null +++ b/BurnOutSharp.Models/AACS/ExplicitSubsetDifferenceRecord.cs @@ -0,0 +1,11 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + public sealed class ExplicitSubsetDifferenceRecord : Record + { + /// + /// In this record, each subset-difference is encoded with 5 bytes. + /// + public SubsetDifference[] SubsetDifferences; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/MediaKeyBlock.cs b/BurnOutSharp.Models/AACS/MediaKeyBlock.cs new file mode 100644 index 00000000..72e28a46 --- /dev/null +++ b/BurnOutSharp.Models/AACS/MediaKeyBlock.cs @@ -0,0 +1,14 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + /// A Media Key Block is formatted as a sequence of contiguous Records. + /// + /// + public sealed class MediaKeyBlock + { + /// + /// Records + /// + public Record[] Records { get; set; } + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/MediaKeyDataRecord.cs b/BurnOutSharp.Models/AACS/MediaKeyDataRecord.cs new file mode 100644 index 00000000..91af9b0a --- /dev/null +++ b/BurnOutSharp.Models/AACS/MediaKeyDataRecord.cs @@ -0,0 +1,18 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + /// This record gives the associated encrypted media key data for the + /// subset-differences identified in the Explicit Subset-Difference Record. + /// + /// + public sealed class MediaKeyDataRecord : Record + { + /// + /// Each subset difference has its associated 16 bytes in this + /// record, in the same order it is encountered in the subset-difference + /// record. This 16 bytes is the ciphertext value C in the media + /// key calculation. + /// + public byte[][] MediaKeyData; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/Record.cs b/BurnOutSharp.Models/AACS/Record.cs new file mode 100644 index 00000000..0c86ec40 --- /dev/null +++ b/BurnOutSharp.Models/AACS/Record.cs @@ -0,0 +1,28 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + /// Each Record begins with a one-byte Record Type field, followed by a + /// three-byte Record Length field. + /// + /// The following subsections describe the currently defined Record types, + /// and how a device processes each. All multi-byte integers, including + /// the length field, are “Big Endian”; in other words, the most significant + /// byte comes first in the record. + /// + /// + public abstract class Record + { + /// + /// The Record Type field value indicates the type of the Record. + /// + public RecordType RecordType; + + /// + /// The Record Length field value indicates the number of bytes in + /// the Record, including the Record Type and the Record Length + /// fields themselves. Record lengths are always multiples of 4 bytes. + /// + // UInt24 not UInt32 + public uint RecordLength; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/SubsetDifference.cs b/BurnOutSharp.Models/AACS/SubsetDifference.cs new file mode 100644 index 00000000..53e63671 --- /dev/null +++ b/BurnOutSharp.Models/AACS/SubsetDifference.cs @@ -0,0 +1,20 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + public sealed class SubsetDifference + { + /// + /// The mask for u is given by the first byte. That byte is + /// treated as a number, the number of low-order 0-bits in + /// the mask. For example, the value 0x01 denotes a mask of + /// 0xFFFFFFFE; value 0x0A denotes a mask of 0xFFFFFC00. + /// + public byte Mask; + + /// + /// The last 4 bytes are the uv number, most significant + /// byte first. + /// + public uint Number; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/SubsetDifferenceIndexRecord.cs b/BurnOutSharp.Models/AACS/SubsetDifferenceIndexRecord.cs new file mode 100644 index 00000000..4428c245 --- /dev/null +++ b/BurnOutSharp.Models/AACS/SubsetDifferenceIndexRecord.cs @@ -0,0 +1,26 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + /// This is a speed-up record which can be ignored by devices not wishing to + /// take advantage of it. It is a lookup table which allows devices to quickly + /// find their subset-difference in the Explicit Subset-Difference record, + /// without processing the entire record. This Subset-Difference Index record + /// is always present, and always precedes the Explicit Subset-Difference record + /// in the MKB, although it does not necessarily immediately precede it. + /// + /// + public sealed class SubsetDifferenceIndexRecord : Record + { + /// + /// The number of devices per index offset. + /// + public uint Span; + + /// + /// These offsets refer to the offset within the following Explicit + /// Subset-Difference record, with 0 being the start of the record. + /// + // UInt24 not UInt32 + public uint[] Offsets; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/TypeAndVersionRecord.cs b/BurnOutSharp.Models/AACS/TypeAndVersionRecord.cs new file mode 100644 index 00000000..8ca2d210 --- /dev/null +++ b/BurnOutSharp.Models/AACS/TypeAndVersionRecord.cs @@ -0,0 +1,30 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + /// Devices, except for recording devices which are writing Media Key Block + /// Extensions, may ignore this record. Recording devices shall verify the + /// signature (see End of Media Key Block record) and use the Version Number + /// in this record to determine if a new Media Key BLock Extension is, in + /// fact, more recent than the Media Key Block Extension that is currently + /// on the media. + /// + /// + public sealed class TypeAndVersionRecord : Record + { + /// + /// For AACS applications, the type field is always 0x00031003. + /// Devices shall ignore this. + /// + public uint MKBType; + + /// + /// The Version Number is a 32-bit unsigned integer. Each time the + /// licensing agency changes the revocation, it increments the version + /// number and inserts the new value in subsequent Media Key Blocks. + /// Thus, larger values indicate more recent Media Key Blocks. The + /// Version Numbers begin at 1; 0 is a special value used for test + /// Media Key Blocks. + /// + public uint VersionNumber; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/AACS/VerifyMediaKeyRecord.cs b/BurnOutSharp.Models/AACS/VerifyMediaKeyRecord.cs new file mode 100644 index 00000000..0eba733f --- /dev/null +++ b/BurnOutSharp.Models/AACS/VerifyMediaKeyRecord.cs @@ -0,0 +1,24 @@ +namespace BurnOutSharp.Models.AACS +{ + /// + /// A properly formatted MKB shall have exactly one Verify Media Key Record + /// as its first record. The presence of the Verify Media Key Record in an MKB + /// is mandatory, but the use of the Record by a device is not mandatory. The + /// device may use the Verify Media Key Record to verify the correctness of a + /// given MKB, or of its processing of it. If everything is correct, the device + /// should observe the condition: + /// [AES_128D(vKm, C]msb_64 == 0x0123456789ABCDEF)] + /// where Km is the Media Key value. + /// + /// + public sealed class VerifyMediaKeyRecord : Record + { + /// + /// Bytes 4 through 19 of the Record contain the ciphertext value + /// Cv = AES-128E (Km, 0x0123456789ABCDEF || 0xXXXXXXXXXXXXXXXX) + /// where 0xXXXXXXXXXXXXXXXX is an arbitrary 8-byte value, and Km is + /// the correct final Media Key value. + /// + public byte[] CiphertextValue; + } +} \ No newline at end of file