--- a
+++ b/python/key_solver.py
@@ -0,0 +1,309 @@
+import itertools
+import multiprocessing
+import os
+import random
+import sys
+import time
+from datetime import datetime, timedelta
+
+from Crypto.Cipher import AES
+
+filename = 'emotiv_encrypted_data_UD20160103001874_2017-04-05.17-21-32.384061.csv'
+# filename = 'emotiv_encrypted_data_UD20160103001874_2017-04-05.17-42-23.292665.csv'
+# filename = 'emotiv_encrypted_data_SN201211150798GM_2017-04-05 17-51-45.771149.csv'
+serial_number = 'SN201211150798GM'
+iv = os.urandom(AES.block_size)
+
+# Probably need to expand this and probably use a serial brute force like approach, but meh
+# Lets just see if it works.
+charset = [char for char in serial_number[-4:]]
+charset.extend(['\x00', '\x10', 'H', 'T', 'B', 'P'])
+possible_combinations = len(charset) * 16 * 16
+
+
+# Credit http://stackoverflow.com/questions/11747254/python-brute-force-algorithm
+def next_value():
+    return (''.join(candidate)
+            for candidate in itertools.chain.from_iterable(itertools.product(charset, repeat=i)
+                                                           for i in range(16, 16 + 1)))
+
+
+def random_key(serial_number):
+    keyset = [serial_number[-5], serial_number[-4], serial_number[-3], serial_number[-2], serial_number[-1]]
+    # Probably need to expand this and probably use a serial brute force like approach, but meh
+    # Lets just see if it works.
+    emotiv_key_possiblities = ['\0', 'H', 'T', '\x10', 'B', 'P']
+    keyset.extend(emotiv_key_possiblities)
+    k = [random.choice(keyset) for value in range(0, 16)]
+    return AES.new(''.join(k), AES.MODE_ECB, iv), k
+
+
+def next_key(charset, previous_key):
+    k = [random.choice(charset) for value in range(0, 16)]
+
+    return AES.new(''.join(k), AES.MODE_ECB, iv), k
+
+
+# Make new crypto function match found key.
+# ['1', '0', '\x00', '\x00', 'H', '0', '8', '\x10', 'T', '0', '0', '\x10', '7', 'T', '8', '1']
+['B', '1', 'H', 'T', '1', 'P', '\x00', '4', '8', 'B', 'P', '7', 'T', '7', '1', 'P']
+
+
+def test_key():
+    return AES.new(''.join(['4', '\x00', '7', '\x15', '8', '\x00', '1', '\x0C', '8', '\x00', '7', 'D', '4', '\x00',
+                            '7', 'X']),
+                   AES.MODE_ECB, iv)
+
+
+def new_crypto_key(serial_number, verbose=False):
+    k = ['\0'] * 16
+    'UD20160103001874'
+    ['4', '7', '7', '8', '8', '8', '7', '1', '4', '1', '7', '7', '1', '1', '7', '4']
+    k[0] = serial_number[-1]
+    k[1] = serial_number[-2]
+    k[2] = serial_number[-2]
+    k[3] = serial_number[-3]
+    k[4] = serial_number[-3]
+    k[5] = serial_number[-3]
+    k[6] = serial_number[-2]
+    k[7] = serial_number[-4]
+    k[8] = serial_number[-1]
+    k[9] = serial_number[-4]
+    k[10] = serial_number[-2]
+    k[11] = serial_number[-2]
+    k[12] = serial_number[-4]
+    k[13] = serial_number[-4]
+    k[14] = serial_number[-2]
+    k[15] = serial_number[-1]
+    if verbose:
+        print("EmotivCrypto: Generated Crypto Key from Serial Number...\n"
+              "   Serial Number - {serial_number} \n"
+              "   AES KEY - {aes_key}".format(serial_number=serial_number, aes_key=k))
+    return AES.new(''.join(k), AES.MODE_ECB, iv), k
+
+
+def original_key(serial_number, is_research):
+    k = ['\0'] * 16
+    k[0] = serial_number[-1]
+    k[1] = '\0'
+    k[2] = serial_number[-2]
+    if is_research:
+        k[3] = 'H'
+        k[4] = serial_number[-1]
+        k[5] = '\0'
+        k[6] = serial_number[-2]
+        k[7] = 'T'
+        k[8] = serial_number[-3]
+        k[9] = '\x10'
+        k[10] = serial_number[-4]
+        k[11] = 'B'
+    else:
+        k[3] = 'T'
+        k[4] = serial_number[-3]
+        k[5] = '\x10'
+        k[6] = serial_number[-4]
+        k[7] = 'B'
+        k[8] = serial_number[-1]
+        k[9] = '\0'
+        k[10] = serial_number[-2]
+        k[11] = 'H'
+    k[12] = serial_number[-3]
+    k[13] = '\0'
+    k[14] = serial_number[-4]
+    k[15] = 'P'
+    return k
+
+
+def reversed_original_key(serial_number, is_research):
+    k = ['\0'] * 16
+    k[0] = serial_number[-1]
+    k[1] = '\0'
+    k[2] = serial_number[-2]
+    if is_research:
+        k[3] = 'H'
+        k[4] = serial_number[-1]
+        k[5] = '\0'
+        k[6] = serial_number[-2]
+        k[7] = 'T'
+        k[8] = serial_number[-3]
+        k[9] = '\x10'
+        k[10] = serial_number[-4]
+        k[11] = 'B'
+    else:
+        k[3] = 'T'
+        k[4] = serial_number[-3]
+        k[5] = '\x10'
+        k[6] = serial_number[-4]
+        k[7] = 'B'
+        k[8] = serial_number[-1]
+        k[9] = '\0'
+        k[10] = serial_number[-2]
+        k[11] = 'H'
+    k[12] = serial_number[-3]
+    k[13] = '\0'
+    k[14] = serial_number[-4]
+    k[15] = 'P'
+    k.reverse()
+    return AES.new(''.join(k), AES.MODE_ECB, iv), k
+
+
+data_ouput = "{0:^4} {1:^4} {2:^4} {3:^4} {4:^4} {5:^4} {6:^4} {7:^4} {8:^4} {9:^4} {10:^4} {11:^4} {12:^4} {13:^4} " \
+             "{14:^4} {15:^4} {16:^4} {17:^4} {18:^4} {19:^4} {20:^4} {21:^4} {22:^4} {23:^4} {24:^4} {25:^4} {26:^4} " \
+             "{27:^4} {28:^4} {29:^4} {30:^4} {31:^4}"
+
+def counter_check(file_data, cipher, swap_data=False):
+    counter_misses = 0
+    counter_checks = 0
+    last_counter = 0
+    lines = 258
+    i = 0
+    for line in file_data:
+        i += 1
+        if i > lines:
+            continue
+        data = line.split(',')[1:]
+        data = [int(value, 2) for value in data]
+        data = ''.join(map(chr, data))
+        if not swap_data:
+            decrypted = cipher.decrypt(data[:16]) + cipher.decrypt(data[16:])
+        else:
+            decrypted = cipher.decrypt(data[16:]) + cipher.decrypt(data[:16])
+        counter = ord(decrypted[0])
+        # (counter)
+        strings_of_data = [ord(char) for char in decrypted]
+        print(len(strings_of_data))
+        print(data_ouput.format(*strings_of_data))
+        # Uncomment this
+        # print(counter)
+        # if counter <= 127:
+        #    if counter != last_counter + 1:
+        #        counter_misses += 1
+        # elif not (counter == 0 and last_counter > 127):
+        #    counter_misses += 1
+        # if counter_misses > 2 and counter_checks > 16:
+        #    return False
+        # if counter_checks > 16 and counter_misses < 2:
+        #    return True
+        counter_checks += 1
+        last_counter = counter
+
+
+def unencrypted_counter_check(file_data, swap_data=True):
+    counter_misses = 0
+    counter_checks = 0
+    last_counter = 0
+    for line in file_data:
+        data = line.split(',')[1:]
+        data = [int(value, 2) for value in data]
+        data = ''.join(map(chr, data))
+        if not swap_data:
+            decrypted = data[:16] + data[16:]
+        else:
+            decrypted = data[16:] + data[:16]
+        counter = ord(decrypted[0])
+        if counter != last_counter + 1:
+            counter_misses += 1
+        if counter_misses > 4 and counter_checks > 5:
+            return False
+        if counter_checks > 5 and counter_misses < 4:
+            return True
+        counter_checks += 1
+        last_counter = counter
+
+
+with open('{}'.format(filename), 'r') as encrypted_data:
+    file_data = encrypted_data.readlines()
+    found_looping = False
+    i = 0
+    # key = [charset[0], ] * 15
+    # key.append('P')
+    # Uncomment this after updating new_crypto_key to verify.
+    # while not found_looping and i < 10000000:
+    #    cipher = test_key()
+    #    if counter_check(file_data, cipher, False):
+    #        print("Verified!")
+    #        sys.exit()
+    #    i += 1
+    # i = 0
+
+
+def check_key(next_check):
+    new_cipher = AES.new(''.join(next_check), AES.MODE_ECB, iv)
+    if counter_check(file_data, new_cipher):
+        print("Correct Key Found! {}".format(next_check))
+    sys.exit()
+
+
+pool = multiprocessing.Pool(multiprocessing.cpu_count() - 1)
+['4', '\x00', '7', 'H', '4', '\x00', '7', 'T', '8', '\x00', '1', 'B', '8', '\x00', '1', 'P']
+key = ['4', '7', '7', '8', '8', '8', '7', '1', '4', '1', '7', '7', '1', '1', '7', '4']
+# key = original_key(serial_number, False)
+check_key(key)
+print("?")
+i = 0
+last_i = 1
+then = datetime.now()
+for key in next_value():
+    pool.apply_async(check_key, args=(key,))
+    i += 1
+
+    now = datetime.now()
+    if now - then > timedelta(minutes=1):
+        print("{} keys per second, last key {}".format(i - last_i / 60, key))
+        last_i = i
+        then = now
+    time.sleep(0.00001)
+
+i += 1
+if False:
+    while not found_looping and i < 10000000:
+        cipher, key = random_key(serial_number)
+        if counter_check(file_data, cipher):
+            print("Correct Key Found! {}".format(key))
+            sys.exit()
+        i += 1
+    i = 0
+    while not found_looping and i < 10000000:
+        cipher, key = random_key(serial_number)
+        if counter_check(file_data, cipher, True):
+            print("Correct Key Found! Swap the data! {}".format(key))
+            sys.exit()
+        i += 1
+    i = 0
+    print("Dumb luck didn't work, starting brute force.")
+
+    i = 0
+    while not found_looping and i < 10000000:
+        cipher, key = random_key(serial_number)
+        if counter_check(file_data, cipher):
+            print("Correct Key Found! {}".format(key))
+            sys.exit()
+        i += 1
+    i = 0
+    while not found_looping and i < 10000000:
+        cipher, key = random_key(serial_number)
+        if counter_check(file_data, cipher, True):
+            print("Correct Key Found! Swap the data! {}".format(key))
+            sys.exit()
+        i += 1
+    i = 0
+    while not found_looping and i < 10000000:
+        cipher, key = random_key(serial_number)
+        if counter_check(file_data, cipher, True):
+            print("Correct Key Found! Swap the data! {}".format(key))
+            sys.exit()
+        i += 1
+    i = 0
+    while not found_looping and i < 13:
+        if unencrypted_counter_check(file_data, False):
+            print("Not encrypted!")
+            sys.exit()
+        i += 1
+    i = 0
+    while not found_looping and i < 13:
+        if unencrypted_counter_check(file_data, True):
+            print("Not Encrypted! Swap the data!")
+            sys.exit()
+        i += 1
+    print("Your script is terrible, try again...")
+