aboutsummaryrefslogtreecommitdiffstats
path: root/crypto_utils.py
blob: 0004ee9f89c9445f657e60b7e79de9186e724b3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import sys, binascii, utils, random
from Crypto.Cipher import DES3

iv = '\x00' * 8
PADDING = '\x80' + '\x00' * 7

def verify_card_cryptogram(session_key, host_challenge, 
    card_challenge, card_cryptogram):
    message = host_challenge + card_challenge
    expected = calculate_MAC(session_key, message, iv)
    
    print >>sys.stderr, "Original: %s" % binascii.b2a_hex(card_cryptogram)
    print >>sys.stderr, "Expected: %s" % binascii.b2a_hex(expected)
    
    return card_cryptogram == expected

def calculate_host_cryptogram(session_key, card_challenge, 
    host_challenge):
    message = card_challenge + host_challenge
    return calculate_MAC(session_key, message, iv)

def calculate_MAC(session_key, message, iv):
    print >>sys.stderr, "Doing MAC for: %s" % utils.hexdump(message, indent = 17)
    
    cipher = DES3.new(session_key, DES3.MODE_CBC, iv)
    block_count = len(message) / cipher.block_size
    for i in range(block_count):
        cipher.encrypt(message[i*cipher.block_size:(i+1)*cipher.block_size])
    
    last_block_length = len(message) % cipher.block_size
    last_block = (message[len(message)-last_block_length:]+PADDING)[:cipher.block_size]
    
    return cipher.encrypt( last_block )

def get_derivation_data(host_challenge, card_challenge):
    return card_challenge[4:8] + host_challenge[:4] + \
        card_challenge[:4] + host_challenge[4:8]

def get_session_key(auth_key, host_challenge, card_challenge):
    cipher = DES3.new(auth_key, DES3.MODE_ECB)
    return cipher.encrypt(get_derivation_data(host_challenge, card_challenge))

def generate_host_challenge():
    random.seed()
    return "".join([chr(random.randint(0,255)) for e in range(8)])

def andstring(string1, string2):
    if len(string1) != len(string2):
        raise ValueError, "string1 and string2 must be of equal length"
    result = []
    for i in range(len(string1)):
        result.append( chr(ord(string1[i]) & ord(string2[i])) )
    return "".join(result)
    
if __name__ == "__main__":
    default_key = binascii.a2b_hex("404142434445464748494A4B4C4D4E4F")
    
    host_chal = binascii.a2b_hex("".join("89 45 19 BF BC 1A 5B D8".split()))
    card_chal = binascii.a2b_hex("".join("27 4D B7 EA CA 66 CE 44".split()))
    card_crypto = binascii.a2b_hex("".join("8A D4 A9 2D 9B 6B 24 E0".split()))
    
    session_key = get_session_key(default_key, host_chal, card_chal)
    print "Session-Key:  ", utils.hexdump(session_key)
    
    print verify_card_cryptogram(session_key, host_chal, card_chal, card_crypto)
    
    host_crypto = calculate_host_cryptogram(session_key, card_chal, host_chal)
    print "Host-Crypto:  ", utils.hexdump( host_crypto )

    external_authenticate = binascii.a2b_hex("".join("84 82 01 00 10".split())) + host_crypto
    print utils.hexdump(calculate_MAC(session_key, external_authenticate, iv))