megapy/mega/crypto.py

150 lines
3.4 KiB
Python
Raw Normal View History

2013-02-04 02:02:33 +00:00
from Crypto.Cipher import AES
import json
import base64
import struct
import binascii
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-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-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-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-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-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-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')
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-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-04 02:02:33 +00:00
def base64_to_a32(s):
return str_to_a32(base64_url_decode(s))
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-04 02:02:33 +00:00
def a32_to_base64(a):
return base64_url_encode(a32_to_str(a))
2013-02-04 02:02:33 +00:00
def get_chunks(size):
p = 0
s = 0x20000
2019-10-16 20:20:22 +00:00
while p + s < size:
yield (p, s)
p += s
if s < 0x100000:
s += 0x20000
2019-10-16 20:20:22 +00:00
yield (p, size - p)
2013-06-27 21:27:58 +00:00
def make_id(length):
text = ''
possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for i in range(length):
text += random.choice(possible)
return text