added prd v3 device support

This commit is contained in:
stratumadev 2024-12-13 02:28:54 +01:00
parent 1f12a75009
commit 37b8bbad1f
8 changed files with 305 additions and 328 deletions

View file

@ -111,8 +111,8 @@ export class BCertStructs {
});
static DrmBCertExtDataSignKeyInfo = new Parser()
.uint16be('type')
.uint16be('length')
.uint16be('key_type')
.uint16be('key_length')
.uint32be('flags')
.buffer('key', {
length: function () {
@ -219,7 +219,7 @@ export class Certificate {
}
// UNSTABLE
static new_key_cert(
static new_leaf_cert(
cert_id: Buffer,
security_level: number,
client_id: Buffer,
@ -232,13 +232,6 @@ export class Certificate {
max_header: number = 15360,
max_chain_depth: number = 2
): Certificate {
if (!cert_id) {
throw new Error('Certificate ID is required');
}
if (!client_id) {
throw new Error('Client ID is required');
}
const basic_info = {
cert_id: cert_id,
security_level: security_level,
@ -269,8 +262,8 @@ export class Certificate {
};
const feature = {
feature_count: 1,
features: [4, 13],
feature_count: 3,
features: [4, 9, 13],
};
const feature_attribute = {
flags: 1,

View file

@ -2,8 +2,8 @@ import { CertificateChain } from './bcert';
import ECCKey from './ecc_key';
import ElGamal, { Point } from './elgamal';
import XmlKey from './xml_key';
import { CipherType, getCipherType, Key } from './key';
import { XMRLicense } from './xmrlicense';
import { Key } from './key';
import { XmrUtil } from './xmrlicense';
import crypto from 'crypto';
import { randomBytes } from 'crypto';
import { createHash } from 'crypto';
@ -79,7 +79,7 @@ export default class Cdm {
private getCipherData(): Buffer {
const b64_chain = this.certificate_chain.dumps().toString('base64');
const body = `<Data><CertificateChains><CertificateChain>${b64_chain}</CertificateChain></CertificateChains></Data>`;
const body = `<Data><CertificateChains><CertificateChain>${b64_chain}</CertificateChain></CertificateChains><Features><Feature Name="AESCBC"></Feature></Features></Data>`;
const cipher = crypto.createCipheriv(
'aes-128-cbc',
@ -105,7 +105,7 @@ export default class Cdm {
return (
'<LA xmlns="http://schemas.microsoft.com/DRM/2007/03/protocols" Id="SignedData" xml:space="preserve">' +
`<Version>${this.la_version}</Version>` +
'<Version>4</Version>' +
`<ContentHeader>${content_header}</ContentHeader>` +
'<CLIENTINFO>' +
`<CLIENTVERSION>${this.client_version}</CLIENTVERSION>` +
@ -209,7 +209,7 @@ export default class Cdm {
return main_body;
}
private _decryptEcc256Key(encrypted_key: Buffer): Buffer {
private decryptEcc256Key(encrypted_key: Buffer): Buffer {
const point1 = this.curve.curve.point(
encrypted_key.subarray(0, 32).toString('hex'),
encrypted_key.subarray(32, 64).toString('hex')
@ -253,19 +253,21 @@ export default class Cdm {
const keys = [];
for (const licenseElement of licenses) {
for (const key of XMRLicense.loads(licenseElement).get_content_keys()) {
if (getCipherType(key.cipher_type) === CipherType.ECC256) {
keys.push(
new Key(
this.fixUUID(key.key_id),
key.key_type,
key.cipher_type,
key.key_length,
this._decryptEcc256Key(key.encrypted_key)
)
);
}
}
const keyMaterial = XmrUtil.parse(Buffer.from(licenseElement, 'base64'))
.license.license.keyMaterial;
if (!keyMaterial || !keyMaterial.contentKey)
throw new Error('No Content Keys retrieved');
keys.push(
new Key(
keyMaterial.contentKey.kid,
keyMaterial.contentKey.keyType,
keyMaterial.contentKey.ciphertype,
keyMaterial.contentKey.length,
this.decryptEcc256Key(keyMaterial.contentKey.value)
)
);
}
return keys;
@ -273,13 +275,4 @@ export default class Cdm {
throw new Error(`Unable to parse license, ${error}`);
}
}
fixUUID(data: Buffer): Buffer {
return Buffer.concat([
Buffer.from(data.subarray(0, 4).reverse()),
Buffer.from(data.subarray(4, 6).reverse()),
Buffer.from(data.subarray(6, 8).reverse()),
data.subarray(8, 16),
]);
}
}

View file

@ -30,10 +30,19 @@ class DeviceStructs {
.buffer('group_certificate', { length: 'group_certificate_length' })
.buffer('encryption_key', { length: 96 })
.buffer('signing_key', { length: 96 });
static v3 = new Parser()
.string('signature', { length: 3, assert: DeviceStructs.magic })
.uint8('version')
.buffer('group_key', { length: 96 })
.buffer('encryption_key', { length: 96 })
.buffer('signing_key', { length: 96 })
.uint32('group_certificate_length')
.buffer('group_certificate', { length: 'group_certificate_length' });
}
export class Device {
static CURRENT_STRUCT = DeviceStructs.v2;
static CURRENT_STRUCT = DeviceStructs.v3;
group_certificate: CertificateChain;
encryption_key: ECCKey;

View file

@ -1,4 +1,4 @@
export enum KeyType {
enum KeyType {
Invalid = 0x0000,
AES128CTR = 0x0001,
RC4 = 0x0002,
@ -8,7 +8,7 @@ export enum KeyType {
UNKNOWN = 0xffff,
}
export function getKeyType(value: number): KeyType {
function getKeyType(value: number): KeyType {
switch (value) {
case KeyType.Invalid:
case KeyType.AES128CTR:
@ -22,7 +22,7 @@ export function getKeyType(value: number): KeyType {
}
}
export enum CipherType {
enum CipherType {
Invalid = 0x0000,
RSA128 = 0x0001,
ChainedLicense = 0x0002,
@ -32,7 +32,7 @@ export enum CipherType {
UNKNOWN = 0xffff,
}
export function getCipherType(value: number): CipherType {
function getCipherType(value: number): CipherType {
switch (value) {
case CipherType.Invalid:
case CipherType.RSA128:
@ -54,17 +54,16 @@ export class Key {
key: string;
constructor(
key_id: Buffer | string,
key_id: string,
key_type: number,
cipher_type: number,
key_length: number,
key: Buffer | string
key: Buffer
) {
this.key_id = Buffer.isBuffer(key_id) ? key_id.toString('hex') : key_id;
this.key_id = key_id;
this.key_type = getKeyType(key_type);
this.cipher_type = getCipherType(cipher_type);
this.key_length = key_length;
this.key = Buffer.isBuffer(key) ? key.toString('hex') : key;
this.key = key.toString('hex');
}
}

View file

@ -5,31 +5,37 @@ import WRMHeader from './wrmheader';
const SYSTEM_ID = Buffer.from('9a04f07998404286ab92e65be0885f95', 'hex');
const PSSHBox = new Parser()
.uint32('length')
.string('pssh', { length: 4, assert: 'pssh' })
.uint32('fullbox')
.buffer('system_id', { length: 16 })
.uint32('data_length')
.buffer('data', { length: 'data_length' });
.buffer('data', {
length: 'data_length',
});
const PlayreadyObject = new Parser()
.endianess('little')
.useContextVars()
.uint16('type')
.uint16('length')
.choice('data', {
tag: 'type',
choices: {
1: new Parser().string('data', {
length: 'length',
length: function () {
return (this as any).$parent.length;
},
encoding: 'utf16le',
}),
},
defaultChoice: new Parser().buffer('data', { length: 'length' }),
defaultChoice: new Parser().buffer('data', {
length: function () {
return (this as any).$parent.length;
},
}),
});
const PlayreadyHeader = new Parser()
.endianess('little')
.uint32('length')
.uint16('record_count')
.array('records', {
@ -38,7 +44,7 @@ const PlayreadyHeader = new Parser()
});
function isPlayreadyPsshBox(data: Buffer): boolean {
if (data.length < 28) return false; // Ensure enough length
if (data.length < 28) return false;
return data.subarray(12, 28).equals(SYSTEM_ID);
}
@ -111,10 +117,12 @@ export class PSSH {
// Header downgrade
public get_wrm_headers(downgrade_to_v4: boolean = false): string[] {
return this.wrm_headers.map(downgrade_to_v4 ? this._downgrade : (_) => _);
return this.wrm_headers.map(
downgrade_to_v4 ? this.downgradePSSH : (_) => _
);
}
private _downgrade(wrm_header: string): string {
private downgradePSSH(wrm_header: string): string {
const header = new WRMHeader(wrm_header);
return header.to_v4_0_0_0();
}

View file

@ -51,10 +51,6 @@ export default class WRMHeader {
return 'UNKNOWN';
}
private static ensureList(element: any): any[] {
return Array.isArray(element) ? element : [element];
}
to_v4_0_0_0(): string {
const [key_ids, la_url, lui_url, ds_id] = this.readAttributes();
if (key_ids.length === 0) throw new Error('No Key IDs available');
@ -98,18 +94,16 @@ export default class WRMHeader {
private static read_vX(data: any): ReturnStructure {
const protectInfo = data.PROTECTINFO;
const signedKeyIDs: SignedKeyID[] = protectInfo?.KID
? WRMHeader.ensureList(protectInfo.KID).map(
(kid: any) =>
new SignedKeyID(
kid['@_ALGID'] || '',
kid['@_VALUE'],
kid['@_CHECKSUM']
)
const signedKeyID: SignedKeyID | undefined = protectInfo.KIDS.KID
? new SignedKeyID(
protectInfo.KIDS.KID['@_ALGID'] || '',
protectInfo.KIDS.KID['@_VALUE'],
protectInfo.KIDS.KID['@_CHECKSUM']
)
: [];
: undefined;
return [
signedKeyIDs,
signedKeyID ? [signedKeyID] : [],
data.LA_URL || null,
data.LUI_URL || null,
data.DS_ID || null,

View file

@ -26,20 +26,20 @@ export default class XmlKey {
}
// Make it more undetectable (not working right now)
// import { ec as EC } from 'elliptic'
// import { Point } from './elgamal.js'
// import { randomBytes } from 'crypto';
// import { randomBytes } from 'crypto'
// export default class XmlKey {
// public aesIv: Uint8Array;
// public aesKey: Uint8Array;
// public aesIv: Uint8Array
// public aesKey: Uint8Array
// public bytes: Uint8Array
// constructor() {
// this.aesIv = randomBytes(16);
// this.aesKey = randomBytes(16);
// }
// this.aesIv = randomBytes(16)
// this.aesKey = randomBytes(16)
// this.bytes = new Uint8Array([...this.aesIv, ...this.aesKey])
// getPoint(curve: EC): Point {
// return curve.curve.point(this.aesIv, this.aesKey)
// console.log('XML key (AES/CBC)')
// console.log('iv:', Buffer.from(this.aesIv).toString('hex'))
// console.log('key:', Buffer.from(this.aesKey).toString('hex'))
// console.log('bytes:', this.bytes)
// }
// }

View file

@ -1,270 +1,251 @@
import { Parser } from 'binary-parser';
import * as fs from 'fs';
export class XMRLicenseStructs {
static PlayEnablerType = new Parser().buffer('player_enabler_type', {
length: 16,
});
type ParsedLicense = {
version: number;
rights: string;
length: number;
license: {
length: number;
signature?: {
length: number;
type: string;
value: string;
};
global_container?: {
revocationInfo?: {
version: number;
};
securityLevel?: {
level: number;
};
};
keyMaterial?: {
contentKey?: {
kid: string;
keyType: number;
ciphertype: number;
length: number;
value: Buffer;
};
encryptionKey?: {
curve: number;
length: number;
value: string;
};
auxKeys?: {
count: number;
value: {
location: number;
value: string;
};
};
};
};
};
static DomainRestrictionObject = new Parser()
.buffer('account_id', { length: 16 })
.uint32('revision');
export class XMRLicenseStructsV2 {
static CONTENT_KEY = new Parser()
.buffer('kid', { length: 16 })
.uint16('keytype')
.uint16('ciphertype')
.uint16('length')
.buffer('value', {
length: 'length',
});
static IssueDateObject = new Parser().uint32('issue_date');
static ECC_KEY = new Parser()
.uint16('curve')
.uint16('length')
.buffer('value', {
length: 'length',
});
static RevInfoVersionObject = new Parser().uint32('sequence');
static SecurityLevelObject = new Parser().uint16('minimum_security_level');
static EmbeddedLicenseSettingsObject = new Parser().uint16('indicator');
static ECCKeyObject = new Parser()
.uint16('curve_type')
.uint16('key_length')
.buffer('key', {
static FTLV = new Parser()
.uint16('flags')
.uint16('type')
.uint32('length')
.buffer('value', {
length: function () {
return (this as any).key_length;
return (this as any).length - 8;
},
});
static SignatureObject = new Parser()
.uint16('signature_type')
.uint16('signature_data_length')
.buffer('signature_data', {
length: function () {
return (this as any).signature_data_length;
},
});
static ContentKeyObject = new Parser()
.buffer('key_id', { length: 16 })
.uint16('key_type')
.uint16('cipher_type')
.uint16('key_length')
.buffer('encrypted_key', {
length: function () {
return (this as any).key_length;
},
});
static RightsSettingsObject = new Parser().uint16('rights');
static OutputProtectionLevelRestrictionObject = new Parser()
.uint16('minimum_compressed_digital_video_opl')
.uint16('minimum_uncompressed_digital_video_opl')
.uint16('minimum_analog_video_opl')
.uint16('minimum_digital_compressed_audio_opl')
.uint16('minimum_digital_uncompressed_audio_opl');
static ExpirationRestrictionObject = new Parser()
.uint32('begin_date')
.uint32('end_date');
static RemovalDateObject = new Parser().uint32('removal_date');
static UplinkKIDObject = new Parser()
.buffer('uplink_kid', { length: 16 })
.uint16('chained_checksum_type')
.uint16('chained_checksum_length')
.buffer('chained_checksum', {
length: function () {
return (this as any).chained_checksum_length;
},
});
static AnalogVideoOutputConfigurationRestriction = new Parser()
.buffer('video_output_protection_id', { length: 16 })
.buffer('binary_configuration_data', {
length: function () {
return (this as any).$parent.length - 16;
},
});
static DigitalVideoOutputRestrictionObject = new Parser()
.buffer('video_output_protection_id', { length: 16 })
.buffer('binary_configuration_data', {
length: function () {
return (this as any).$parent.length - 16;
},
});
static DigitalAudioOutputRestrictionObject = new Parser()
.buffer('audio_output_protection_id', { length: 16 })
.buffer('binary_configuration_data', {
length: function () {
return (this as any).$parent.length - 16;
},
});
static PolicyMetadataObject = new Parser()
.buffer('metadata_type', { length: 16 })
.buffer('policy_data', {
length: function () {
return (this as any).$parent.length - 16;
},
});
static SecureStopRestrictionObject = new Parser().buffer('metering_id', {
length: 16,
});
static MeteringRestrictionObject = new Parser().buffer('metering_id', {
length: 16,
});
static ExpirationAfterFirstPlayRestrictionObject = new Parser().uint32(
'seconds'
);
static GracePeriodObject = new Parser().uint32('grace_period');
static SourceIdObject = new Parser().uint32('source_id');
static AuxiliaryKey = new Parser()
static AUXILIARY_LOCATIONS = new Parser()
.uint32('location')
.buffer('key', { length: 16 });
.buffer('value', { length: 16 });
static AuxiliaryKeysObject = new Parser()
static AUXILIARY_KEY_OBJECT = new Parser()
.uint16('count')
.array('auxiliary_keys', {
.array('locations', {
length: 'count',
type: XMRLicenseStructs.AuxiliaryKey,
type: XMRLicenseStructsV2.AUXILIARY_LOCATIONS,
});
static UplinkKeyObject3 = new Parser()
.buffer('uplink_key_id', { length: 16 })
.uint16('chained_length')
.buffer('checksum', {
length: function () {
return (this as any).chained_length;
static SIGNATURE = new Parser()
.uint16('type')
.uint16('siglength')
.buffer('signature', {
length: 'siglength',
});
static XMR = new Parser()
.string('constant', { length: 4, assert: 'XMR\x00' })
.int32('version')
.buffer('rightsid', { length: 16 })
.nest('data', {
type: XMRLicenseStructsV2.FTLV,
});
}
enum XMRTYPE {
XMR_OUTER_CONTAINER = 0x0001,
XMR_GLOBAL_POLICY_CONTAINER = 0x0002,
XMR_PLAYBACK_POLICY_CONTAINER = 0x0004,
XMR_KEY_MATERIAL_CONTAINER = 0x0009,
XMR_RIGHTS_SETTINGS = 0x000d,
XMR_EMBEDDED_LICENSE_SETTINGS = 0x0033,
XMR_REVOCATION_INFORMATION_VERSION = 0x0032,
XMR_SECURITY_LEVEL = 0x0034,
XMR_CONTENT_KEY_OBJECT = 0x000a,
XMR_ECC_KEY_OBJECT = 0x002a,
XMR_SIGNATURE_OBJECT = 0x000b,
XMR_OUTPUT_LEVEL_RESTRICTION = 0x0005,
XMR_AUXILIARY_KEY_OBJECT = 0x0051,
XMR_EXPIRATION_RESTRICTION = 0x0012,
XMR_ISSUE_DATE = 0x0013,
XMR_EXPLICIT_ANALOG_CONTAINER = 0x0007,
}
export class XmrUtil {
public data: Buffer;
public license: ParsedLicense;
constructor(data: Buffer, license: ParsedLicense) {
this.data = data;
this.license = license;
}
static parse(license: Buffer) {
const xmr = XMRLicenseStructsV2.XMR.parse(license);
const parsed_license: ParsedLicense = {
version: xmr.version,
rights: Buffer.from(xmr.rightsid).toString('hex'),
length: license.length,
license: {
length: xmr.data.length,
},
})
.uint16('count')
.array('entries', {
length: 'count',
type: new Parser().uint32('entry'),
});
};
const container = parsed_license.license;
const data = xmr.data;
static CopyEnablerObject = new Parser().buffer('copy_enabler_type', {
length: 16,
});
let pos = 0;
while (pos < data.length - 16) {
const value = XMRLicenseStructsV2.FTLV.parse(data.value.slice(pos));
static CopyCountRestrictionObject = new Parser().uint32('count');
// XMR_SIGNATURE_OBJECT
if (value.type === XMRTYPE.XMR_SIGNATURE_OBJECT) {
const signature = XMRLicenseStructsV2.SIGNATURE.parse(value.value);
static MoveObject = new Parser().uint32('minimum_move_protection_level');
static XMRObject = (): Parser =>
new Parser()
.namely('self')
.int16('flags')
.int16('type')
.int32('length')
.choice('data', {
tag: 'type',
choices: {
0x0005: XMRLicenseStructs.OutputProtectionLevelRestrictionObject,
0x0008: XMRLicenseStructs.AnalogVideoOutputConfigurationRestriction,
0x000a: XMRLicenseStructs.ContentKeyObject,
0x000b: XMRLicenseStructs.SignatureObject,
0x000d: XMRLicenseStructs.RightsSettingsObject,
0x0012: XMRLicenseStructs.ExpirationRestrictionObject,
0x0013: XMRLicenseStructs.IssueDateObject,
0x0016: XMRLicenseStructs.MeteringRestrictionObject,
0x001a: XMRLicenseStructs.GracePeriodObject,
0x0022: XMRLicenseStructs.SourceIdObject,
0x002a: XMRLicenseStructs.ECCKeyObject,
0x002c: XMRLicenseStructs.PolicyMetadataObject,
0x0029: XMRLicenseStructs.DomainRestrictionObject,
0x0030: XMRLicenseStructs.ExpirationAfterFirstPlayRestrictionObject,
0x0031: XMRLicenseStructs.DigitalAudioOutputRestrictionObject,
0x0032: XMRLicenseStructs.RevInfoVersionObject,
0x0033: XMRLicenseStructs.EmbeddedLicenseSettingsObject,
0x0034: XMRLicenseStructs.SecurityLevelObject,
0x0037: XMRLicenseStructs.MoveObject,
0x0039: XMRLicenseStructs.PlayEnablerType,
0x003a: XMRLicenseStructs.CopyEnablerObject,
0x003b: XMRLicenseStructs.UplinkKIDObject,
0x003d: XMRLicenseStructs.CopyCountRestrictionObject,
0x0050: XMRLicenseStructs.RemovalDateObject,
0x0051: XMRLicenseStructs.AuxiliaryKeysObject,
0x0052: XMRLicenseStructs.UplinkKeyObject3,
0x005a: XMRLicenseStructs.SecureStopRestrictionObject,
0x0059: XMRLicenseStructs.DigitalVideoOutputRestrictionObject,
},
defaultChoice: 'self',
});
static XmrLicense = new Parser()
.useContextVars()
.buffer('signature', { length: 4 })
.int32('xmr_version')
.buffer('rights_id', { length: 16 })
.array('containers', {
type: XMRLicenseStructs.XMRObject(),
readUntil: 'eof',
});
}
export class XMRLicense extends XMRLicenseStructs {
parsed: any;
_LICENSE: Parser;
constructor(
parsed_license: any,
license_obj: Parser = XMRLicenseStructs.XmrLicense
) {
super();
this.parsed = parsed_license;
this._LICENSE = license_obj;
}
static loads(data: string | Buffer): XMRLicense {
if (typeof data === 'string') {
data = Buffer.from(data, 'base64');
}
if (!Buffer.isBuffer(data)) {
throw new Error(`Expecting Bytes or Base64 input, got ${data}`);
}
const licence = XMRLicenseStructs.XmrLicense;
const parsed_license = licence.parse(data);
return new XMRLicense(parsed_license, licence);
}
static load(filePath: string): XMRLicense {
if (typeof filePath !== 'string') {
throw new Error(`Expecting path string, got ${filePath}`);
}
const data = fs.readFileSync(filePath);
return XMRLicense.loads(data);
}
dumps(): Buffer {
return this._LICENSE.parse(this.parsed);
}
struct(): Parser {
return this._LICENSE;
}
private _locate(container: any): any {
if (container.flags === 2 || container.flags === 3) {
return this._locate(container.data);
} else {
return container;
}
}
*get_object(type_: number): Generator<any> {
for (const obj of this.parsed.containers) {
const container = this._locate(obj);
if (container.type === type_) {
yield container.data;
container.signature = {
length: value.length,
type: signature.type,
value: Buffer.from(signature.signature).toString('hex'),
};
}
// XMRTYPE.XMR_GLOBAL_POLICY_CONTAINER
if (value.type === XMRTYPE.XMR_GLOBAL_POLICY_CONTAINER) {
container.global_container = {};
let index = 0;
while (index < value.length - 16) {
const data = XMRLicenseStructsV2.FTLV.parse(value.value.slice(index));
// XMRTYPE.XMR_REVOCATION_INFORMATION_VERSION
if (data.type === XMRTYPE.XMR_REVOCATION_INFORMATION_VERSION) {
container.global_container.revocationInfo = {
version: data.value.readUInt32BE(0),
};
}
// XMRTYPE.XMR_SECURITY_LEVEL
if (data.type === XMRTYPE.XMR_SECURITY_LEVEL) {
container.global_container.securityLevel = {
level: data.value.readUInt16BE(0),
};
}
index += data.length;
}
}
// XMRTYPE.XMR_KEY_MATERIAL_CONTAINER
if (value.type === XMRTYPE.XMR_KEY_MATERIAL_CONTAINER) {
container.keyMaterial = {};
let index = 0;
while (index < value.length - 16) {
const data = XMRLicenseStructsV2.FTLV.parse(value.value.slice(index));
// XMRTYPE.XMR_CONTENT_KEY_OBJECT
if (data.type === XMRTYPE.XMR_CONTENT_KEY_OBJECT) {
const content_key = XMRLicenseStructsV2.CONTENT_KEY.parse(
data.value
);
container.keyMaterial.contentKey = {
kid: XmrUtil.fixUUID(content_key.kid).toString('hex'),
keyType: content_key.keytype,
ciphertype: content_key.ciphertype,
length: content_key.length,
value: content_key.value,
};
}
// XMRTYPE.XMR_ECC_KEY_OBJECT
if (data.type === XMRTYPE.XMR_ECC_KEY_OBJECT) {
const ecc_key = XMRLicenseStructsV2.ECC_KEY.parse(data.value);
container.keyMaterial.encryptionKey = {
curve: ecc_key.curve,
length: ecc_key.length,
value: Buffer.from(ecc_key.value).toString('hex'),
};
}
// XMRTYPE.XMR_AUXILIARY_KEY_OBJECT
if (data.type === XMRTYPE.XMR_AUXILIARY_KEY_OBJECT) {
const aux_keys = XMRLicenseStructsV2.AUXILIARY_KEY_OBJECT.parse(
data.value
);
container.keyMaterial.auxKeys = {
count: aux_keys.count,
value: aux_keys.locations.map((a: any) => {
return {
location: a.location,
value: Buffer.from(a.value).toString('hex'),
};
}),
};
}
index += data.length;
}
}
pos += value.length;
}
return new XmrUtil(license, parsed_license);
}
get_content_keys(): Generator<any> {
return this.get_object(0x000a);
static fixUUID(data: Buffer): Buffer {
return Buffer.concat([
Buffer.from(data.subarray(0, 4).reverse()),
Buffer.from(data.subarray(4, 6).reverse()),
Buffer.from(data.subarray(6, 8).reverse()),
data.subarray(8, 16),
]);
}
}