larley.dev home page
================================================================================
← Inner workings of Playready (12/11/2024)
----------------------------------------------------------------------
I'll shed some light into the darkness that is Playready.
+ Client authentication:
Playready `devices` consist of two files. The `bgroupcert.dat`
file, which is a certificate issued by Microsoft for a specific
device, and the `zgpriv.dat`, a 32-byte large ECC private key point.
The group certificate isn't directly usable as-is, but has to first
be fitted with an ECC encryption and signing key. These sometimes
come with the other files included you can use, but don't have
to. Generating random ones does the job just fine.
To integrate them into the existing certificate chain, we firstly
create a new certificate, containing the respective public keys
of the encryption / signing curves and then sign all of that with
the group private key. The signature will also include the group
public key, so the server will be able to verify the signature.
The created (activated) certificate is also called `bdevcert.dat`.
+ PSSH
A Playready PSSH, defined here, consists of a Playready Object
containing one or more Playready Object Records, each identified
by a type value. Currently, only the type `1` is usable, which
corresponds to a Playready Header, containing UTF-16-LE encoded XML,
called the WRM Header.
+ License Request
Communication between the client server only takes place
using XML (which I think is foolish).
The WRM Header is placed in the `ContentHeader` section of the
license request.
To ensure that messages can only be read by the server and noone
else, we use the WMRMServer public key to encrypt our keys.
First, we generate a new temporary ECC key (per request), take
its X coordinate, convert that to bytes and then split it into
two halves. These two halves create a temporary AES key and IV
to encrypt data later on.
The aforementioned X coordinate in combination with its Y
coordinate is now encrypted with the WMRM Server public key, using
a not-so-well-known encryption algorithm called `ElGamal`.
This will produce two points, which are converted to bytes and
then concatenated into a single 128-byte value (p1.x + p1.y +
p2.x + p2.y). This is our `EncryptedKey` value in the challenge.
The temporary AES key and IV are now used to encrypt the
activated group certificate, and the IV is prepended to the
encrypted ciphertext, forming the main cipher data in the
challenge.
The digest (SHA-256) below the encrypted data is derived from the
`LA` section of the challenge and then placed inside the `SignedInfo`
element of the XML.
A signature (SHA-256, fips-186-3) is created from that section with
the temporary encryption key, resulting in the `SignatureValue`.
The signing key is also placed in the challenge, to, again, give
the server a way to verify the signature.
+ License
The License, internally also known as XMR License, contains the
ElGamal encrypted content keys.
It's made up of containers, each with a flag, a tag and length.
A type value of `10` corresponds to a ContentKey Object and can
contain multiple encrypted content keys.
Each encrypted key is 128 bytes long and consists of two ECC Points,
each with a 32-byte X and Y coordinate.
We can use the encryption key we generated beforehand to decrypt
the two points, which will result in a single point.
Now, convert the point's X coordinate to bytes and take the latter
16 bytes of the 32 bytes to get the content key.