mirror of
https://github.com/valitydev/APT_CyberCriminal_Campagin_Collections.git
synced 2024-11-07 09:08:58 +00:00
405 lines
7.3 KiB
Python
405 lines
7.3 KiB
Python
#!/usr/bin/env python
|
|
|
|
#################################################################################
|
|
|
|
# Python implementation of the Tiny Encryption Algorithm (TEA)
|
|
|
|
# By Moloch
|
|
|
|
#
|
|
|
|
# About: TEA has a few weaknesses. Most notably, it suffers from
|
|
|
|
# equivalent keys each key is equivalent to three others,
|
|
|
|
# which means that the effective key size is only 126 bits.
|
|
|
|
# As a result, TEA is especially bad as a cryptographic hash
|
|
|
|
# function. This weakness led to a method for hacking Microsoft's
|
|
|
|
# Xbox game console (where I first encountered it), where the
|
|
|
|
# cipher was used as a hash function. TEA is also susceptible
|
|
|
|
# to a related-key attack which requires 2^23 chosen plaintexts
|
|
|
|
# under a related-key pair, with 2^32 time complexity.
|
|
|
|
#
|
|
|
|
# Block size: 64bits
|
|
|
|
# Key size: 128bits
|
|
|
|
#
|
|
|
|
##################################################################################
|
|
|
|
|
|
|
|
import os
|
|
|
|
import getpass
|
|
|
|
import platform
|
|
|
|
import struct
|
|
|
|
|
|
from random import choice
|
|
|
|
from hashlib import sha256
|
|
|
|
from ctypes import c_uint32
|
|
|
|
from string import ascii_letters, digits
|
|
|
|
|
|
if platform.system().lower() in ['linux', 'darwin']:
|
|
|
|
INFO = "\033[1m\033[36m[*]\033[0m "
|
|
|
|
WARN = "\033[1m\033[31m[!]\033[0m "
|
|
|
|
else:
|
|
|
|
INFO = "[*] "
|
|
|
|
WARN = "[!] "
|
|
|
|
|
|
### Magical Constants
|
|
|
|
DELTA = 0x9e3779b9
|
|
|
|
SUMATION = 0xc6ef3720
|
|
|
|
ROUNDS = 32
|
|
|
|
BLOCK_SIZE = 2 # number of 32-bit ints
|
|
|
|
KEY_SIZE = 4
|
|
|
|
|
|
|
|
### Functions ###
|
|
|
|
def encrypt_block(block, key, verbose=False):
|
|
|
|
'''
|
|
|
|
Encrypt a single 64-bit block using a given key
|
|
|
|
@param block: list of two c_uint32s
|
|
|
|
@param key: list of four c_uint32s
|
|
|
|
'''
|
|
|
|
assert len(block) == BLOCK_SIZE
|
|
|
|
assert len(key) == KEY_SIZE
|
|
|
|
sumation = c_uint32(0)
|
|
|
|
delta = c_uint32(DELTA)
|
|
|
|
for index in range(0, ROUNDS):
|
|
|
|
sumation.value += delta.value
|
|
|
|
block[0].value += ((block[1].value << 4) + key[0].value) ^ (block[1].value + sumation.value) ^ ((block[1].value >> 5) + key[1].value)
|
|
|
|
block[1].value += ((block[0].value << 4) + key[2].value) ^ (block[0].value + sumation.value) ^ ((block[0].value >> 5) + key[3].value)
|
|
|
|
if verbose: print("\t--> Encrypting block round %d of %d" % (index + 1, ROUNDS))
|
|
|
|
return block
|
|
|
|
|
|
def decrypt_block(block, key, verbose=False):
|
|
|
|
'''
|
|
|
|
Decrypt a single 64-bit block using a given key
|
|
|
|
@param block: list of two c_uint32s
|
|
|
|
@param key: list of four c_uint32s
|
|
|
|
'''
|
|
|
|
assert len(block) == BLOCK_SIZE
|
|
|
|
assert len(key) == KEY_SIZE
|
|
|
|
sumation = c_uint32(SUMATION)
|
|
|
|
delta = c_uint32(DELTA)
|
|
|
|
for index in range(0, ROUNDS):
|
|
|
|
block[1].value -= ((block[0].value << 4) + key[2].value) ^ (block[0].value + sumation.value) ^ ((block[0].value >> 5) + key[3].value);
|
|
|
|
block[0].value -= ((block[1].value << 4) + key[0].value) ^ (block[1].value + sumation.value) ^ ((block[1].value >> 5) + key[1].value);
|
|
|
|
sumation.value -= delta.value
|
|
|
|
if verbose: print("\t<-- Decrypting block round %d of %d" % (index + 1, ROUNDS))
|
|
|
|
return block
|
|
|
|
|
|
def to_c_array(data):
|
|
|
|
''' Converts a string to a list of c_uint32s '''
|
|
|
|
c_array = []
|
|
|
|
for index in range(0, len(data)/4):
|
|
|
|
chunk = data[index*4:index*4+4]
|
|
|
|
packed = struct.unpack(">L", chunk)[0]
|
|
|
|
c_array.append(c_uint32(packed))
|
|
|
|
return c_array
|
|
|
|
|
|
def to_string(c_array):
|
|
|
|
''' Converts a list of c_uint32s to a Python (ascii) string '''
|
|
|
|
output = ''
|
|
|
|
for block in c_array:
|
|
|
|
output += struct.pack(">L", block.value)
|
|
|
|
return output
|
|
|
|
|
|
def random_chars(nchars):
|
|
|
|
chars = ''
|
|
|
|
for n in range(0, nchars):
|
|
|
|
chars += choice(ascii_letters + digits)
|
|
|
|
return chars
|
|
|
|
|
|
def add_padding(data, verbose=False):
|
|
|
|
pad_delta = 4 - (len(data) % 4)
|
|
|
|
if verbose:
|
|
|
|
print(INFO + "Padding delta: %d" % pad_delta)
|
|
|
|
data += random_chars(pad_delta)
|
|
|
|
data += "%s%d" % (random_chars(3), pad_delta)
|
|
|
|
return data
|
|
|
|
|
|
def encrypt(data, key, verbose=False):
|
|
|
|
'''
|
|
|
|
Encrypt string using TEA algorithm with a given key
|
|
|
|
'''
|
|
|
|
data = add_padding(data, verbose)
|
|
|
|
data = to_c_array(data)
|
|
|
|
key = to_c_array(key.encode('ascii', 'ignore'))
|
|
|
|
cipher_text = []
|
|
|
|
for index in range(0, len(data), 2):
|
|
|
|
if verbose:
|
|
|
|
print(INFO + "Encrypting block %d" % index)
|
|
|
|
block = data[index:index + 2]
|
|
|
|
block = encrypt_block(block, key, verbose)
|
|
|
|
for uint in block:
|
|
|
|
cipher_text.append(uint)
|
|
|
|
if verbose:
|
|
|
|
print(INFO + "Encryption completed successfully")
|
|
|
|
return to_string(cipher_text)
|
|
|
|
|
|
def decrypt(data, key, verbose=False):
|
|
|
|
data = to_c_array(data)
|
|
|
|
key = to_c_array(key.encode('ascii', 'ignore'))
|
|
|
|
plain_text = []
|
|
|
|
for index in range(0, len(data), 2):
|
|
|
|
if verbose:
|
|
|
|
print(INFO + "Encrypting block %d" % index)
|
|
|
|
block = data[index:index + 2]
|
|
|
|
decrypted_block = decrypt_block(block, key, verbose)
|
|
|
|
for uint in decrypted_block:
|
|
|
|
plain_text.append(uint)
|
|
|
|
data = to_string(plain_text)
|
|
|
|
if verbose:
|
|
|
|
print(INFO + "Decryption compelted successfully")
|
|
|
|
return data
|
|
|
|
|
|
def get_key(password=''):
|
|
|
|
''' Generate a key based on user password '''
|
|
|
|
if 0 == len(password):
|
|
|
|
password = getpass.getpass(INFO + "Password: ")
|
|
|
|
sha = sha256()
|
|
|
|
sha.update(password + "Magic Static Salt")
|
|
|
|
sha.update(sha.hexdigest())
|
|
|
|
return ''.join([char for char in sha.hexdigest()[::4]])
|
|
|
|
|
|
def encrypt_file(fpath, key, verbose=False):
|
|
|
|
with open(fpath, 'rb+') as fp:
|
|
|
|
data = fp.read()
|
|
|
|
cipher_text = encrypt(data, key, verbose)
|
|
|
|
fp.seek(0)
|
|
|
|
fp.write(cipher_text)
|
|
|
|
fp.close()
|
|
|
|
|
|
def decrypt_file(fpath, key, verbose=False):
|
|
|
|
with open(fpath, 'rb+') as fp:
|
|
|
|
data = fp.read()
|
|
|
|
plain_text = decrypt(data, key, verbose)
|
|
|
|
fp.close()
|
|
|
|
fp = open(fpath, 'w')
|
|
|
|
fp.write(plain_text)
|
|
|
|
fp.close()
|
|
|
|
|
|
|
|
### UI Code ###
|
|
|
|
if __name__ == '__main__':
|
|
|
|
from argparse import ArgumentParser
|
|
|
|
parser = ArgumentParser(
|
|
|
|
description='Python implementation of the TEA cipher',
|
|
|
|
)
|
|
|
|
parser.add_argument('-e', '--encrypt',
|
|
|
|
help='encrypt a file',
|
|
|
|
dest='epath',
|
|
|
|
default=None
|
|
|
|
)
|
|
|
|
parser.add_argument('-d', '--decrypt',
|
|
|
|
help='decrypt a file',
|
|
|
|
dest='dpath',
|
|
|
|
default=None
|
|
|
|
)
|
|
|
|
parser.add_argument('--verbose',
|
|
|
|
help='display verbose output',
|
|
|
|
default=False,
|
|
|
|
action='store_true',
|
|
|
|
dest='verbose'
|
|
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.epath is None and args.dpath is None:
|
|
|
|
print('Error: Must use --encrypt or --decrypt')
|
|
|
|
elif args.epath is not None:
|
|
|
|
print(WARN + 'Encrypt Mode: The file will be overwritten')
|
|
|
|
if os.path.exists(args.epath) and os.path.isfile(args.epath):
|
|
|
|
key = get_key()
|
|
|
|
encrypt_file(args.epath, key, args.verbose)
|
|
|
|
else:
|
|
|
|
print(WARN + 'Error: target does not exist, or is not a file')
|
|
|
|
elif args.dpath is not None:
|
|
|
|
print(WARN + 'Decrypt Mode: The file will be overwritten')
|
|
|
|
if os.path.exists(args.dpath) and os.path.isfile(args.dpath):
|
|
|
|
key = get_key()
|
|
|
|
decrypt_file(args.dpath, key, args.verbose)
|
|
|
|
else:
|
|
|
|
print(WARN + 'Error: target does not exist, or is not a file')
|