def generate_asymmetric(self, generate_dto, kek_meta_dto, project_id): """Generate asymmetric keys based on below rules: - RSA, with passphrase (supported) - RSA, without passphrase (supported) - DSA, without passphrase (supported) - DSA, with passphrase (not supported) Note: PyCrypto is not capable of serializing DSA keys and DER formated keys. Such keys will be serialized to Base64 PEM to store in DB. TODO (atiwari/reaperhulk): PyCrypto is not capable to serialize DSA keys and DER formated keys, later we need to pick better crypto lib. """ if (generate_dto.algorithm is None or generate_dto.algorithm.lower() == 'rsa'): private_key = RSA.generate(generate_dto.bit_length, None, None, 65537) elif generate_dto.algorithm.lower() == 'dsa': private_key = DSA.generate(generate_dto.bit_length, None, None) else: raise c.CryptoPrivateKeyFailureException() public_key = private_key.publickey() # Note (atiwari): key wrapping format PEM only supported if generate_dto.algorithm.lower() == 'rsa': public_key, private_key = self._wrap_key(public_key, private_key, generate_dto.passphrase) if generate_dto.algorithm.lower() == 'dsa': if generate_dto.passphrase: raise ValueError(u._('Passphrase not supported for DSA key')) public_key, private_key = self._serialize_dsa_key( public_key, private_key) private_dto = self.encrypt(c.EncryptDTO(private_key), kek_meta_dto, project_id) public_dto = self.encrypt(c.EncryptDTO(public_key), kek_meta_dto, project_id) passphrase_dto = None if generate_dto.passphrase: if isinstance(generate_dto.passphrase, six.text_type): generate_dto.passphrase = generate_dto.passphrase.encode( 'utf-8') passphrase_dto = self.encrypt( c.EncryptDTO(generate_dto.passphrase), kek_meta_dto, project_id) return private_dto, public_dto, passphrase_dto
def test_encrypt_bad_session(self): self.pkcs11.get_session.return_value = mock.DEFAULT self.pkcs11.get_session.side_effect = pkcs11.P11CryptoPluginException( 'Testing error handling' ) payload = b'test payload' encrypt_dto = plugin_import.EncryptDTO(payload) kek_meta = mock.MagicMock() kek_meta.kek_label = 'pkek' kek_meta.plugin_meta = ('{"iv": "iv==",' '"hmac": "hmac",' '"wrapped_key": "wrappedkey==",' '"mkek_label": "mkek_label",' '"hmac_label": "hmac_label"}') self.assertRaises(pkcs11.P11CryptoPluginException, self.plugin.encrypt, encrypt_dto, kek_meta, mock.MagicMock()) self.assertEqual(self.pkcs11.get_key_handle.call_count, 2) self.assertEqual(self.pkcs11.get_session.call_count, 2) self.assertEqual(self.pkcs11.verify_hmac.call_count, 1) self.assertEqual(self.pkcs11.unwrap_key.call_count, 1) self.assertEqual(self.pkcs11.encrypt.call_count, 0) self.assertEqual(self.pkcs11.return_session.call_count, 0)
def test_encrypt_with_unicode_kek_must_pass(self): """Test plan: Generate a kek Encrypt with master kek Convert to unicode call plugin.encrypt on unencrypted decrypt response cypher_text Compare with unencrypted """ project_kek = fernet.Fernet.generate_key() encryptor = fernet.Fernet(self.plugin.master_kek) ENC_project_kek = encryptor.encrypt(project_kek) UENC_project_kek = six.u(ENC_project_kek) kek_meta_dto = self._get_mocked_kek_meta_dto() kek_meta_dto.plugin_meta = UENC_project_kek unencrypted = b'PlainTextSecret' encrypt_dto = plugin.EncryptDTO(unencrypted) response_dto = self.plugin.encrypt(encrypt_dto, kek_meta_dto, mock.MagicMock()) project_encryptor = fernet.Fernet(project_kek) decrypted = project_encryptor.decrypt(response_dto.cypher_text) self.assertEqual(unencrypted, decrypted)
def store_secret(self, secret_dto, context): """Store a secret. :param secret_dto: SecretDTO for secret :param context: StoreCryptoContext for secret :returns: an optional dictionary containing metadata about the secret """ # Find HSM-style 'crypto' plugin. encrypting_plugin = manager.get_manager().get_plugin_store_generate( crypto.PluginSupportTypes.ENCRYPT_DECRYPT) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( encrypting_plugin, context.project_model) # Secrets are base64 encoded before being passed to the secret stores. secret_bytes = base64.b64decode(secret_dto.secret) encrypt_dto = crypto.EncryptDTO(secret_bytes) # Enhance the context with content_type, This is needed to build # datum_model to store if not context.content_type: context.content_type = secret_dto.content_type # Create an encrypted datum instance and add the encrypted cyphertext. response_dto = encrypting_plugin.encrypt( encrypt_dto, kek_meta_dto, context.project_model.external_id) # Convert binary data into a text-based format. _store_secret_and_datum(context, context.secret_model, kek_datum_model, response_dto) return None
def generate_symmetric(self, generate_dto, kek_meta_dto, project_id): byte_length = generate_dto.bit_length / 8 session = self.pkcs11.create_working_session() buf = self.pkcs11.generate_random(byte_length, session) self.pkcs11.close_session(session) rand = self.pkcs11.ffi.buffer(buf)[:] assert len(rand) == byte_length return self.encrypt(plugin.EncryptDTO(rand), kek_meta_dto, project_id)
def test_byte_string_encryption(self): unencrypted = b'some_secret' encrypt_dto = plugin.EncryptDTO(unencrypted) kek_meta_dto = self._get_mocked_kek_meta_dto() response_dto = self.plugin.encrypt(encrypt_dto, kek_meta_dto, mock.MagicMock()) decrypt_dto = plugin.DecryptDTO(response_dto.cypher_text) decrypted = self.plugin.decrypt(decrypt_dto, kek_meta_dto, response_dto.kek_meta_extended, mock.MagicMock()) self.assertEqual(unencrypted, decrypted)
def test_random_bytes_encryption(self): unencrypted = os.urandom(10) encrypt_dto = plugin.EncryptDTO(unencrypted) kek_meta_dto = self._get_mocked_kek_meta_dto() response_dto = self.plugin.encrypt(encrypt_dto, kek_meta_dto, mock.MagicMock()) decrypt_dto = plugin.DecryptDTO(response_dto.cypher_text) decrypted = self.plugin.decrypt(decrypt_dto, kek_meta_dto, response_dto.kek_meta_extended, mock.MagicMock()) self.assertEqual(unencrypted, decrypted)
def test_encrypt(self): payload = 'encrypt me!!' self.lib.C_EncryptInit.return_value = p11_crypto.CKR_OK self.lib.C_Encrypt.return_value = p11_crypto.CKR_OK encrypt_dto = plugin_import.EncryptDTO(payload) with mock.patch.object(self.plugin, '_unwrap_key') as unwrap_key_mock: unwrap_key_mock.return_value = 'unwrapped_key' response_dto = self.plugin.encrypt(encrypt_dto, mock.MagicMock(), mock.MagicMock()) self.assertEqual(self.lib.C_Encrypt.call_count, 1) self.assertEqual(response_dto.cypher_text, b"\x00" * 32)
def test_encrypt_unicode_raises_value_error(self): unencrypted = u'unicode_beer\U0001F37A' encrypt_dto = plugin.EncryptDTO(unencrypted) secret = mock.MagicMock() secret.mime_type = 'text/plain' kek_meta_dto = self._get_mocked_kek_meta_dto() self.assertRaises( ValueError, self.plugin.encrypt, encrypt_dto, kek_meta_dto, mock.MagicMock(), )
def test_encrypt(self): payload = 'encrypt me!!' self.lib.C_EncryptInit.return_value = pkcs11.CKR_OK self.lib.C_Encrypt.return_value = pkcs11.CKR_OK encrypt_dto = plugin_import.EncryptDTO(payload) kek_meta = mock.MagicMock() kek_meta.plugin_meta = ('{"iv":123,' '"hmac": "hmac",' '"wrapped_key": "wrapped_key",' '"mkek_label": "mkek_label",' '"hmac_label": "hmac_label"}') with mock.patch.object(self.plugin.pkcs11, 'unwrap_key') as key_mock: key_mock.return_value = 'unwrapped_key' response_dto = self.plugin.encrypt(encrypt_dto, kek_meta, mock.MagicMock()) self.assertEqual(self.lib.C_Encrypt.call_count, 1) self.assertEqual(response_dto.cypher_text, b"\x00" * 32)
def test_encrypt(self): payload = b'test payload' encrypt_dto = plugin_import.EncryptDTO(payload) kek_meta = mock.MagicMock() kek_meta.kek_label = 'pkek' kek_meta.plugin_meta = ('{"iv": "iv==",' '"hmac": "hmac",' '"wrapped_key": "wrappedkey==",' '"mkek_label": "mkek_label",' '"hmac_label": "hmac_label"}') response_dto = self.plugin.encrypt(encrypt_dto, kek_meta, mock.MagicMock()) self.assertEqual(b'0', response_dto.cypher_text) self.assertIn('iv', response_dto.kek_meta_extended) self.assertEqual(2, self.pkcs11.get_key_handle.call_count) self.assertEqual(2, self.pkcs11.get_session.call_count) self.assertEqual(1, self.pkcs11.verify_hmac.call_count) self.assertEqual(1, self.pkcs11.unwrap_key.call_count) self.assertEqual(1, self.pkcs11.encrypt.call_count) self.assertEqual(1, self.pkcs11.return_session.call_count)
def generate_symmetric(self, generate_dto, kek_meta_dto, project_id): byte_length = generate_dto.bit_length / 8 buf = self._generate_random(byte_length) rand = self.ffi.buffer(buf)[:] assert len(rand) == byte_length return self.encrypt(plugin.EncryptDTO(rand), kek_meta_dto, project_id)
def generate_symmetric(self, generate_dto, kek_meta_dto, project_id): byte_length = int(generate_dto.bit_length) // 8 unencrypted = os.urandom(byte_length) return self.encrypt(c.EncryptDTO(unencrypted), kek_meta_dto, project_id)