⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 technical

📁 vc_net.zip 网络通信开发包vc源码 一套易用的网络通信包
💻
📖 第 1 页 / 共 2 页
字号:
We're looking at a file RIAALuvsMe.wma, and find in the header the
following bit of XML:

		 <KID>nA67jM7dNGIUQIkP5v7hSQ==</KID>

The actual KID seems to be a Base64 encoding of a GUID, but it is
treated as a string (uninterpreted) by the software, so the origin
doesn't seem to make much difference.

The license is inside the drmv2.lic file, which is a structured "DOC
file", meaning it can be accessed through the IStorage and IStream
interfaces (and it can be browsed by the Microsoft Visual Studio "DOC
File Viewer" tool if you're curious).  The top level drmv2.lic file
has a lower-level IStorage object for each KID, which can contain a
set of licenses for each KID.  In order to guarantee valid IStorage
names, the KID is first processed to change all '/' characters to '@',
and all '!' to '%'.  The names of the IStream objects containing the
licenses again look like Base64 encoded GUIDs, which turn out to be
the LID (license ID?)  element stored in the license.  This can be
verified once the license is obtained, but we're not sure how to
generate LID's from the content header information, and so can't
directly open the appropriate LID stream.  Instead, we simply
enumerate through all available streams for this KID, testing each one
for a PUBKEY element (see below) that we know.  This is taken to be
the license for this content.  While this is really just a guess as to
the proper workings, it seems to work fine in all our tests.

Inside the license we find the following XML (this has been formatted
so that it's easier to look at - in the actual file this would all be
on one line).

  <ENABLINGBITS>
    <ALGORITHM type="MSDRM"></ALGORITHM>
    <PUBKEY type="machine">
       S3O5h0DH*NdqFlK6W6InM2*5VxnnYtCCOuCwvOsXTdOCgZjtseE5iQ==
    </PUBKEY>
    <VALUE>
       VEsbPedfwrybrpkg0fhoOfe5eB9ef0R7QTxgX7NbtMIFK!h*4Pk7ek
       PUqlDIRqYwQkgCGE0r0qtQdCUYszT!b7XedCIpsApQjstaFmafahM=
    </VALUE>
    <SIGNATURE>
       KpxCm6lSXH8dTPI359jToftSEuLiP9v*zpHAy!kDEhlYkw6mkfQzlg==
    </SIGNATURE>
  </ENABLINGBITS>

The SIGNATURE element above is just random garbage.  We didn't make a
real signature for this example (among other things, we don't have a
certified public key, which would have to follow this in a real
license.  Requiring such a signature keeps people from creating their
own licenses, since only those that have been issued valid
certificates can do so).

First look at the PUBKEY part.  If this is run through a Base64
decoder (modified for the MS character set as described earlier) you
get the following binary values, shown below as a memory dump:

    0000: 4B 73 B9 87 40 C7 FC D7 6A 16 52 BA 5B A2 27 33 
    0010: 6F F9 57 19 E7 62 D0 82 3A E0 B0 BC EB 17 4D D3 
    0020: 82 81 98 ED B1 E1 39 89   

Notice how this is exactly our public key from above, stored in little
endian order!  So this license is for our machine.

Next, take the VALUE element above, run it through a Base64 decoder,
and interpret the 80 byte result as 4 20-byte values stored in little
endian order.  These four numbers are as follows:

     Encrypted u.x: & 1f78b9f73968f8d12099ae9bbcc25fe73d1b4b54
               u.y: & 7a3bf9e07fe82b05c2b45bb35f603c417b447f5e
               v.x: & 18257450abd22b4d1802484230a646c850aad443
               v.y: & 136a9f66165acb8e500ab0292274deb56ffe34b3

To decrypt this value, first we multiply the point u by our private
key, resulting in the point

	     x: 399c72d525a9b65b7543a3e3adc88ce0f6a38db5
	     y: 66cfa6bdbfbb93b906b22deb36792363d8e8adc2

and then subtract this point from v to get

             x: c91590616b4b3707
	     y: 753e24e50d437e147b4998376f163dc27b639a7a

Since x is so short, we have almost certainly gotten our content key.
Writing in storage order (little endian), x is

   0000: 07 37 4B 6B 61 90 15 C9

which means that the content key has length 7 (from the first byte),
and the actual key is the string of bytes 374B6B619015C9.


DECRYPTING THE CONTENT

The content encryption process is simpler to explain than decryption,
so we start with that.  The content key is not used directly, but is
processed for several different uses.  First, the content key is
hashed using the SHA-1 hashing algorithm, producing a 20-bit output.
The first 12 bytes of this output are used as an RC4 key, and a block
of 16 words (or 64 bytes) of zeros is encrypted.  The least
significant bits of the first 12 words of this output are all set, and
are used as the MultiSwap key.  The next 2 words are the encryption
in-whitening mask and the next 2 words are the encryption
out-whitening mask (this will be explained later).  The last 8 bytes
of the original SHA-1 hash output are used as a DES key.

To encrypt the content so that packets can be accessed randomly (for
seeks), the content cannot be encrypted as one single stream.
However, to strengthen the cipher we also don't want to re-use the
same key for every packet.  To satisfy both of these goals, MS-DRM
uses the following scheme to encrypt a packet: First, the packet (with
size rounded down to a multiple of 8 bytes) is run through
MultiSwapMAC to produce a 64-bit MAC.  For some reason, the 32-bit
halves of this MAC are swapped before further processing.  Next, the
entire packet is RC4 encrypted using the swapped MAC as an 8-byte RC4
key.  The 8-byte MAC (with swapped halves) is then run through a
"whitened DES" by first XORing with the in-whitening mask, then
running through DES (using the DES key from the last paragraph), and
then XORing the result with the out-whitening mask.  The resulting 8
bytes are then placed in the final encrypted packet, overwriting the
last full 8-byte block (not the last 8 bytes of the packet, but
blocking the packet from the beginning into 8 byte pieces, and
overwriting the last full piece).

To decrypt such a packet, first locate the last full 8-byte block, run
it through the whitened DES decryption, and the result is used as an
RC4 key to decrypt the packet.  This will produce the correct packet
except for 8 bytes: those in the position of the last full 8-byte
block are wrong, since they were overwritten in the last phase of the
encryption.  However, by swapping the halves of the RC4 key, we have
the MAC for the original packet up to and including the original bytes
in this position.  Since the MAC is actually created out of a block
cipher, we can recover the original 8 bytes as follows: run the entire
packet through MultiSwapMAC up to the block in question, but not
including it.  This output is the next-to-last state seen by
MultiSwapMAC in the encryption MAC computation, and we just recovered
the final output of the MAC, so we can put these two values into the
block cipher decryption to obtain the original data of this 8-byte
block.  The original 8-bytes are placed back into the packet, and now
the entire original contents are restored!

This is a pretty clever scheme: by using a MAC constructed from a
block cipher, individual packet keys can be computed and encoded into
the encrypted packet with absolutely no increase in space, and since
the size is maintained nothing in the structure of the content file
(describing packet sizes or other parameters) needs to be changed at
all.  The encrypted content can be completely transparent to
applications that deal with .wma files in a non-content-sensitive
manner.

We finish this section showing an example of content decryption, using
the content key from the previous paragraph.  We first process the
content key by running it through SHA-1 to obtain

    15 CB 92 F9 97 2E C8 75 29 4F 12 65    36 B6 C6 DB AC A2 40 35

The first 12 bytes are used as an RC4 key to encrypt a block of all
zeros, giving

    0000: 80 0A 2D 48 D1 FD 7E ED   83 69 4A 7D A5 D5 EE C4
    0010: 4E E1 64 52 D1 71 98 26   9A F3 14 E3 51 C8 B6 92
    0020: D4 93 E4 57 97 6D 63 EF   0E 06 07 54 F7 DD ED 38
    0030: E8 CA A0 D0 83 13 F1 DB   C1 70 AE 56 61 7D FB 94

The first 48 bytes are interpreted as 12 32-bit words, stored little
endian, and are saved as the MultiSwap key after setting all least
significant bits.  So the key values are k[0]=0x482D0A81,
k[1]=0xED7EFDD1, etc.  The last 16 bytes of the RC4-encrypted block
are the whitening masks for DES, and the key for DES is given as the
last 8 bytes of the SHA-1 hash value.

Assume we get a packet with size 1450 bytes, which is 181 8-byte
blocks followed by 2 additional bytes.  Numbering the byte positions
as 0 through 1449, we look at the bytes in positions 1440 through 1447
(the last full 8-byte block), and find that they are

		       A8 49 65 36 A2 33 18 09

XORing with the encryption out-whitening mask (the last 8 bytes from
the RC4-encrypted block above) we get

		       69 39 CB 60 C3 4E E3 9D

and decrypting with DES using key 36 B6 C6 DB AC A2 40 35 gives

		       FD EF 98 7D 8B 77 72 FD

and finally XORing with the encryption in-whitening mask (the
next-to-last 8-byte piece in the RC4-encrypted block above) gives

		       15 25 38 AD 08 64 83 26

This is then used as an RC4 key to decrypt the packet.  To replace
bytes at positions 1440 through 1447 with the correct values, take
the RC4 value and swap the words around to get

		       08 64 83 26 15 25 38 AD

This is the MultiSwapMAC of the input packet using bytes 0 through
1447.  We run bytes 0 through 1439 through MultiSwapMAC to get

		       D9 F7 D9 53 A9 6E 14 D9

and then use this as the state input, along with the original MAC
output as the data input to the MultiSwapDecode function to obtain

		       DA 05 D8 EB 97 FE 1E 7B

These 8 bytes are placed in positions 1440 through 1447, and then the
entire original packet is restored.


OTHER ISSUES

Communication between different DLL modules is encrypted and checked
at multiple points.  This works roughly as follows:  Objects are
initialized with communication parameters by sending certified public
keys to the object you want to communicate with.  The second object
verifies these certificates, generates a random session key (which it
uses to generate a MultiSwap key in addition to the use as a session
key), and sends the encrypted session key back to the calling object.
Future "sensitive communication" is RC4 encrypted with the session key,
and run through MultiSwapMAC to verify integrity (after padding with
zeros to make the data a multiple of 64 bits).  This is done for data
sent both to and from the object.

Presumably, this is done so that anyone monitoring parameters passed
between DLL modules wouldn't see any "sensitive data," although its
use for this purpose is pretty limited.  However, it does lead to some
interesting and strange situations: when blackbox is sent a packet to
decrypt, it decrypts it, and then immediately *re-encrypts* it using
the session key to send it back to the media player!  So in decrypting
a packet, the computer actually goes through a decrypt/encrypt/decrypt
sequence of operations!

One very important effect of this scheme is that Microsoft fully
controls who gets to write modules that interact with the basic
Microsoft media modules.  Without a certified public key (and the
corresponding private key) it is impossible to write a compatible DLL
that interfaces with their code.  Since Microsoft controls the issuing
of certified public keys, they also have complete control over who is
allowed to make compatible and competing products.  Microsoft's
reputation for being generous to competitors is well-known, so this
effectively gives Microsoft a technically guaranteed monopoly power.

Of course, these certificates and private keys must be distributed
with any "Microsoft blessed" software as well, and in fact exist in
the media player and blackbox DLLs.  They're not hard to extract, if
you know where to look, but I won't give them here.  They would be of
limited use anyway, since Microsoft also has a "revocation list"
mechanism built in to the Media player software, meaning that they can
revoke any of these certificates at their whim, remotely disabling any
software that depends on that certificate for communication.





-----BEGIN PGP SIGNATURE-----
Version: 2.6.2

iQCVAwUBO5qt3JCr1f2GXCalAQE8ygP9Gb4Dm0ZQ5GePjAIfMFyqYVtUNSUUfj7A
3ZLwbMwUtnRHeYDGWRJEqvJMPf4SujKHcwQL3LtefrhH7dOn6r4AyUQV6ymezpd/
AMY53ONufawU+T8YgilEe2WCDRc4Y/uDbQFZIhcPQ+H78nzFSvdj+FzQ7pKrxsIr
QWe1ZNP4xfY=
=WL0q
-----END PGP SIGNATURE-----

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -