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
|
2019-10-16 20:59:31 +00:00
|
|
|
import sys
|
|
|
|
|
|
|
|
### Python3 compatibility
|
|
|
|
if sys.version_info < (3, ):
|
|
|
|
|
|
|
|
def makebyte(x):
|
|
|
|
return x
|
|
|
|
|
|
|
|
def makestring(x):
|
|
|
|
return x
|
|
|
|
else:
|
|
|
|
import codecs
|
|
|
|
|
|
|
|
def makebyte(x):
|
|
|
|
return codecs.latin_1_encode(x)[0]
|
|
|
|
|
|
|
|
def makestring(x):
|
|
|
|
return codecs.latin_1_decode(x)[0]
|
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):
|
2019-10-16 20:59:31 +00:00
|
|
|
aes_cipher = AES.new(key, AES.MODE_CBC, makebyte('\0' * 16))
|
2013-02-04 02:02:33 +00:00
|
|
|
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):
|
2019-10-16 20:59:31 +00:00
|
|
|
aes_cipher = AES.new(key, AES.MODE_CBC, makebyte('\0' * 16))
|
2013-02-04 02:02:33 +00:00
|
|
|
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(
|
2019-10-16 20:20:22 +00:00
|
|
|
(aes_cbc_encrypt_a32(a[i:i + 4], key) for i in range(0, len(a), 4)), ()
|
|
|
|
)
|
2013-02-04 02:02:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
def decrypt_key(a, key):
|
|
|
|
return sum(
|
2019-10-16 20:20:22 +00:00
|
|
|
(aes_cbc_decrypt_a32(a[i:i + 4], key) for i in range(0, len(a), 4)), ()
|
|
|
|
)
|
2013-02-04 02:02:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
def encrypt_attr(attr, key):
|
2019-10-16 20:59:31 +00:00
|
|
|
attr = makebyte('MEGA' + json.dumps(attr))
|
2013-02-04 02:02:33 +00:00
|
|
|
if len(attr) % 16:
|
2019-10-16 20:59:31 +00:00
|
|
|
attr += b'\0' * (16 - len(attr) % 16)
|
2013-02-04 02:02:33 +00:00
|
|
|
return aes_cbc_encrypt(attr, a32_to_str(key))
|
|
|
|
|
|
|
|
|
|
|
|
def decrypt_attr(attr, key):
|
2019-10-16 20:59:31 +00:00
|
|
|
attr = aes_cbc_decrypt(attr, a32_to_str(key))
|
|
|
|
attr = makestring(attr)
|
|
|
|
attr = attr.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):
|
2019-10-16 20:59:31 +00:00
|
|
|
if isinstance(b, str):
|
|
|
|
b = makebyte(b)
|
2013-02-04 02:02:33 +00:00
|
|
|
if len(b) % 4:
|
|
|
|
# pad to multiple of 4
|
2019-10-16 20:59:31 +00:00
|
|
|
b += b'\0' * (4 - len(b) % 4)
|
2013-02-04 02:02:33 +00:00
|
|
|
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):
|
2019-10-16 20:20:22 +00:00
|
|
|
data += '==' [(2 - len(data) * 3) % 4:]
|
2013-02-04 02:02:33 +00:00
|
|
|
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)
|
2019-10-16 20:59:31 +00:00
|
|
|
data = makestring(data)
|
2013-02-04 02:02:33 +00:00
|
|
|
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):
|
2013-05-05 17:48:23 +00:00
|
|
|
p = 0
|
|
|
|
s = 0x20000
|
2019-10-16 20:20:22 +00:00
|
|
|
while p + s < size:
|
|
|
|
yield (p, s)
|
2013-05-05 17:48:23 +00:00
|
|
|
p += s
|
|
|
|
if s < 0x100000:
|
|
|
|
s += 0x20000
|
2019-10-16 20:20:22 +00:00
|
|
|
yield (p, size - p)
|
2013-02-04 21:15:18 +00:00
|
|
|
|
2013-06-27 21:27:58 +00:00
|
|
|
|
2013-02-04 21:15:18 +00:00
|
|
|
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
|