1 __all__ = ('EncryptedBlockStorage',)
7 from pyoram.storage.block_storage import (BlockStorageInterface,
8 BlockStorageTypeFactory)
9 from pyoram.crypto.aes import AES
13 class EncryptedBlockStorageInterface(BlockStorageInterface):
20 def key(self, *args, **kwds):
21 raise NotImplementedError # pragma: no cover
23 def raw_storage(self, *args, **kwds):
24 raise NotImplementedError # pragma: no cover
26 class EncryptedBlockStorage(EncryptedBlockStorageInterface):
28 _index_struct_string = "!"+("x"*hashlib.sha384().digest_size)+"?"
29 _index_offset = struct.calcsize(_index_struct_string)
30 _verify_struct_string = "!LLL"
31 _verify_size = struct.calcsize(_verify_struct_string)
33 def __init__(self, storage, **kwds):
34 self._key = kwds.pop('key', None)
37 "An encryption key is required using "
39 if isinstance(storage, BlockStorageInterface):
41 self._storage = storage
44 "Keywords not used when initializing "
45 "with a storage device: %s"
49 storage_type = kwds.pop('storage_type', 'file')
51 BlockStorageTypeFactory(storage_type)(storage, **kwds)
54 header_data = AES.GCMDec(self._key,
55 self._storage.header_data)
56 (self._ismodegcm,) = struct.unpack(
57 self._index_struct_string,
58 header_data[:self._index_offset])
59 self._verify_digest = header_data[:hashlib.sha384().digest_size]
63 msg=struct.pack(self._verify_struct_string,
64 self._storage.block_size,
65 self._storage.block_count,
66 len(self._storage.header_data)),
67 digestmod=hashlib.sha384)
68 if verify.digest() != self._verify_digest:
70 "HMAC of plaintext index data does not match")
72 self._encrypt_block_func = AES.GCMEnc
73 self._decrypt_block_func = AES.GCMDec
75 self._encrypt_block_func = AES.CTREnc
76 self._decrypt_block_func = AES.CTRDec
83 # Define EncryptedBlockStorageInterface Methods
91 def raw_storage(self):
95 # Define BlockStorageInterface Methods
98 def clone_device(self):
99 return EncryptedBlockStorage(self._storage.clone_device(),
103 def compute_storage_size(cls,
110 assert (block_size > 0) and (block_size == int(block_size))
111 assert (block_count > 0) and (block_count == int(block_count))
112 assert aes_mode in ('ctr', 'gcm')
113 if not isinstance(storage_type, BlockStorageInterface):
114 storage_type = BlockStorageTypeFactory(storage_type)
116 if aes_mode == 'ctr':
117 extra_block_data = AES.block_size
119 assert aes_mode == 'gcm'
120 extra_block_data = 2 * AES.block_size
122 return (extra_block_data * block_count) + \
123 storage_type.compute_storage_size(
129 return cls._index_offset + \
130 2 * AES.block_size + \
131 (extra_block_data * block_count) + \
132 storage_type.compute_storage_size(
150 if (key is not None) and (key_size is not None):
152 "Only one of 'key' or 'keysize' keywords can "
153 "be specified at a time")
156 key_size = AES.key_sizes[-1]
157 if key_size not in AES.key_sizes:
159 "Invalid key size: %s" % (key_size))
160 key = AES.KeyGen(key_size)
162 if len(key) not in AES.key_sizes:
164 "Invalid key size: %s" % (len(key)))
166 if (block_size <= 0) or (block_size != int(block_size)):
168 "Block size (bytes) must be a positive integer: %s"
172 encrypt_block_func = None
173 encrypted_block_size = block_size
174 if aes_mode == 'ctr':
176 encrypt_block_func = AES.CTREnc
177 encrypted_block_size += AES.block_size
178 elif aes_mode == 'gcm':
180 encrypt_block_func = AES.GCMEnc
181 encrypted_block_size += (2 * AES.block_size)
184 "AES encryption mode must be one of 'ctr' or 'gcm'. "
185 "Invalid value: %s" % (aes_mode))
186 assert ismodegcm is not None
187 assert encrypt_block_func is not None
189 if not isinstance(storage_type, BlockStorageInterface):
190 storage_type = BlockStorageTypeFactory(storage_type)
192 if initialize is None:
193 zeros = bytes(bytearray(block_size))
194 initialize = lambda i: zeros
195 def encrypted_initialize(i):
196 return encrypt_block_func(key, initialize(i))
197 kwds['initialize'] = encrypted_initialize
199 user_header_data = kwds.get('header_data', bytes())
200 if type(user_header_data) is not bytes:
202 "'header_data' must be of type bytes. "
203 "Invalid type: %s" % (type(user_header_data)))
204 # we generate the first time simply to
208 msg=struct.pack(cls._verify_struct_string,
209 encrypted_block_size,
212 digestmod=hashlib.sha384).digest()
213 header_data = bytearray(struct.pack(cls._index_struct_string,
215 header_data[:hashlib.sha384().digest_size] = tmp
216 header_data = header_data + user_header_data
217 header_data = AES.GCMEnc(key, bytes(header_data))
218 # now that we know the length of the header data
219 # being sent to the underlying storage we can
220 # compute the real hmac
221 verify_digest = hmac.HMAC(
223 msg=struct.pack(cls._verify_struct_string,
224 encrypted_block_size,
227 digestmod=hashlib.sha384).digest()
228 header_data = bytearray(struct.pack(cls._index_struct_string,
230 header_data[:hashlib.sha384().digest_size] = verify_digest
231 header_data = header_data + user_header_data
232 kwds['header_data'] = AES.GCMEnc(key, bytes(header_data))
234 return EncryptedBlockStorage(
235 storage_type.setup(storage_name,
236 encrypted_block_size,
242 def header_data(self):
243 return AES.GCMDec(self._key,
244 self._storage.header_data)\
245 [self._index_offset:]
248 def block_count(self):
249 return self._storage.block_count
252 def block_size(self):
254 return self._storage.block_size - 2 * AES.block_size
256 return self._storage.block_size - AES.block_size
259 def storage_name(self):
260 return self._storage.storage_name
262 def update_header_data(self, new_header_data):
263 self._storage.update_header_data(
266 AES.GCMDec(self._key,
267 self._storage.header_data)\
268 [:self._index_offset] + \
272 self._storage.close()
285 def read_block(self, i):
286 a = self._storage.read_block(i)
287 return self._decrypt_block_func(self._key,a)
289 def read_blocks(self, indices, *args, **kwds):
290 a = self._storage.read_blocks(indices, *args, **kwds)
291 return [self._decrypt_block_func(self._key, b) for b in a]
293 def yield_blocks(self, indices, *args, **kwds):
294 for b in self._storage.yield_blocks(indices, *args, **kwds):
295 yield self._decrypt_block_func(self._key, b)
298 def write_block(self, i, block, *args, **kwds):
299 a = self._encrypt_block_func(self._key, block)
300 self._storage.write_block(i, a,*args, **kwds)
302 def write_blocks(self, indices, blocks, *args, **kwds):
304 for i, b in zip(indices, blocks):
305 enc_blocks.append(self._encrypt_block_func(self._key, b))
308 self._storage.write_blocks(indices, enc_blocks, *args, **kwds)
321 def bytes_sent(self):
322 return self._storage.bytes_sent
325 def bytes_received(self):
326 return self._storage.bytes_received