📄 technical
字号:
-----BEGIN PGP SIGNED MESSAGE-----
Microsoft's Digital Rights Management Scheme - Technical Details
By "Beale Screamer"
This document describes version 2 of the Microsoft Digital Rights
Management (MS-DRM), as applied to audio (.wma files). The sources
for this material are varied, and some of the information might be
slightly incomplete; however, the fundamental ideas are solid and
easily verified. There is no attempt at describing the older version
1 of DRM. While version 1 is widely used (probably more widely than
version 2!), and the scheme is somewhat simpler, the purpose of this
is to describe the latest technology and not necessarily allow all
existing systems to be broken. The ideas described here are also
implemented in the software originally distributed with this document
(but as an independent piece, so the software may or may not be
available from where you have obtained this document), so a real
implementation can be examined. Not all of the information here is
needed in order to write the software that removes the encryption, but
some of the more interesting points surrounding the MS-DRM scheme and
software are given even if not necessary. Also note that no code is
included in this document, either real code or pseudo-code. All
that's in this document is a straight mathematical discussion, which
should be fully protected under the 1st Amendment to the
U.S. Constitution. I have no doubt that the corporate entities that
this document offends will attempt to suppress it, but I don't think
any argument they make could hold up to Constitutional scrutiny.
The basic components of MS-DRM involve use of elliptic curve
cryptography (ECC) for public key cryptography, DES for a block
cipher, RC4 for a stream cipher, and SHA-1 for a hash function. There
is also a block cipher which I haven't seen before, used in the MS-DRM
system to build a MAC, or keyed hash function. This cipher will be
explained completely below, and while the remaining algorithms are
well-known, more will be said about Microsoft's use of ECC below.
In the discussion and examples below, all numbers are expressed in
hexadecimal in the standard ordering (most-to-least significant)
unless otherwise stated. The actual bytes comprising large numbers in
any code are stored little endian, so at times it is convenient to
look at data in that ordering, and this will be clearly marked when it
is done.
One confusing item is that binary data sent back and forth is encoded
using Base64, but not using the standard algorithm! For some reason,
Microsoft has decided to use the non-alphanumeric character '*'
instead of '/', and '!' instead of '+' in some places, and in other
places they replace '/' with '@' and '!' with '%'. This means that
any software dealing with these strings cannot use a standard Base64
decoder, but must use a custom-build decoder.
FILES INVOLVED
Several key DLLs are kept in \windows\system that relate to the MS-DRM
scheme.
drmv2clt.dll: Provides basic DRM version 2 functionality
blackbox.dll: Provides basic, machine-specific crypto for MS-DRM.
Functionality replaced by IndivBox.key when the local
system has been "individualized."
The other interesting place for files is in \windows\All Users\DRM
(this location is not necessarily fixed but comes from the registry
entry HKEY_LOCAL_MACHINE\Software\Microsoft\DRM\DataPath). Here's a
sampling of some of the files in this directory (these are hidden
system files, so be sure to turn on "view all files" in order to see
them!):
IndivBox.key: Despite the extension, this is really a DLL
that is an "individualized" version of blackbox.dll
drmv2.lic: The file of licenses (a structured IStorage file)
drmv2.sst: "Secure state" for each of the licenses. Also an IStorage
file, but each stream is RC4 encrypted.
v2ks.bla: The version 2 "key store" - this is where all the public/private
keys are kept (encrypted, of course!).
v2ksndv.bla: The individualized version 2 "key store."
A SIMPLE BLOCK CIPHER (MULTISWAP)
Microsoft is using a very simple block cipher to create a message
authentication code (MAC). As this is not a standard algorithm, I
will describe it fully. The main operations in this cipher are
32-bit multiplications and swaps of the two halves of 32-bit words, so
I have called this cipher the "MultiSwap" cipher.
The MultiSwap cipher works on 64-bit blocks, using a key that consists
of 12 32-bit words, and a current state (or initialization vector)
that is 64-bits long. In the Microsoft implementation, the least
significant bits of all 12 words are set to 1, although once the
cipher is understood it is clear that really only 10 of the words
require this bit to be set. The basic operation of the cipher is a
transformation that is done on the first 32-bit word of the plaintext
block using the first 6 key words, and then repeated for the other
plaintext word and remaining key words.
Let k[0], k[1], k[2], k[3], k[4], and k[5] denote the first 6 key
words, and let s[0] and s[1] denote the two words of the state. To
transform a 32-bit input word x, first define the following function
f(a)=swap(swap(swap(swap(swap(a*k[0])*k[1])*k[2])*k[3])*k[4]) + k[5]
where * is multiplication modulo 2^(32), and "swap" is an operation
which exchanges the two 16-bit halves of a 32-bit word. The complete
transformation of a 32-bit word x then consists of s[1]=s[1]+f(x+s[0])
and s[0]=f(x+s[0]). This is first done with the value x set to the
first 32 bits of the input, and then repeated with x set to the second
32 bits and the using keys k[6] through k[11]. The output of the
block cipher is the new state s[0] and s[1].
The reason this block cipher can be inverted is because all the key
words are odd, which means they have multiplicative inverses modulo
2^(32). To invert f(), just do the operations in the reverse order:
first subtract off k[5], then do the multiply/swap operations with the
inverses of k[4] through k[0]. Notice that only the multiplicative
key words really need to be odd, so there is no reason for the least
significant bit of k[5] or k[11] to be set; however, Microsoft sets
these bits anyway.
This block cipher is never used for encryption, but is used to create
a message authentication code (MAC) in the standard way. Assuming the
length of the message to be hashed is a multiple of 8 bytes (64 bits),
the cipher is initialized with a state of all zeros, and then used to
encrypt the entire data. The output of the last block (the final
state) is the MAC for that message. This is used in computing packet
keys to encrypt protected content by MS-DRM, as will be explained
later.
ELLIPTIC CURVE CRYPTOGRAPHY
For ECC, Microsoft is using an elliptic curve over Zp, where p is a
160 bit prime number (given below). The curve consists of the points
that lie on the curve y^2=x^3+ax+b, where the operations are done over
the field Zp and a and b are coefficients that are given below.
All values are represented as packed binary values: in other words, a
single value over Zp is encoded simply as 20 bytes, stored in little
endian order. A point on the elliptic curve is therefore a 40 byte
block, which consists of two 20 byte little endian values (the x
coordinate followed by the y coordinate). Here are the parameters for
the elliptic curve used in MS-DRM:
p (modulus): 89abcdef012345672718281831415926141424f7
coefficient a: 37a5abccd277bce87632ff3d4780c009ebe41497
coefficient b: 0dd8dabf725e2f3228e85f1ad78fdedf9328239e
generator x: 8723947fd6a3a1e53510c07dba38daf0109fa120
generator y: 445744911075522d8c3c5856d4ed7acda379936f
Order of curve: 89abcdef012345672716b26eec14904428c2a675
These constants are fixed, and used by all parties in the MS-DRM
system. The "nerd appeal" of the modulus is high when you see this
number in hexadecimal: it includes counting in the hexadecimal, as
well as the digits of fundamental constants e, pi, and sqrt(2).
In order to use this public key system, any user must have a
private/public key pair. Since the security of the system relies
pretty heavily on the private keys remaining secret (even from the
user of the system on which they reside), they are carefully hidden.
In fact, there are keys hidden in various files that are used,
including blackbox.dll, v2ks.bla, and IndivBox.key. For example, once
the player has been individualized, IndivBox.key is created, and there
are at least two keys embedded into this file: a 64-bit key used for
RC4, and a 160-bit private key for use in ECC. The ECC private key is
used as the basic client key (the corresponding public key is stored
unencrypted in the key store file, and used as the initial part of the
"client id" sent when requesting a license), and additional key pairs
are stored in part of the keystore file (v2ks.bla or v2ksndv.bla),
encrypted with the RC4 key.
These secret keys are stored in linked lists that contain 32 bits per
node (so the key as a whole is not in contiguous memory), interspersed
with the code in the library (IndivBox.key for example). The idea is
that they can be read by that library, used internally by that
library, and never communicated outside the library. Since the
IndivBox.key file is shuffled in a random way for each client, these
keys would be extremely difficult to extract from the file itself.
Fortunately, we don't have to: these keys are part of the object state
that is maintained by this library, and since the offset within this
object of these secret keys is known, we can let the library itself
extract the secret keys! The code for this simply loads up the "black
box" library, has it initialize an instance of the object, and then
reads the keys right out of that object. This is clearly a weakness
in the code which can be corrected by the DRM software fairly easily,
but for now it is the basis of our exploit.
GETTING A LICENSE
Each protected media file is encrypted with a "content key" that will
unlock the packets of the media stream. We describe briefly how a
license (containing a content key) is obtained for information
purposes, but the license acquisition protocol is not really important
for unlocking that content. Simply use the MS Media player, have it
request and decrypt the licenses, store them in drmv2.lic, and then we
can extract them directly from that file.
A protected media file is apparently recognized by the presence of a
DRMV2 object in the .wma file header. This object has GUID
298ae614-2622-4c17-b935-dae07ee9289c, and contains an XML object 6
bytes into the data part of the object. Among other things, this
header contains a "KID" element identifying the key used to unlock the
content. The drmv2.lic file is then checked to see if a license with
this KID exists locally. If the license doesn't exist, a license
request is formed, which sends an encrypted "client id" to the license
server. This is sent as a "challenge," which consists of 168 bytes in
the MS-Base64 encoding. The first 80 bytes are two ECC points, which
make up an ECC encrypted random session key, and the remaining 88
bytes are the "client id" encrypted using RC4 and the session key.
The ECC encryption is done using a public key that seems to be fixed
for all clients, so it is safe to assume that this corresponds to a
private key that is common to all license servers and built in to that
side of the system (without access to the server side code, it was
impossible to find the corresponding private key).
After some interaction, the license comes back as mime type
application/x-drm-v2, as an escaped XML-encoded license in the
following format
<LICENSERESPONSE><LICENSE version="x.x.x.x">
...base64 encoded license... </LICENSE></LICENSERESPONSE>
where x.x.x.x is most likely "2.0.0.0". To make things tricky for a
sniffer, the license is actually RC4 encrypted using the same session
key that was established by the client when sending the challenge.
The client then decrypts the license and stores it in the drmv2.lic
file.
GETTING THE CONTENT KEY
Getting the content key from a license is pretty easy once the client
knows what its public/private key pairs are, and has a copy of the
license obtained from drmv2.lic. The license entry is an XML object
with an element for "ENABLINGBITS", which has sub-elements ALGORITHM
(which should have type "MSDRM"), PUBKEY, VALUE, and SIGNATURE. The
PUBKEY element should match one of the client's public keys, or else
there a problem! The VALUE element is the ECC-encrypted content key,
which can be decrypted by the private key that corresponds to the
given PUBKEY.
The content key has a specific format: the y coordinate is ignored,
and when the x coordinate is written in storage order (little endian),
the first byte is the length of the content key (which may always be
7), which is followed by that many bytes of the content key. While
the content key is tied to the encoded media file (which may be common
to many users), the enabling bits value will be different for each
user, and tied to that user's public/private keys. Because of this,
licenses are not transferable from one user to another, even though
the media files themselves are (the new user must obtain his own
license from the license server).
We go through an example now of finding a content key. In this
example, we have identified our public and private keys as the
following values:
Public key x: 1957f96f3327a25bba52166ad7fcc74087b9734b
Public key y: 8939e1b1ed988182d34d17ebbcb0e03a82d062e7
Private key: 757ff01b853496452eea0b0646c3a357a6f33509
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -