def test_replace_key(self): """ Test replacing the key (and re-encrypting the database). """ self.assertTrue(util.has_encrypted_data()) # Create a new key ekey = hashlib.sha256('new-encrypt').digest() skey = hashlib.sha256('new-sign').digest() new_key = MasterKey(encryption_key=ekey, signing_key=skey) with self.assertRaises(exc.DatabaseAlreadyEncrypted): util.replace_key(new_key) # Check existing passwords for an arbitrary user for (i,pw) in enumerate(self.data.resources['host1.example.com'].passwords.order_by('username')): self.assertEquals('password{0}'.format(i), pw.password_decrypted) util.replace_key(new_key, force=True) # The replace_key functions updates the global state, so this should work: for (i,pw) in enumerate(self.data.resources['host1.example.com'].passwords.order_by('username')): self.assertEquals('password{0}'.format(i), pw.password_decrypted) # But using the old key should, of course, now fail: for (i,pw) in enumerate(self.data.resources['host1.example.com'].passwords.order_by('username')): with self.assertRaises(exc.CryptoAuthenticationFailed): engine.decrypt(pw.password, key=self.SECRET_KEY)
def test_empty(self): """ Test encrypt/decrypt behavior when using empty/None values. """ self.assertNotEquals("", engine.encrypt(""), "Expected empty strings to actually be encryptable.") self.assertIs(None, engine.encrypt(None)) self.assertEquals(None, engine.decrypt("")) self.assertIs(None, engine.decrypt(None))
def validate_key(key): """ Checks the key against an encrypted blob in the database. :param key: The master key to check. :type key: ensconce.crypto.MasterKey :raise ensconce.exc.MissingKeyMetadata: If the metadata row does not exist yet. :raise ensconce.exc.MultipleKeyMetadata: If there are multiple metadata rows. :raise ensconce.exc.UnconfiguredModel: If we can't create an SA session. """ if meta.Session is None: raise exc.UnconfiguredModel() session = meta.Session() try: key_info = session.query(model.KeyMetadata).one() # log.debug("Got bytes for validation: {0!r}".format(key_info.validation)) try: decrypted = engine.decrypt(key_info.validation, key=key) # log.debug("Decrypts to: {0!r}".format(decrypted)) except exc.CryptoAuthenticationFailed: log.exception("Validation fails due to error decrypting block.") return False else: return True except NoResultFound: raise exc.MissingKeyMetadata() except MultipleResultsFound: raise exc.CryptoError("Multiple key metadata rows are not supported.") except: log.exception("Error validating encryption key.") raise
def password_decrypted(self): # The unicode conversion *seems* like overkill, but is probably the safe thing to do. decrypted = engine.decrypt(self.password) if decrypted is not None: return unicode(decrypted, 'utf-8') else: return decrypted
def test_encrypt_decrypt(self): """ Basic encryption/decryption tests. """ # 012345678901234567890123456789012345678901234567890123456789 # 1 2 3 4 5 6 a = "The slow dog jumped over." b = "The slow dog jumped over the brown fox." c = "The slow dog jumped over the brown fox and the roosters too." a_c = engine.encrypt(a) self.assertIsInstance(a_c, str) self.assertEquals(a, engine.decrypt(a_c)) b_c = engine.encrypt(b) self.assertEquals(b, engine.decrypt(b_c)) c_c = engine.encrypt(c) self.assertEquals(c, engine.decrypt(c_c))
def test_decrypt_garbage(self): """ Test that exceptions are raised when decrypt input is garbage. """ data = os.urandom(100) # 100 bytes of garbage with self.assertRaises(exc.CryptoAuthenticationFailed): engine.decrypt(data) # We'll also make it look more like the expected data format with self.assertRaises(exc.CryptoAuthenticationFailed): engine.decrypt(binascii.hexlify(data)) # And finally we'll even add a pad string, but we still expect # an error like "Input strings must be a multiple of 16 in length." with self.assertRaises(exc.CryptoAuthenticationFailed): engine.decrypt(binascii.hexlify(("%02d" % 10) + data))
def test_binary(self): """ Test encrypt/decrypt of non-ascii data. """ data = os.urandom(100) # 100 bytes of binary data data_c = engine.encrypt(data) self.assertEquals(data, engine.decrypt(data_c))
def notes_decrypted(self): decrypted = engine.decrypt(self.notes) if decrypted is not None: return unicode(decrypted, 'utf-8') else: return decrypted
def password_decrypted(self): return engine.decrypt(self.password)