Ole Andre Vadla Ravnaas (oleavr) <oleavr gmail com> |
Sunday, September 24 2006 13:15.41 CDT |
Just finished reverse-engineering the new authentication scheme introduced by MSNP15 (which appeared in the Windows Live Messenger 8.1 betas). No decompiled code was touched at all, oSpy was used exclusively to figure out everything. So here you go, a tiny python implementation that should be fairly self-explanatory.
import struct
from base64 import standard_b64encode, standard_b64decode
from Crypto.Hash import HMAC, SHA
from Crypto.Cipher import DES3
from Crypto.Util import randpool
CRYPT_MODE_CBC = 1
CALC_3DES = 0x6603
CALG_SHA1 = 0x8004
def mbi_encrypt(key, nonce):
def derive_key(key, magic):
hash1 = HMAC.new(key, magic, SHA).digest()
hash2 = HMAC.new(key, hash1 + magic, SHA).digest()
hash3 = HMAC.new(key, hash1, SHA).digest()
hash4 = HMAC.new(key, hash3 + magic, SHA).digest()
return hash2 + hash4[0:4]
#
# Read key and generate two derived keys
#
key1 = standard_b64decode(key)
key2 = derive_key(key1, "WS-SecureConversationSESSION KEY HASH")
key3 = derive_key(key1, "WS-SecureConversationSESSION KEY ENCRYPTION")
#
# Create a HMAC-SHA-1 hash of nonce using key2
#
hash = HMAC.new(key2, nonce, SHA).digest()
#
# Encrypt nonce with DES3 using key3
#
# IV: 8 bytes of random data
iv = randpool.KeyboardRandomPool().get_bytes(8)
obj = DES3.new(key3, DES3.MODE_CBC, iv)
# XXX: win32's Crypt API seems to pad the input with 0x08 bytes to align on 72/36/18/9 boundary
ciph = obj.encrypt(nonce + "\x08\x08\x08\x08\x08\x08\x08\x08")
#
# Generate the blob
#
blob = struct.pack("<LLLLLLL", 28, CRYPT_MODE_CBC, CALC_3DES, CALG_SHA1,
len(iv), len(hash), len(ciph))
blob += iv + hash + ciph
return standard_b64encode(blob)
So the new authentication scheme basically goes like this:
1. Connect to the notification server as usual, but when sending the initial USR, you should send:
>> USR 19 SSO I [email protected]
and in the reply you get the nonce as the last parameter, and the policy parameter should be set to MBI:
<< USR 19 SSO S MBI <nonce>
2. Authenticate with Passport 3.0 (documented in MSNPiki), requesting a token for "messengerclear.live.com" with policy URI set to "MBI". In the response, store the security-token (RequestedSecurityToken.BinarySecurityToken) and proof-token (RequestedProofToken.BinarySecret).
3. Call mbi_encrypt() with key=proof-token and nonce=nonce, and store the base64-encoded blob returned.
4. Send the final USR to the notification server:
>> USR 20 SSO S <security-token> <blob>
and, if successful you should receive:
<< USR 20 OK [email protected] 1 0
|