2013-02-04 02:02:33 +00:00
|
|
|
from Crypto.Cipher import AES
|
|
|
|
import json
|
|
|
|
import base64
|
|
|
|
import struct
|
|
|
|
import binascii
|
2013-02-04 21:15:18 +00:00
|
|
|
import random
|
2013-02-04 02:02:33 +00:00
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def aes_cbc_encrypt(data, key):
|
|
|
|
aes_cipher = AES.new(key, AES.MODE_CBC, '\0' * 16)
|
|
|
|
return aes_cipher.encrypt(data)
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def aes_cbc_decrypt(data, key):
|
|
|
|
aes_cipher = AES.new(key, AES.MODE_CBC, '\0' * 16)
|
|
|
|
return aes_cipher.decrypt(data)
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def aes_cbc_encrypt_a32(data, key):
|
|
|
|
return str_to_a32(aes_cbc_encrypt(a32_to_str(data), a32_to_str(key)))
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def aes_cbc_decrypt_a32(data, key):
|
|
|
|
return str_to_a32(aes_cbc_decrypt(a32_to_str(data), a32_to_str(key)))
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def stringhash(str, aeskey):
|
|
|
|
s32 = str_to_a32(str)
|
|
|
|
h32 = [0, 0, 0, 0]
|
|
|
|
for i in range(len(s32)):
|
|
|
|
h32[i % 4] ^= s32[i]
|
|
|
|
for r in range(0x4000):
|
|
|
|
h32 = aes_cbc_encrypt_a32(h32, aeskey)
|
|
|
|
return a32_to_base64((h32[0], h32[2]))
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def prepare_key(arr):
|
|
|
|
pkey = [0x93C467E3, 0x7DB0C7A4, 0xD1BE3F81, 0x0152CB56]
|
|
|
|
for r in range(0x10000):
|
|
|
|
for j in range(0, len(arr), 4):
|
|
|
|
key = [0, 0, 0, 0]
|
|
|
|
for i in range(4):
|
|
|
|
if i + j < len(arr):
|
|
|
|
key[i] = arr[i + j]
|
|
|
|
pkey = aes_cbc_encrypt_a32(pkey, key)
|
|
|
|
return pkey
|
|
|
|
|
|
|
|
|
|
|
|
def encrypt_key(a, key):
|
|
|
|
return sum(
|
2013-02-09 18:29:58 +00:00
|
|
|
(aes_cbc_encrypt_a32(a[i:i + 4], key)
|
2013-02-04 02:02:33 +00:00
|
|
|
for i in range(0, len(a), 4)), ())
|
|
|
|
|
|
|
|
|
|
|
|
def decrypt_key(a, key):
|
|
|
|
return sum(
|
2013-02-09 18:29:58 +00:00
|
|
|
(aes_cbc_decrypt_a32(a[i:i + 4], key)
|
2013-02-04 02:02:33 +00:00
|
|
|
for i in range(0, len(a), 4)), ())
|
|
|
|
|
|
|
|
|
|
|
|
def encrypt_attr(attr, key):
|
|
|
|
attr = 'MEGA' + json.dumps(attr)
|
|
|
|
if len(attr) % 16:
|
|
|
|
attr += '\0' * (16 - len(attr) % 16)
|
|
|
|
return aes_cbc_encrypt(attr, a32_to_str(key))
|
|
|
|
|
|
|
|
|
|
|
|
def decrypt_attr(attr, key):
|
|
|
|
attr = aes_cbc_decrypt(attr, a32_to_str(key)).rstrip('\0')
|
2013-02-06 15:55:29 +00:00
|
|
|
return json.loads(attr[4:]) if attr[:6] == 'MEGA{"' else False
|
2013-02-04 02:02:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
def a32_to_str(a):
|
|
|
|
return struct.pack('>%dI' % len(a), *a)
|
|
|
|
|
|
|
|
|
|
|
|
def str_to_a32(b):
|
|
|
|
if len(b) % 4:
|
|
|
|
# pad to multiple of 4
|
|
|
|
b += '\0' * (4 - len(b) % 4)
|
|
|
|
return struct.unpack('>%dI' % (len(b) / 4), b)
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def mpi_to_int(s):
|
|
|
|
return int(binascii.hexlify(s[2:]), 16)
|
|
|
|
|
|
|
|
|
|
|
|
def base64_url_decode(data):
|
|
|
|
data += '=='[(2 - len(data) * 3) % 4:]
|
|
|
|
for search, replace in (('-', '+'), ('_', '/'), (',', '')):
|
|
|
|
data = data.replace(search, replace)
|
|
|
|
return base64.b64decode(data)
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def base64_to_a32(s):
|
|
|
|
return str_to_a32(base64_url_decode(s))
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def base64_url_encode(data):
|
|
|
|
data = base64.b64encode(data)
|
|
|
|
for search, replace in (('+', '-'), ('/', '_'), ('=', '')):
|
|
|
|
data = data.replace(search, replace)
|
|
|
|
return data
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def a32_to_base64(a):
|
|
|
|
return base64_url_encode(a32_to_str(a))
|
|
|
|
|
2013-02-09 18:29:58 +00:00
|
|
|
|
2013-02-04 02:02:33 +00:00
|
|
|
def get_chunks(size):
|
|
|
|
chunks = {}
|
|
|
|
p = pp = 0
|
|
|
|
i = 1
|
|
|
|
|
|
|
|
while i <= 8 and p < size - i * 0x20000:
|
|
|
|
chunks[p] = i * 0x20000
|
|
|
|
pp = p
|
|
|
|
p += chunks[p]
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
while p < size:
|
|
|
|
chunks[p] = 0x100000
|
|
|
|
pp = p
|
|
|
|
p += chunks[p]
|
|
|
|
|
|
|
|
chunks[pp] = size - pp
|
|
|
|
if not chunks[pp]:
|
|
|
|
del chunks[pp]
|
|
|
|
|
|
|
|
return chunks
|
2013-02-04 21:15:18 +00:00
|
|
|
|
|
|
|
# more general functions
|
|
|
|
def make_id(length):
|
|
|
|
text = ''
|
|
|
|
possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
|
|
|
for i in range(length):
|
|
|
|
text += random.choice(possible)
|
2013-02-06 15:55:29 +00:00
|
|
|
return text
|