multi-downloader-nx_mirror/modules/playready/device.ts
2024-12-07 03:35:22 +01:00

117 lines
3.5 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 })
}
export class Device {
static CURRENT_STRUCT = DeviceStructs.v2
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)
// }
// }