def update_header_data(self, new_header_data): self._storage.update_header_data( AES.GCMEnc( self.key, AES.GCMDec(self._key, self._storage.header_data)\ [:self._index_offset] + \ new_header_data))
def test_KeyGen(self): self.assertTrue(len(AES.key_sizes) in (3, 4)) self.assertTrue(len(set(AES.key_sizes)) in (3, 4)) for keysize in AES.key_sizes: key_list = [] key_set = set() for i in range(10): k = AES.KeyGen(keysize) self.assertEqual(len(k), keysize) key_list.append(k) key_set.add(k) self.assertEqual(len(key_list), 10) # make sure every key is unique self.assertEqual(len(key_list), len(key_set))
def __init__(self, storage, **kwds): self._key = kwds.pop('key', None) if self._key is None: raise ValueError("An encryption key is required using " "the 'key' keyword.") if isinstance(storage, BlockStorageInterface): storage_owned = False self._storage = storage if len(kwds): raise ValueError("Keywords not used when initializing " "with a storage device: %s" % (str(kwds))) else: storage_owned = True storage_type = kwds.pop('storage_type', 'file') self._storage = \ BlockStorageTypeFactory(storage_type)(storage, **kwds) try: header_data = AES.GCMDec(self._key, self._storage.header_data) (self._ismodegcm, ) = struct.unpack( self._index_struct_string, header_data[:self._index_offset]) self._verify_digest = header_data[:hashlib.sha384().digest_size] verify = hmac.HMAC(key=self.key, msg=struct.pack(self._verify_struct_string, self._storage.block_size, self._storage.block_count, len(self._storage.header_data)), digestmod=hashlib.sha384) if verify.digest() != self._verify_digest: raise ValueError("HMAC of plaintext index data does not match") if self._ismodegcm: self._encrypt_block_func = AES.GCMEnc self._decrypt_block_func = AES.GCMDec else: self._encrypt_block_func = AES.CTREnc self._decrypt_block_func = AES.CTRDec except: if storage_owned: self._storage.close() raise
def runtest(label, enc_func, dec_func): print("") print("$" * 20) print("{0:^20}".format(label)) print("$" * 20) for keysize in AES.key_sizes[:3]: print("") print("@@@@@@@@@@@@@@@@@@@@") print(" Key Size: %s bytes" % (keysize)) print("@@@@@@@@@@@@@@@@@@@@") print("\nTest Bulk") # # generate a key # key = AES.KeyGen(keysize) print("Key: %s" % (base64.b64encode(key))) # # generate some plaintext # nblocks = 1000000 plaintext_numbytes = AES.block_size * nblocks print("Plaintext Size: %s MB" % (plaintext_numbytes * 1.0e-6)) # all zeros plaintext = bytes(bytearray(plaintext_numbytes)) # # time encryption # start_time = time.time() ciphertext = enc_func(key, plaintext) stop_time = time.time() print("Encryption Time: %.3fs (%.3f MB/s)" % (stop_time - start_time, (plaintext_numbytes * 1.0e-6) / (stop_time - start_time))) # # time decryption # start_time = time.time() plaintext_decrypted = dec_func(key, ciphertext) stop_time = time.time() print("Decryption Time: %.3fs (%.3f MB/s)" % (stop_time - start_time, (plaintext_numbytes * 1.0e-6) / (stop_time - start_time))) assert plaintext_decrypted == plaintext assert ciphertext != plaintext # IND-CPA assert enc_func(key, plaintext) != ciphertext # make sure the only difference is not in the IV assert enc_func(key, plaintext)[AES.block_size:] \ != ciphertext[AES.block_size:] if enc_func is AES.CTREnc: assert len(plaintext) == \ len(ciphertext) - AES.block_size else: assert enc_func is AES.GCMEnc assert len(plaintext) == \ len(ciphertext) - 2*AES.block_size del plaintext del plaintext_decrypted del ciphertext print("\nTest Chunks") # # generate a key # key = AES.KeyGen(keysize) print("Key: %s" % (base64.b64encode(key))) # # generate some plaintext # nblocks = 1000 blocksize = 16000 total_bytes = blocksize * nblocks print("Block Size: %s KB" % (blocksize * 1.0e-3)) print("Block Count: %s" % (nblocks)) print("Total: %s MB" % (total_bytes * 1.0e-6)) plaintext_blocks = [ bytes(bytearray(blocksize)) for i in range(nblocks) ] # # time encryption # start_time = time.time() ciphertext_blocks = [enc_func(key, b) for b in plaintext_blocks] stop_time = time.time() print("Encryption Time: %.3fs (%.3f MB/s)" % (stop_time - start_time, (total_bytes * 1.0e-6) / (stop_time - start_time))) # # time decryption # start_time = time.time() plaintext_decrypted_blocks = [ dec_func(key, c) for c in ciphertext_blocks ] stop_time = time.time() print("Decryption Time: %.3fs (%.3f MB/s)" % (stop_time - start_time, (total_bytes * 1.0e-6) / (stop_time - start_time)))
def _test_Enc_Dec(self, enc_func, dec_func, get_plaintext, keysizes): keysizes = list(keysizes) self.assertTrue(len(keysizes) > 0) blocksize_factor = [0.5, 1, 1.5, 2, 2.5] plaintext_blocks = [] for i, f in enumerate(blocksize_factor): size = AES.block_size * f size = int(round(size)) if int(f) != f: assert (size % AES.block_size) != 0 plaintext_blocks.append(get_plaintext(i, size)) assert len(AES.key_sizes) > 0 ciphertext_blocks = {} keys = {} for keysize in keysizes: key = AES.KeyGen(keysize) keys[keysize] = key ciphertext_blocks[keysize] = [] for block in plaintext_blocks: ciphertext_blocks[keysize].append(enc_func(key, block)) self.assertEqual(len(ciphertext_blocks), len(keysizes)) self.assertEqual(len(keys), len(keysizes)) plaintext_decrypted_blocks = {} for keysize in keys: key = keys[keysize] plaintext_decrypted_blocks[keysize] = [] for block in ciphertext_blocks[keysize]: plaintext_decrypted_blocks[keysize].append(dec_func( key, block)) self.assertEqual(len(plaintext_decrypted_blocks), len(keysizes)) for i in range(len(blocksize_factor)): for keysize in keysizes: self.assertEqual(plaintext_blocks[i], plaintext_decrypted_blocks[keysize][i]) self.assertNotEqual(plaintext_blocks[i], ciphertext_blocks[keysize][i]) if enc_func is AES.CTREnc: self.assertEqual(len(ciphertext_blocks[keysize][i]), len(plaintext_blocks[i]) + AES.block_size) else: assert enc_func is AES.GCMEnc self.assertEqual( len(ciphertext_blocks[keysize][i]), len(plaintext_blocks[i]) + 2 * AES.block_size) # check IND-CPA key = keys[keysize] alt_ciphertext = enc_func(key, plaintext_blocks[i]) self.assertNotEqual(ciphertext_blocks[keysize][i], alt_ciphertext) self.assertEqual(len(ciphertext_blocks[keysize][i]), len(alt_ciphertext)) self.assertNotEqual( ciphertext_blocks[keysize][i][:AES.block_size], alt_ciphertext[:AES.block_size]) self.assertNotEqual( ciphertext_blocks[keysize][i][AES.block_size:], alt_ciphertext[AES.block_size:])
def header_data(self): return AES.GCMDec(self._key, self._storage.header_data)\ [self._index_offset:]
def setup(cls, storage_name, block_size, block_count, aes_mode='ctr', key_size=None, key=None, storage_type='file', initialize=None, **kwds): if (key is not None) and (key_size is not None): raise ValueError("Only one of 'key' or 'keysize' keywords can " "be specified at a time") if key is None: if key_size is None: key_size = 32 if key_size not in AES.key_sizes: raise ValueError("Invalid key size: %s" % (key_size)) key = AES.KeyGen(key_size) else: if len(key) not in AES.key_sizes: raise ValueError("Invalid key size: %s" % (len(key))) if (block_size <= 0) or (block_size != int(block_size)): raise ValueError( "Block size (bytes) must be a positive integer: %s" % (block_size)) ismodegcm = None encrypt_block_func = None encrypted_block_size = block_size if aes_mode == 'ctr': ismodegcm = False encrypt_block_func = AES.CTREnc encrypted_block_size += AES.block_size elif aes_mode == 'gcm': ismodegcm = True encrypt_block_func = AES.GCMEnc encrypted_block_size += (2 * AES.block_size) else: raise ValueError( "AES encryption mode must be one of 'ctr' or 'gcm'. " "Invalid value: %s" % (aes_mode)) assert ismodegcm is not None assert encrypt_block_func is not None if not isinstance(storage_type, BlockStorageInterface): storage_type = BlockStorageTypeFactory(storage_type) if initialize is None: zeros = bytes(bytearray(block_size)) initialize = lambda i: zeros def encrypted_initialize(i): return encrypt_block_func(key, initialize(i)) kwds['initialize'] = encrypted_initialize user_header_data = kwds.get('header_data', bytes()) if type(user_header_data) is not bytes: raise TypeError("'header_data' must be of type bytes. " "Invalid type: %s" % (type(user_header_data))) # we generate the first time simply to # compute the length tmp = hmac.HMAC(key=key, msg=struct.pack(cls._verify_struct_string, encrypted_block_size, block_count, 0), digestmod=hashlib.sha384).digest() header_data = bytearray( struct.pack(cls._index_struct_string, ismodegcm)) header_data[:hashlib.sha384().digest_size] = tmp header_data = header_data + user_header_data header_data = AES.GCMEnc(key, bytes(header_data)) # now that we know the length of the header data # being sent to the underlying storage we can # compute the real hmac verify_digest = hmac.HMAC(key=key, msg=struct.pack(cls._verify_struct_string, encrypted_block_size, block_count, len(header_data)), digestmod=hashlib.sha384).digest() header_data = bytearray( struct.pack(cls._index_struct_string, ismodegcm)) header_data[:hashlib.sha384().digest_size] = verify_digest header_data = header_data + user_header_data kwds['header_data'] = AES.GCMEnc(key, bytes(header_data)) return EncryptedBlockStorage(storage_type.setup( storage_name, encrypted_block_size, block_count, **kwds), key=key)
def test_setup_fails(self): self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(IOError): PathORAM.setup( os.path.join(thisdir, "baselines", "exists.empty"), block_size=10, block_count=10, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=self._test_key, key_size=self._test_key_size, aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(IOError): PathORAM.setup( os.path.join(thisdir, "baselines", "exists.empty"), block_size=10, block_count=10, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=self._test_key, key_size=self._test_key_size, storage_type=self._type_name, aes_mode=self._aes_mode, ignore_existing=False, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=1, block_count=0, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=self._test_key, key_size=self._test_key_size, aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=0, block_count=1, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=self._test_key, key_size=self._test_key_size, aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(TypeError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=self._test_key, key_size=self._test_key_size, aes_mode=self._aes_mode, storage_type=self._type_name, header_data=2, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=self._test_key, key_size=self._test_key_size, aes_mode=None, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, bucket_capacity=0, heap_base=self._heap_base, key=self._test_key, key_size=self._test_key_size, aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, bucket_capacity=self._bucket_capacity, heap_base=1, key=self._test_key, key_size=self._test_key_size, aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key_size=-1, aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(TypeError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=-1, aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=AES.KeyGen(AES.key_sizes[-1]), key_size=AES.key_sizes[-1], aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) self.assertEqual(os.path.exists(self._dummy_name), False) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=os.urandom(AES.key_sizes[-1]+100), aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds) with self.assertRaises(ValueError): PathORAM.setup( self._dummy_name, block_size=1, block_count=1, heap_height=1, bucket_capacity=self._bucket_capacity, heap_base=self._heap_base, key=self._key, aes_mode=self._aes_mode, storage_type=self._type_name, **self._kwds)