multi-downloader-nx_mirror/modules/playready/device.ts
2024-12-13 02:28:54 +01:00

128 lines
3.7 KiB
TypeScript

import { Parser } from 'binary-parser-encoder';
import { CertificateChain } from './bcert';
import ECCKey from './ecc_key';
import * as fs from 'fs';
type RawDeviceV2 = {
signature: string;
version: number;
group_certificate_length: number;
group_certificate: Buffer;
encryption_key: Buffer;
signing_key: Buffer;
};
class DeviceStructs {
static magic = 'PRD';
static v1 = new Parser()
.string('signature', { length: 3, assert: DeviceStructs.magic })
.uint8('version')
.uint32('group_key_length')
.buffer('group_key', { length: 'group_key_length' })
.uint32('group_certificate_length')
.buffer('group_certificate', { length: 'group_certificate_length' });
static v2 = new Parser()
.string('signature', { length: 3, assert: DeviceStructs.magic })
.uint8('version')
.uint32('group_certificate_length')
.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.v3;
group_certificate: CertificateChain;
encryption_key: ECCKey;
signing_key: ECCKey;
security_level: number;
constructor(parsedData: RawDeviceV2) {
this.group_certificate = CertificateChain.loads(
parsedData.group_certificate
);
this.encryption_key = ECCKey.loads(parsedData.encryption_key);
this.signing_key = ECCKey.loads(parsedData.signing_key);
this.security_level = this.group_certificate.get_security_level();
}
static loads(data: Buffer): Device {
const parsedData = Device.CURRENT_STRUCT.parse(data);
return new Device(parsedData);
}
static load(filePath: string): Device {
const data = fs.readFileSync(filePath);
return Device.loads(data);
}
dumps(): Buffer {
const groupCertBytes = this.group_certificate.dumps();
const encryptionKeyBytes = this.encryption_key.dumps();
const signingKeyBytes = this.signing_key.dumps();
const buildData = {
signature: DeviceStructs.magic,
version: 2,
group_certificate_length: groupCertBytes.length,
group_certificate: groupCertBytes,
encryption_key: encryptionKeyBytes,
signing_key: signingKeyBytes,
};
return Device.CURRENT_STRUCT.encode(buildData);
}
dump(filePath: string): void {
const data = this.dumps();
fs.writeFileSync(filePath, data);
}
get_name(): string {
const name = `${this.group_certificate.get_name()}_sl${
this.security_level
}`;
return name.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase();
}
}
// Device V2 disabled because unstable provisioning
// export class Device {
// group_certificate: CertificateChain
// encryption_key: ECCKey
// signing_key: ECCKey
// security_level: number
// constructor(group_certificate: Buffer, group_key: Buffer) {
// this.group_certificate = CertificateChain.loads(group_certificate)
// this.encryption_key = ECCKey.generate()
// this.signing_key = ECCKey.generate()
// this.security_level = this.group_certificate.get_security_level()
// const new_certificate = Certificate.new_key_cert(
// randomBytes(16),
// this.group_certificate.get_security_level(),
// randomBytes(16),
// this.signing_key,
// this.encryption_key,
// ECCKey.loads(group_key),
// this.group_certificate
// )
// this.group_certificate.prepend(new_certificate)
// }
// }