~ubuntu-branches/ubuntu/utopic/bittornado/utopic

« back to all changes in this revision

Viewing changes to BitTornado/BTcrypto.py

  • Committer: Bazaar Package Importer
  • Author(s): Cameron Dale
  • Date: 2008-07-19 16:08:44 UTC
  • mfrom: (0.1.14 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080719160844-nnmp02ar9pri55v1
Tags: 0.3.18-7
* Refresh all the quilt patches (Closes: #485320)
* Update standards version to 3.8.0
  - Add a README.source file pointing to the quilt documentation
* medium urgency to get it into lenny

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Written by John Hoffman
 
2
# based on code by Uoti Urpala
 
3
# see LICENSE.txt for license information
 
4
 
 
5
from __future__ import generators   # for python 2.2
 
6
from random import randrange,randint,seed
 
7
try:
 
8
    from os import urandom
 
9
except:
 
10
    seed()
 
11
    urandom = lambda x: ''.join([chr(randint(0,255)) for i in xrange(x)])
 
12
from sha import sha
 
13
 
 
14
try:
 
15
    True
 
16
except:
 
17
    True = 1
 
18
    False = 0
 
19
    
 
20
try:
 
21
    from Crypto.Cipher import ARC4
 
22
    CRYPTO_OK = True
 
23
except:
 
24
    CRYPTO_OK = False
 
25
 
 
26
KEY_LENGTH = 160
 
27
DH_PRIME = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563
 
28
PAD_MAX = 200 # less than protocol maximum, and later assumed to be < 256
 
29
DH_BYTES = 96
 
30
 
 
31
def bytetonum(x):
 
32
    return long(x.encode('hex'), 16)
 
33
 
 
34
def numtobyte(x):
 
35
    x = hex(x).lstrip('0x').rstrip('Ll')
 
36
    x = '0'*(192 - len(x)) + x
 
37
    return x.decode('hex')
 
38
 
 
39
class Crypto:
 
40
    def __init__(self, initiator, disable_crypto = False):
 
41
        self.initiator = initiator
 
42
        self.disable_crypto = disable_crypto
 
43
        if not disable_crypto and not CRYPTO_OK:
 
44
            raise NotImplementedError, "attempt to run encryption w/ none installed"
 
45
        self.privkey = bytetonum(urandom(KEY_LENGTH/8))
 
46
        self.pubkey = numtobyte(pow(2, self.privkey, DH_PRIME))
 
47
        self.keylength = DH_BYTES
 
48
        self._VC_pattern = None
 
49
 
 
50
    def received_key(self, k):
 
51
        self.S = numtobyte(pow(bytetonum(k), self.privkey, DH_PRIME))
 
52
        self.block3a = sha('req1'+self.S).digest()
 
53
        self.block3bkey = sha('req3'+self.S).digest()
 
54
        self.block3b = None
 
55
 
 
56
    def _gen_block3b(self, SKEY):
 
57
        a = sha('req2'+SKEY).digest()
 
58
        return ''.join([ chr(ord(a[i])^ord(self.block3bkey[i]))
 
59
                         for i in xrange(20) ])
 
60
 
 
61
    def test_skey(self, s, SKEY):
 
62
        block3b = self._gen_block3b(SKEY)
 
63
        if block3b != s:
 
64
            return False
 
65
        self.block3b = block3b
 
66
        if not self.disable_crypto:
 
67
            self.set_skey(SKEY)
 
68
        return True
 
69
 
 
70
    def set_skey(self, SKEY):
 
71
        if not self.block3b:
 
72
            self.block3b = self._gen_block3b(SKEY)
 
73
        crypta = ARC4.new(sha('keyA'+self.S+SKEY).digest())
 
74
        cryptb = ARC4.new(sha('keyB'+self.S+SKEY).digest())
 
75
        if self.initiator:
 
76
            self.encrypt = crypta.encrypt
 
77
            self.decrypt = cryptb.decrypt
 
78
        else:
 
79
            self.encrypt = cryptb.encrypt
 
80
            self.decrypt = crypta.decrypt
 
81
        self.encrypt('x'*1024)  # discard first 1024 bytes
 
82
        self.decrypt('x'*1024)
 
83
 
 
84
    def VC_pattern(self):
 
85
        if not self._VC_pattern:
 
86
            self._VC_pattern = self.decrypt('\x00'*8)
 
87
        return self._VC_pattern
 
88
 
 
89
 
 
90
    def read(self, s):
 
91
        self._read(self.decrypt(s))
 
92
 
 
93
    def write(self, s):
 
94
        self._write(self.encrypt(s))
 
95
 
 
96
    def setrawaccess(self, _read, _write):
 
97
        self._read = _read
 
98
        self._write = _write
 
99
 
 
100
    def padding(self):
 
101
        return urandom(randrange(PAD_MAX-16)+16)
 
102
     
 
103