def test_unknown_parameters(self): self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, 7, counter=self.ctr_128) self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, counter=self.ctr_128, unknown=7) # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module) AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128, use_aesni=False)
def test_IV_iv_attributes(self): cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) eiv = cipher.encrypt(b"") self.assertEqual(cipher.iv, self.iv_128) cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) self.assertEqual(cipher.iv, self.iv_128)
def test_data_must_be_bytes(self): cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) self.assertRaises(TypeError, cipher.decrypt_and_verify, u'test1234567890-*', b("xxxx"))
def test_unaligned_data_128(self): plaintexts = [ b"7777777" ] * 100 cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
def decrypt(secretkey, params): iv = b64decode(params['iv']) salt = b64decode(params['salt']) #~ keylen = params.get('ks', 128) // 8 # FIXME use somewhere? taglen = params.get('ts', 64) // 8 iterations = params.get('iter', 1000) data = b64decode(params['ct']) ciphertext = data[:-taglen] tag = data[-taglen:] if params.get('adata'): raise NotImplementedError('authenticated data support is not implemented') iv = trunc_iv(iv, ciphertext, taglen) hash_func = lambda k, s: HMAC.new(k, s, SHA256).digest() key = PBKDF2(secretkey, salt=salt, count=iterations, prf=hash_func) mode_str = params.get('mode', 'ccm') mode = dict(ccm=AES.MODE_CCM)[mode_str] if mode_str == 'ccm': cipher = AES.new(key, mode=AES.MODE_CCM, nonce=iv, mac_len=taglen) else: cipher = AES.new(key, mode=mode, iv=iv) decrypted = cipher.decrypt_and_verify(ciphertext, tag) return decrypted
def test_aes_128(self): plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ '30c81c46a35ce411e5fbc1191a0a52ef' +\ 'f69f2445df4f9b17ad2b417be66c3710' ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\ '7789508d16918f03f53c52dac54ed825' +\ '9740051e9c5fecf64344f7a82260edcc' +\ '304c6528f659c77866a510d9c1d6ae5e' key = '2b7e151628aed2a6abf7158809cf4f3c' iv = '000102030405060708090a0b0c0d0e0f' key = unhexlify(key) iv = unhexlify(iv) plaintext = unhexlify(plaintext) ciphertext = unhexlify(ciphertext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.encrypt(plaintext), ciphertext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.decrypt(ciphertext), plaintext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
def test_unknown_parameters(self): self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, self.iv_128, 7) self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, iv=self.iv_128, unknown=7) # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module) AES.new(self.key_128, self.aes_mode, iv=self.iv_128, use_aesni=False)
def test_aes_256(self): plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ '30c81c46a35ce411e5fbc1191a0a52ef' +\ 'f69f2445df4f9b17ad2b417be66c3710' ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\ '4febdc6740d20b3ac88f6ad82a4fb08d' +\ '71ab47a086e86eedf39d1c5bba97c408' +\ '0126141d67f37be8538f5a8be740e484' key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' iv = '000102030405060708090a0b0c0d0e0f' key = unhexlify(key) iv = unhexlify(iv) plaintext = unhexlify(plaintext) ciphertext = unhexlify(ciphertext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.encrypt(plaintext), ciphertext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.decrypt(ciphertext), plaintext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
def test_aes_192(self): plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ '30c81c46a35ce411e5fbc1191a0a52ef' +\ 'f69f2445df4f9b17ad2b417be66c3710' ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\ 'fcc28b8d4c63837c09e81700c1100401' +\ '8d9a9aeac0f6596f559c6d4daf59a5f2' +\ '6d9f200857ca6c3e9cac524bd9acc92a' key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' iv = '000102030405060708090a0b0c0d0e0f' key = unhexlify(key) iv = unhexlify(iv) plaintext = unhexlify(plaintext) ciphertext = unhexlify(ciphertext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.encrypt(plaintext), ciphertext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.decrypt(ciphertext), plaintext) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) cipher = AES.new(key, AES.MODE_OFB, iv) self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
def test_valid_init_verify(self): # Verify path INIT->VERIFY cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) mac = cipher.digest() cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) cipher.verify(mac)
def test_hex_mac(self): cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) mac_hex = cipher.hexdigest() self.assertEqual(cipher.digest(), unhexlify(mac_hex)) cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) cipher.hexverify(mac_hex)
def test_bytearray(self): data = b"1" * 16 iv = b"\x00" * 6 + b"\xFF\xFF" # Encrypt cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64, initial_value=iv) ref1 = cipher1.encrypt(data) cipher2 = AES.new(self.key_128, AES.MODE_CTR, nonce=bytearray(self.nonce_64), initial_value=bytearray(iv)) ref2 = cipher2.encrypt(bytearray(data)) self.assertEqual(ref1, ref2) self.assertEqual(cipher1.nonce, cipher2.nonce) # Decrypt cipher3 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64, initial_value=iv) ref3 = cipher3.decrypt(data) cipher4 = AES.new(self.key_128, AES.MODE_CTR, nonce=bytearray(self.nonce_64), initial_value=bytearray(iv)) ref4 = cipher4.decrypt(bytearray(data)) self.assertEqual(ref3, ref4)
def test_nonce_parameter(self): # Nonce parameter becomes nonce attribute cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64) self.assertEqual(cipher1.nonce, self.nonce_64) counter = Counter.new(64, prefix=self.nonce_64, initial_value=0) cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) self.assertEqual(cipher1.nonce, cipher2.nonce) pt = get_tag_random("plaintext", 65536) self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) # Nonce is implicitly created (for AES) when no parameters are passed nonce1 = AES.new(self.key_128, AES.MODE_CTR).nonce nonce2 = AES.new(self.key_128, AES.MODE_CTR).nonce self.assertNotEqual(nonce1, nonce2) self.assertEqual(len(nonce1), 8) # Nonce can be zero-length cipher = AES.new(self.key_128, AES.MODE_CTR, nonce=b"") self.assertEqual(b"", cipher.nonce) cipher.encrypt(b'0'*300) # Nonce and Counter are mutually exclusive self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, counter=self.ctr_128, nonce=self.nonce_64)
def test_output_param(self): pt = b'5' * 16 cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) ct = cipher.encrypt(pt) tag = cipher.digest() output = bytearray(16) cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) res = cipher.encrypt(pt, output=output) self.assertEqual(ct, output) self.assertEqual(res, None) cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) res = cipher.decrypt(ct, output=output) self.assertEqual(pt, output) self.assertEqual(res, None) cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) res, tag_out = cipher.encrypt_and_digest(pt, output=output) self.assertEqual(ct, output) self.assertEqual(res, None) self.assertEqual(tag, tag_out) cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) res = cipher.decrypt_and_verify(ct, tag, output=output) self.assertEqual(pt, output) self.assertEqual(res, None)
def _aes_CTR_cipher(key, nonce, block_index=0, little_endian=False): if little_endian: counter = Cryptodome.Util.Counter.new( nbits=64, prefix=nonce, initial_value=block_index, little_endian=True) return AES.new(key, AES.MODE_CTR, counter=counter) else: return AES.new(key, AES.MODE_CTR, nonce=nonce, initial_value=block_index)
def test_invalid_multiple_decrypt_and_verify(self): cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) ct, tag = cipher.encrypt_and_digest(self.data_128) cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) cipher.decrypt_and_verify(ct, tag) self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag)
def test_memoryview(self): data = b"1" * 16 data_mv = memoryview(bytearray(data)) # Encrypt key_mv = memoryview(bytearray(self.key_128)) iv_mv = memoryview(bytearray(self.iv_128)) cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128) ref1 = cipher1.encrypt(data) cipher2 = AES.new(key_mv, self.aes_mode, iv_mv) key_mv[:3] = b'\xFF\xFF\xFF' iv_mv[:3] = b'\xFF\xFF\xFF' ref2 = cipher2.encrypt(data_mv) self.assertEqual(ref1, ref2) self.assertEqual(cipher1.iv, cipher2.iv) # Decrypt key_mv = memoryview(bytearray(self.key_128)) iv_mv = memoryview(bytearray(self.iv_128)) cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128) ref3 = cipher3.decrypt(data) cipher4 = AES.new(key_mv, self.aes_mode, iv_mv) key_mv[:3] = b'\xFF\xFF\xFF' iv_mv[:3] = b'\xFF\xFF\xFF' ref4 = cipher4.decrypt(data_mv) self.assertEqual(ref3, ref4)
def test_bytearray(self): data = b"1" * 16 data_ba = bytearray(data) # Encrypt key_ba = bytearray(self.key_128) iv_ba = bytearray(self.iv_128) cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128) ref1 = cipher1.encrypt(data) cipher2 = AES.new(key_ba, self.aes_mode, iv_ba) key_ba[:3] = b'\xFF\xFF\xFF' iv_ba[:3] = b'\xFF\xFF\xFF' ref2 = cipher2.encrypt(data_ba) self.assertEqual(ref1, ref2) self.assertEqual(cipher1.iv, cipher2.iv) # Decrypt key_ba = bytearray(self.key_128) iv_ba = bytearray(self.iv_128) cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128) ref3 = cipher3.decrypt(data) cipher4 = AES.new(key_ba, self.aes_mode, iv_ba) key_ba[:3] = b'\xFF\xFF\xFF' iv_ba[:3] = b'\xFF\xFF\xFF' ref4 = cipher4.decrypt(data_ba) self.assertEqual(ref3, ref4)
def test_shorter_assoc_data_than_expected(self): # With plaintext cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, assoc_len=17) cipher.update(self.data_128) self.assertRaises(ValueError, cipher.encrypt, self.data_128) # With empty plaintext cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, assoc_len=17) cipher.update(self.data_128) self.assertRaises(ValueError, cipher.digest) # With ciphertext cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, assoc_len=17) cipher.update(self.data_128) self.assertRaises(ValueError, cipher.decrypt, self.data_128) # With empty ciphertext cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) cipher.update(self.data_128) mac = cipher.digest() cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, assoc_len=17) cipher.update(self.data_128) self.assertRaises(ValueError, cipher.verify, mac)
def test3(self): for keylen, taglen, result in self.tv3: key = bchr(0) * (keylen // 8 - 1) + bchr(taglen) C = b("") for i in range(128): S = bchr(0) * i N = long_to_bytes(3 * i + 1, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(S) C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() N = long_to_bytes(3 * i + 2, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() N = long_to_bytes(3 * i + 3, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(S) C += cipher.encrypt() + cipher.digest() N = long_to_bytes(385, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(C) result2 = cipher.encrypt() + cipher.digest() self.assertEquals(unhexlify(b(result)), result2)
def test_either_encrypt_or_decrypt(self): cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) cipher.encrypt(b"") self.assertRaises(TypeError, cipher.decrypt, b"") cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) cipher.decrypt(b"") self.assertRaises(TypeError, cipher.encrypt, b"")
def test_loopback_128(self): cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) pt = get_tag_random("plaintext", 16 * 100) ct = cipher.encrypt(pt) cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) pt2 = cipher.decrypt(ct) self.assertEqual(pt, pt2)
def test_either_encrypt_or_decrypt(self): cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) eiv = cipher.encrypt(b"") self.assertRaises(TypeError, cipher.decrypt, b"") cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) cipher.decrypt(b"") self.assertRaises(TypeError, cipher.encrypt, b"")
def test_loopback_128(self): cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) pt = get_tag_random("plaintext", 16 * 100) ct = cipher.encrypt(pt) cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) pt2 = cipher.decrypt(ct) self.assertEqual(pt, pt2)
def test_loopback_128(self): cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) pt = get_tag_random("plaintext", 16 * 100) ct, mac = cipher.encrypt_and_digest(pt) cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) pt2 = cipher.decrypt_and_verify(ct, mac) self.assertEqual(pt, pt2)
def test_either_encrypt_or_decrypt(self): cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) cipher.encrypt(b("")) self.assertRaises(TypeError, cipher.decrypt, b("")) cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) cipher.decrypt(b("")) self.assertRaises(TypeError, cipher.encrypt, b(""))
def test_either_encrypt_or_decrypt(self): cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) cipher.encrypt(b("xyz")) self.assertRaises(TypeError, cipher.decrypt, b("xyz")) cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) cipher.decrypt(b("xyz")) self.assertRaises(TypeError, cipher.encrypt, b("xyz"))
def test_loopback_128(self): cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) pt = get_tag_random("plaintext", 16 * 100) ct = cipher.encrypt(pt) cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) pt2 = cipher.decrypt(ct) self.assertEqual(pt, pt2)
def test_unaligned_data_128(self): cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) for wrong_length in xrange(1,16): self.assertRaises(ValueError, cipher.encrypt, b("5") * wrong_length) cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) for wrong_length in xrange(1,16): self.assertRaises(ValueError, cipher.decrypt, b("5") * wrong_length)
def initialize_cipher(self): """Creates the cipher-related objects needed for AES-CTR encryption and decryption. """ self.ctr_e = Counter.new(self.AES_block_size, initial_value=self.iv) self.ctr_d = Counter.new(self.AES_block_size, initial_value=self.iv) self.encryptor = AES.new(self.key, AES.MODE_CTR, counter=self.ctr_e) self.decryptor = AES.new(self.key, AES.MODE_CTR, counter=self.ctr_d)
def encrypt_func(plaintext, encryption_key, iv): #print("Character should be: ", plaintext[-1]) cipher_obj = AES.new(encryption_key, AES.MODE_CBC, iv) encrypted_bytes = cipher_obj.encrypt(plaintext) return encrypted_bytes
def test_valid_init_digest(self): # Verify path INIT->DIGEST cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) cipher.digest()
def encryptData(self, pw, data): key = hashlib.sha256(pw.encode()).hexdigest() cipher = AES.new(key[:32].encode('utf-8'), AES.MODE_EAX) ciphertext, tag = cipher.encrypt_and_digest( json.dumps(data).encode("utf-8")) return cipher, ciphertext, tag
def dumpfile(file_path): # 预定义key core_key = binascii.a2b_hex("687A4852416D736F356B496E62617857") meta_key = binascii.a2b_hex("2331346C6A6B5F215C5D2630553C2728") unpad = lambda s: s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] f = open(file_path, 'rb') # magic header header = f.read(8) assert binascii.b2a_hex(header) == b'4354454e4644414d' # key data f.seek(2, 1) key_length = f.read(4) key_length = struct.unpack('<I', bytes(key_length))[0] key_data = bytearray(f.read(key_length)) key_data = bytes(bytearray([byte ^ 0x64 for byte in key_data])) cryptor = AES.new(core_key, AES.MODE_ECB) key_data = unpad(cryptor.decrypt(key_data))[17:] key_length = len(key_data) # key box key_data = bytearray(key_data) key_box = bytearray(range(256)) j = 0 for i in range(256): j = (key_box[i] + j + key_data[i % key_length]) & 0xff key_box[i], key_box[j] = key_box[j], key_box[i] # meta data meta_length = f.read(4) meta_length = struct.unpack('<I', bytes(meta_length))[0] meta_data = bytearray(f.read(meta_length)) meta_data = bytes(bytearray([byte ^ 0x63 for byte in meta_data])) meta_data = base64.b64decode(meta_data[22:]) cryptor = AES.new(meta_key, AES.MODE_ECB) meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:] meta_data = json.loads(meta_data) # crc32 crc32 = f.read(4) crc32 = struct.unpack('<I', bytes(crc32))[0] # album cover f.seek(5, 1) image_size = f.read(4) image_size = struct.unpack('<I', bytes(image_size))[0] image_data = f.read(image_size) author_name = "" # media data if len(meta_data['artist']) == 1: author_name = meta_data['artist'][0][0] else: for i in range(len(meta_data['artist'])): if i == len(meta_data['artist']) - 1: author_name += meta_data['artist'][i][0] else: author_name += meta_data['artist'][i][0] author_name += ',' file_name = author_name + ' - ' + meta_data['musicName'] + '.' + meta_data[ 'format'] music_path = os.path.join(os.path.split(file_path)[0], file_name) m = open(music_path, 'wb') while True: chunk = bytearray(f.read(0x8000)) chunk_length = len(chunk) if not chunk: break for i in range(chunk_length): j = (i + 1) & 0xff chunk[i] ^= key_box[(key_box[j] + key_box[(key_box[j] + j) & 0xff]) & 0xff] m.write(chunk) m.close() f.close() # media tag if meta_data['format'] == 'flac': audio = flac.FLAC(music_path) # audio.delete() image = flac.Picture() image.type = 3 image.mime = 'image/jpeg' image.data = image_data audio.clear_pictures() audio.add_picture(image) elif meta_data['format'] == 'mp3': audio = mp3.MP3(music_path) # audio.delete() image = id3.APIC() image.type = 3 image.mime = 'image/jpeg' image.data = image_data audio.tags.add(image) audio.save() audio = mp3.EasyMP3(music_path) audio['title'] = meta_data['musicName'] audio['album'] = meta_data['album'] audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']]) audio.save()
def decrypt_and_verify_challenge(self, challenge_url, accept=True): """ Decrypts the data packed in the challenge url, verifies its content, returns the parsed data as a dictionary, calculates and returns the signature. The calling method must then send the signature back to the server. (The reason for this control flow is that the challenge data must be checked in different scenarios, e.g. when we have a pairing the data must be checked by the method that simulates the pairing) :param challenge_url: the challenge url as sent by the server :returns: (challenge, signature) challenge has the keys * content_type - one of the three values CONTENT_TYPE_SIGNREQ, CONTENT_TYPE_PAIRING or CONTENT_TYPE_LOGIN) (all defined in this module) * transaction_id - used to identify the challenge on the server * callback_url (optional) - the url to which the challenge response should be set * user_token_id - used to identify the token in the user database for which this challenge was created depending on the content type additional keys are present * for CONTENT_TYPE_PAIRING: serial * for CONTENT_TYPE_SIGNREQ: message * for CONTENT_TYPE_LOGIN: login, host signature is the generated user signature used to respond to the challenge """ challenge_data_encoded = challenge_url[len('lseqr://chal/'):] challenge_data = decode_base64_urlsafe(challenge_data_encoded) # ------------------------------------------------------------------ -- # parse and verify header information in the # encrypted challenge data header = challenge_data[0:5] version, user_token_id = struct.unpack('<bI', header) self.assertEqual(version, CHALLENGE_URL_VERSION) # ------------------------------------------------------------------ -- # get token from client token database token = self.tokens[user_token_id] server_public_key = token['server_public_key'] # ------------------------------------------------------------------ -- # prepare decryption by seperating R from # ciphertext and server signature R = challenge_data[5:5 + 32] ciphertext = challenge_data[5 + 32:-64] server_signature = challenge_data[-64:] # check signature data = challenge_data[0:-64] crypto_sign_verify_detached(server_signature, data, server_public_key) # ------------------------------------------------------------------ -- # key derivation secret_key_dh = dsa_to_dh_secret(self.secret_key) ss = calc_dh(secret_key_dh, R) U = SHA256.new(ss).digest() sk = U[0:16] nonce = U[16:32] # ------------------------------------------------------------------ -- # decrypt and verify challenge nonce_as_int = int_from_bytes(nonce, byteorder='big') ctr = Counter.new(128, initial_value=nonce_as_int) cipher = AES.new(sk, AES.MODE_CTR, counter=ctr) plaintext = cipher.decrypt(ciphertext) # ------------------------------------------------------------------ -- # parse/check plaintext header # 1 - for content type # 8 - for transaction id # 8 - for time stamp offset = 1 + 8 + 8 pt_header = plaintext[0:offset] (content_type, transaction_id, _time_stamp) = struct.unpack('<bQQ', pt_header) transaction_id = u64_to_transaction_id(transaction_id) # ------------------------------------------------------------------ -- # prepare the parsed challenge data challenge = {} challenge['content_type'] = content_type # ------------------------------------------------------------------ -- # retrieve plaintext data depending on content_type if content_type == CONTENT_TYPE_PAIRING: serial, callback_url, __ = plaintext[offset:].split('\x00') challenge['serial'] = serial elif content_type == CONTENT_TYPE_SIGNREQ: message, callback_url, __ = plaintext[offset:].split('\x00') challenge['message'] = message elif content_type == CONTENT_TYPE_LOGIN: login, host, callback_url, __ = plaintext[offset:].split('\x00') challenge['login'] = login challenge['host'] = host # ------------------------------------------------------------------ -- # prepare the parsed challenge data challenge['callback_url'] = callback_url challenge['transaction_id'] = transaction_id challenge['user_token_id'] = user_token_id # calculate signature - dependend on reject or accept mode if accept: sig_base = ( struct.pack('<b', CHALLENGE_URL_VERSION) + b'ACCEPT\0' + server_signature + plaintext) else: sig_base = ( struct.pack('<b', CHALLENGE_URL_VERSION) + b'DENY\0' + server_signature + plaintext) sig = crypto_sign_detached(sig_base, self.secret_key) encoded_sig = encode_base64_urlsafe(sig) return challenge, encoded_sig
import os import signal def exit_cleanly(signal, frame): print("Received SIGINT, exiting...") exit(0) signal.signal(signal.SIGINT, exit_cleanly) from Cryptodome.Cipher import AES pad = lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16) unpad = lambda s: s[:-ord(s[len(s) - 1:])] encrypt = lambda msg, key: AES.new(key, AES.MODE_ECB).encrypt( pad(msg).encode()) decrypt = lambda msg, key: unpad(AES.new(key, AES.MODE_ECB).decrypt(msg) ).decode() from base64 import b64encode import hashlib import hmac import binascii import json jsonstr = lambda j: json.dumps(j, separators=(',', ':')) def file_as_bytes(file_name): with open(file_name, 'rb') as file: return file.read()
def encrypt(self, raw): raw = self._pad(raw) iv = Random.new().read(AES.block_size) cipher = AES.new(self.key, AES.MODE_CBC, iv) return base64.b64encode(iv + cipher.encrypt(raw.encode()))
def _handle_AES(self, id): key_and_iv = hashlib.md5((self.SECRET_KEY + id).encode()).hexdigest().upper() half_keylen=len(key_and_iv) // 2 secret_key = key_and_iv[0:half_keylen] iv = key_and_iv[half_keylen:] return AES.new(bytes(secret_key.encode('utf8')), AES.MODE_CBC, bytes(iv.encode('utf8')))
def test_data_must_be_bytes(self): cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
def aes_decrypt(data, key): iv = bytes(16) cipher = AES.new(key, AES.MODE_CBC, iv) return cipher.decrypt(data)
sys.exit(-1) key = my_socket.recv(8192) # receives encrypted AES key time.sleep(3) data = my_socket.recv(4096) # receives encrypted menu print(f'{"":-^40}') print(f'{"Received menu!": ^40}') print(f'{"":-^40}') print(f'{"Decrypting menu...": ^40}') # decrypting AES key to decrypt menu cipher = PKCS1_OAEP.new(aes_rsa_keypair) decrypted_key = cipher.decrypt(key) my_cipher = AES.new(decrypted_key,AES.MODE_ECB) decrypted_menu = unpad(my_cipher.decrypt(data),BLOCK_SIZE) print(f'{"Done!": ^40}') print(f'{"":-^40}') print(f'{"Processing menu...": ^40}') menu_bytes = decrypted_menu.decode() menu_list = [] menu_list = menu_bytes.split("\n") # opening menu.xlsx workbook = xlsxwriter.Workbook(menu_file) menuws = workbook.add_worksheet("menu") for i in range(0,len(menu_list)): menuws.write(i,0,menu_list[i]) # protecting worksheet from modifications by unauthorized persons
def test_null_encryption_decryption(self): cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) eiv = cipher.encrypt(b"") cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) self.assertEqual(cipher.decrypt(b""), b"")
def CBC_MAC(P: bytes, K: bytes, IV=bytes(BS)): return AES.new(K, AES.MODE_CBC, iv=IV).encrypt(pad(P, BS))[-BS:]
def decrypt(self, enc): enc = base64.b64decode(enc) iv = enc[:AES.block_size] cipher = AES.new(self.key, AES.MODE_CBC, iv) return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
data = PREF + userdata + SUFF # IV = key return AES.new(_KEY, AES.MODE_CBC, iv=_KEY).encrypt(pad(data, BS)) def decrypt(ciph: bytes) -> bool: data = unpad(AES.new(_KEY, AES.MODE_CBC, iv=_KEY).decrypt(ciph), BS) if not all(32<=b<127 for b in data): raise ValueError('Invalid charset', data) return True if __name__=='__main__': ciph0 = encrypt('*'*BS) assert decrypt(ciph0) # we prepend the first block + a block of 0s ciph1 = ciph0[:BS] + bytes(BS) + ciph0 # plaintext: m0, m1, ... # ciphertext: c0, zz, c0, c1, ... # decrypted: d0, d1, d2, d3, ... # we have d0 = m0 and d2 = zz ⊕ AES_decrypt(c0) = IV ⊕ m0 # hence d0 ⊕ d2 = IV key = None try: decrypt(ciph1) except ValueError as err: err_msg, deciph1 = err.args print(err_msg, deciph1) key = strxor(deciph1[:BS], deciph1[2*BS:3*BS]) assert key == _KEY print() print(unpad(AES.new(key, AES.MODE_CBC, iv=key).decrypt(ciph0), BS).decode())
def auth_receive(request): if 's' in request.GET and request.GET['s'] == "logout": # This was a logout request return HttpResponseRedirect('/') if 'i' not in request.GET: return HttpResponse("Missing IV in url!", status=400) if 'd' not in request.GET: return HttpResponse("Missing data in url!", status=400) # Set up an AES object and decrypt the data we received decryptor = AES.new(base64.b64decode(settings.PGAUTH_KEY), AES.MODE_CBC, base64.b64decode(str(request.GET['i']), "-_")) s = decryptor.decrypt(base64.b64decode(str(request.GET['d']), "-_")).rstrip(b' ').decode('utf8') # Now un-urlencode it try: data = parse_qs(s, strict_parsing=True) except ValueError: return HttpResponse("Invalid encrypted data received.", status=400) # Check the timestamp in the authentication if (int(data['t'][0]) < time.time() - 10): return HttpResponse("Authentication token too old.", status=400) # Update the user record (if any) try: user = User.objects.get(username=data['u'][0]) # User found, let's see if any important fields have changed changed = False if user.first_name != data['f'][0]: user.first_name = data['f'][0] changed = True if user.last_name != data['l'][0]: user.last_name = data['l'][0] changed = True if user.email != data['e'][0]: user.email = data['e'][0] changed = True if changed: user.save() except User.DoesNotExist: # User not found, create it! # NOTE! We have some legacy users where there is a user in # the database with a different userid. Instead of trying to # somehow fix that live, give a proper error message and # have somebody look at it manually. if User.objects.filter(email=data['e'][0]).exists(): return HttpResponse( """A user with email %s already exists, but with a different username than %s. This is almost certainly caused by some legacy data in our database. Please send an email to [email protected], indicating the username and email address from above, and we'll manually merge the two accounts for you. We apologize for the inconvenience. """ % (data['e'][0], data['u'][0]), content_type='text/plain') if getattr(settings, 'PGAUTH_CREATEUSER_CALLBACK', None): res = getattr(settings, 'PGAUTH_CREATEUSER_CALLBACK')( data['u'][0], data['e'][0], ['f'][0], data['l'][0], ) # If anything is returned, we'll return that as our result. # If None is returned, it means go ahead and create the user. if res: return res user = User( username=data['u'][0], first_name=data['f'][0], last_name=data['l'][0], email=data['e'][0], password='******', ) user.save() # Ok, we have a proper user record. Now tell django that # we're authenticated so it persists it in the session. Before # we do that, we have to annotate it with the backend information. user.backend = "%s.%s" % (AuthBackend.__module__, AuthBackend.__name__) django_login(request, user) # Finally, check of we have a data package that tells us where to # redirect the user. if 'd' in data: (ivs, datas) = data['d'][0].split('$') decryptor = AES.new( SHA.new(settings.SECRET_KEY.encode('ascii')).digest()[:16], AES.MODE_CBC, base64.b64decode(ivs, b"-_")) s = decryptor.decrypt(base64.b64decode( datas, "-_")).rstrip(b' ').decode('utf8') try: rdata = parse_qs(s, strict_parsing=True) except ValueError: return HttpResponse("Invalid encrypted data received.", status=400) if 'r' in rdata: # Redirect address return HttpResponseRedirect(rdata['r'][0]) # No redirect specified, see if we have it in our settings if hasattr(settings, 'PGAUTH_REDIRECT_SUCCESS'): return HttpResponseRedirect(settings.PGAUTH_REDIRECT_SUCCESS) return HttpResponse( "Authentication successful, but don't know where to redirect!", status=500)
def test_null_encryption_decryption(self): for func in "encrypt", "decrypt": cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) result = getattr(cipher, func)(b("")) self.assertEqual(result, b(""))
def encrypt(userdata: str) -> bytes: userdata = userdata.replace(';','";"').replace('=','"="').encode() data = PREF + userdata + SUFF # IV = key return AES.new(_KEY, AES.MODE_CBC, iv=_KEY).encrypt(pad(data, BS))
def decrypt(enc, password): private_key = hashlib.sha256(password.encode("utf-8")).digest() enc = base64.b64decode(enc) iv = enc[:16] cipher = AES.new(private_key, AES.MODE_CBC, iv) return unpad(cipher.decrypt(enc[16:]))
def __init__(self, cia, dev): keys_set = False key_x = 0 # check for boot9 to get common key X def check_b9_file(path): nonlocal keys_set, key_x if not keys_set: if os.path.isfile(path): key_offset = 0x5A20 if dev: key_offset += 0x400 if os.path.getsize(path) == 0x10000: key_offset += 0x8000 with open(path, 'rb') as b9: b9.seek(key_offset) key_x = int.from_bytes(b9.read(0x10), 'big') keys_set = True check_b9_file('boot9.bin') check_b9_file('boot9_prot.bin') check_b9_file(os.path.expanduser('~') + '/.3ds/boot9.bin') check_b9_file(os.path.expanduser('~') + '/.3ds/boot9_prot.bin') if not keys_set: sys.exit('Failed to get keys from boot9') # get status change, modify, and file access times cia_stat = os.stat(cia) self.g_stat = {} self.g_stat['st_ctime'] = int(cia_stat.st_ctime) self.g_stat['st_mtime'] = int(cia_stat.st_mtime) self.g_stat['st_atime'] = int(cia_stat.st_atime) # open cia and get section sizes self.f = open(cia, 'rb') # TODO: do this based off the section sizes instead of file size. self.cia_size = os.path.getsize(cia) archive_header_size, cia_type, cia_version, cert_chain_size, ticket_size, tmd_size, meta_size, content_size = struct.unpack('<IHHIIIIQ', self.f.read(0x20)) # get offsets for sections of the CIA # each section is aligned to 64-byte blocks cert_chain_offset = new_offset(archive_header_size) ticket_offset = cert_chain_offset + new_offset(cert_chain_size) tmd_offset = ticket_offset + new_offset(ticket_size) content_offset = tmd_offset + new_offset(tmd_size) meta_offset = content_offset + new_offset(content_size) # read title id, encrypted titlekey and common key index self.f.seek(ticket_offset + 0x1DC) title_id = self.f.read(8) self.f.seek(ticket_offset + 0x1BF) enc_titlekey = self.f.read(0x10) self.f.seek(ticket_offset + 0x1F1) common_key_index = ord(self.f.read(1)) # decrypt titlekey normalkey = keygen(key_x, int(common_key_y[common_key_index][dev], 16)) cipher_titlekey = AES.new(normalkey, AES.MODE_CBC, title_id + (b'\0' * 8)) self.titlekey = cipher_titlekey.decrypt(enc_titlekey) # get content count self.f.seek(tmd_offset + 0x1DE) content_count = int.from_bytes(self.f.read(2), 'big') # get offset for tmd chunks, mostly so it can be put into a tmdchunks.bin virtual file tmd_chunks_offset = tmd_offset + 0xB04 tmd_chunks_size = content_count * 0x30 # create virtual files self.files = {} self.files['/header.bin'] = {'size': archive_header_size, 'offset': 0, 'type': 'raw'} self.files['/cert.bin'] = {'size': cert_chain_size, 'offset': cert_chain_offset, 'type': 'raw'} self.files['/ticket.bin'] = {'size': ticket_size, 'offset': ticket_offset, 'type': 'raw'} self.files['/tmd.bin'] = {'size': tmd_size, 'offset': tmd_offset, 'type': 'raw'} self.files['/tmdchunks.bin'] = {'size': tmd_chunks_size, 'offset': tmd_chunks_offset, 'type': 'raw'} if meta_size: self.files['/meta.bin'] = {'size': meta_size, 'offset': meta_offset, 'type': 'raw'} # show icon.bin if meta size is the expected size # in practice this never changes, but better to be safe if meta_size == 0x3AC0: self.files['/icon.bin'] = {'size': 0x36C0, 'offset': meta_offset + 0x400, 'type': 'raw'} self.f.seek(tmd_chunks_offset) tmd_chunks_raw = self.f.read(tmd_chunks_size) # read chunks to generate virtual files current_offset = content_offset for chunk in [tmd_chunks_raw[i:i + 30] for i in range(0, content_count * 0x30, 0x30)]: content_id = chunk[0:4] content_index = chunk[4:6] content_size = int.from_bytes(chunk[8:16], 'big') content_is_encrypted = int.from_bytes(chunk[6:8], 'big') & 1 filename = '/{}.{}.app'.format(content_index.hex(), content_id.hex()) self.files[filename] = {'size': content_size, 'offset': current_offset, 'index': content_index, 'type': 'enc' if content_is_encrypted else 'raw'} current_offset += new_offset(content_size)
def decrypt(ciph: bytes) -> bool: data = unpad(AES.new(_KEY, AES.MODE_CBC, iv=_KEY).decrypt(ciph), BS) if not all(32<=b<127 for b in data): raise ValueError('Invalid charset', data) return True
def decrypt(message, key, iv): cipher = AES.new(key, AES.MODE_CBC, iv ) return cipher.decrypt(message)
def encrypt(raw, password): private_key = hashlib.sha256(password.encode("utf-8")).digest() raw = pad(raw) iv = Random.new().read(AES.block_size) cipher = AES.new(private_key, AES.MODE_CBC, iv) return base64.b64encode(iv + cipher.encrypt(raw))
import base64 from Cryptodome.Cipher import AES # 补足字符串长度为16的倍数 def add_to_16(s): while len(s) % 16 != 0: s += '\0' return str.encode(s) # 返回bytes key = '1234567890123456' # 密钥长度必须为16、24或32位,分别对应AES-128、AES-192和AES-256 text = 'abcdefg' # 待加密文本 aes = AES.new(str.encode(key), AES.MODE_ECB) # 初始化加密器,本例采用ECB加密模式 encrypted_text = str(base64.encodebytes(aes.encrypt(add_to_16(text))), encoding='utf8').replace('\n', '') # 加密 decrypted_text = str( aes.decrypt(base64.decodebytes(bytes( encrypted_text, encoding='utf8'))).rstrip(b'\0').decode("utf8")) # 解密 print('加密值:', encrypted_text) print('解密值:', decrypted_text)
def encrypt(self, msg): msg = pad(msg, AES.block_size) iv = get_random_bytes(16) cipher = AES.new(self.key, AES.MODE_CBC, iv) return iv, cipher.encrypt(msg)
def decrypt(self, iv, msg): cipher = AES.new(self.key, AES.MODE_CBC, iv) return unpad(cipher.decrypt(msg), AES.block_size)
from Cryptodome.Cipher import AES from Cryptodome import Random # key and plaintext must be bytes(), not strings key = b"I am a short key" plaintext = b"Alice I love you" # may be public , but must be chosen at random iv = Random.new().read(AES.block_size) # or , if using ‘secrets ‘: # iv = secrets.randbits(AES.block_size *8).to_bytes(AES.block_size , ’big ’) # this object remembers how many bytes have been encrypted encrypter = AES.new(key , AES.MODE_CFB , iv) ciphertext = encrypter.encrypt(plaintext) print("Gibberish incoming:", ciphertext.hex()) # the same as the encrypter , but initialized anew decrypter = AES.new(key , AES.MODE_CFB , iv) decrypted = decrypter.decrypt(ciphertext) if plaintext == decrypted: print("All good!")
def test_block_size_128(self): cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) self.assertEqual(cipher.block_size, AES.block_size)
def activation_finalyze(self, random_bytes=None): R = self.getR() params = { "action": "ActionFinalize", "mode": self.mode, "id": self.data.iwid, "lastsync": self.data.iwTsync, "version": "Generator-1.0/0.2.11", "lang": "fr", "ack": "", "macid": self.macid } if self.mode == Otp.OTP_MODE: params.update({"keytype": '0', "sid": self.data.iwsecid}) elif self.mode == Otp.ACTIVATE_MODE: kma_crypt = self.cipher.encrypt( bytes.fromhex(self.generateKMA(self.codepin))).hex() pin_crypt = self.cipher.encrypt(self.codepin.encode("utf-8")).hex() params.update({ "serial": self.getSerial(), "code": self.smsCode, "Kma": kma_crypt, "pin": pin_crypt, "name": "Android SDK built for x86_64 / UNKNOWN", }) params.update(R) xml = self.request(params) self.data.synchro(xml, self.generateKMA(self.codepin)) if self.mode == Otp.OTP_MODE: self.defi = str(xml["defi"]) if "J" in xml: logger.debug("Need another otp request") return Otp.OTP_TWICE else: return Otp.OK if "ms_n" not in xml or xml["ms_n"] == 0: logger.debug("no ms_n request needed") return Otp.OK if int(xml["ms_n"]) > 1: raise NotImplementedError else: ms_n = "0" self.challenge = xml["challenge"] self.action = "synchro" res = self.decode_oeap(xml["ms_key"], self.Kfact) temp_key = RSA.construct((int(res, 16), self.exponent)) temp_cipher = oaep.new(temp_key, hashAlgo=Hash.SHA256) if random_bytes is None: random_bytes = token_bytes(16) KpubEncode = temp_cipher.encrypt(random_bytes) aes_cipher = AES.new(bytes.fromhex(self.generateKMA(self.codepin)), AES.MODE_ECB) encodeAesFromHex = aes_cipher.encrypt(random_bytes).hex() self.data.iwsecval = encodeAesFromHex self.data.iwsecid = xml["s_id"] self.data.iwsecn = 1 req_param = { "action": "ActionFinalize", "mode": Otp.MS_MODE, "ms_id" + ms_n: xml["ms_id"], "ms_val" + ms_n: KpubEncode.hex(), "macid": self.macid } req_param.update({ "id": self.data.iwid, "lastsync": self.data.iwTsync, "ms_n": 1 }) req_param.update(self.getR()) xml = self.request(req_param) self.data.synchro(xml, self.generateKMA(self.codepin)) return Otp.OK
def decryptData(self, pw, ciphertext, tag, nonce): key = hashlib.sha256(pw.encode()).hexdigest() cipher = AES.new(key[:32].encode('utf-8'), AES.MODE_EAX, nonce) return json.loads(cipher.decrypt_and_verify(ciphertext, tag)) # data