def serialize_encrypted_data_key(encrypted_data_key): """Serializes an encrypted data key. .. versionadded:: 1.3.0 :param encrypted_data_key: Encrypted data key to serialize :type encrypted_data_key: aws_encryption_sdk.structures.EncryptedDataKey :returns: Serialized encrypted data key :rtype: bytes """ encrypted_data_key_format = ( '>' # big endian 'H' # key provider ID length '{provider_id_len}s' # key provider ID 'H' # key info length '{provider_info_len}s' # key info 'H' # encrypted data key length '{enc_data_key_len}s' # encrypted data key ) return struct.pack( encrypted_data_key_format.format( provider_id_len=len(encrypted_data_key.key_provider.provider_id), provider_info_len=len(encrypted_data_key.key_provider.key_info), enc_data_key_len=len(encrypted_data_key.encrypted_data_key)), len(encrypted_data_key.key_provider.provider_id), to_bytes(encrypted_data_key.key_provider.provider_id), len(encrypted_data_key.key_provider.key_info), to_bytes(encrypted_data_key.key_provider.key_info), len(encrypted_data_key.encrypted_data_key), encrypted_data_key.encrypted_data_key)
def _generate_test_cases(): # noqa=C901 try: root_dir = os.path.abspath(file_root()) except Exception: # pylint: disable=broad-except root_dir = os.getcwd() if not os.path.isdir(root_dir): root_dir = os.getcwd() base_dir = os.path.join( root_dir, 'aws_encryption_sdk_resources' ) ciphertext_manifest_path = os.path.join( base_dir, 'manifests', 'ciphertext.manifest' ) if not os.path.isfile(ciphertext_manifest_path): # Make no test cases if the ciphertext file is not found return [] with open(ciphertext_manifest_path) as f: ciphertext_manifest = json.load(f) _test_cases = [] # Collect keys from ciphertext manifest for algorithm, keys in ciphertext_manifest['test_keys'].items(): algorithm = to_bytes(algorithm.upper()) for key_bits, key_desc in keys.items(): key_desc = to_bytes(key_desc) key_bits = int(key_bits) raw_key = to_bytes(key_desc.get('line_separator', '').join(key_desc['key'])) if key_desc['encoding'].lower() in ('raw', 'pem'): _STATIC_KEYS[algorithm][key_bits] = raw_key elif key_desc['encoding'].lower() == 'base64': _STATIC_KEYS[algorithm][key_bits] = base64.b64decode(raw_key) else: raise Exception('TODO' + 'Unknown key encoding') # Collect test cases from ciphertext manifest for test_case in ciphertext_manifest['test_cases']: key_ids = [] algorithm = aws_encryption_sdk.Algorithm.get_by_id(int(test_case['algorithm'], 16)) for key in test_case['master_keys']: sys.stderr.write('XC:: ' + json.dumps(key) + '\n') if key['provider_id'] == StaticStoredMasterKeyProvider.provider_id: key_ids.append(RawKeyDescription( key['encryption_algorithm'], key.get('key_bits', algorithm.data_key_len * 8), key.get('padding_algorithm', ''), key.get('padding_hash', '') ).key_id) if key_ids: _test_cases.append(Scenario( os.path.join(base_dir, test_case['plaintext']['filename']), os.path.join(base_dir, test_case['ciphertext']['filename']), key_ids )) return _test_cases
def _generate_test_cases(): # noqa=C901 try: root_dir = os.path.abspath(file_root()) except Exception: # pylint: disable=broad-except root_dir = os.getcwd() if not os.path.isdir(root_dir): root_dir = os.getcwd() base_dir = os.path.join(root_dir, "aws_encryption_sdk_resources") ciphertext_manifest_path = os.path.join(base_dir, "manifests", "ciphertext.manifest") if not os.path.isfile(ciphertext_manifest_path): # Make no test cases if the ciphertext file is not found return [] with open(ciphertext_manifest_path) as f: ciphertext_manifest = json.load(f) _test_cases = [] # Collect keys from ciphertext manifest for algorithm, keys in ciphertext_manifest["test_keys"].items(): algorithm = to_bytes(algorithm.upper()) for key_bits, key_desc in keys.items(): key_desc = to_bytes(key_desc) key_bits = int(key_bits) raw_key = to_bytes( key_desc.get("line_separator", "").join(key_desc["key"])) if key_desc["encoding"].lower() in ("raw", "pem"): _STATIC_KEYS[algorithm][key_bits] = raw_key elif key_desc["encoding"].lower() == "base64": _STATIC_KEYS[algorithm][key_bits] = base64.b64decode(raw_key) else: raise Exception("TODO" + "Unknown key encoding") # Collect test cases from ciphertext manifest for test_case in ciphertext_manifest["test_cases"]: key_ids = [] algorithm = aws_encryption_sdk.Algorithm.get_by_id( int(test_case["algorithm"], 16)) for key in test_case["master_keys"]: sys.stderr.write("XC:: " + json.dumps(key) + "\n") if key["provider_id"] == StaticStoredMasterKeyProvider.provider_id: key_ids.append( RawKeyDescription( key["encryption_algorithm"], key.get("key_bits", algorithm.data_key_len * 8), key.get("padding_algorithm", ""), key.get("padding_hash", ""), ).key_id) if key_ids: _test_cases.append( Scenario( os.path.join(base_dir, test_case["plaintext"]["filename"]), os.path.join(base_dir, test_case["ciphertext"]["filename"]), key_ids, )) return _test_cases
def serialize_wrapped_key(key_provider, wrapping_algorithm, wrapping_key_id, encrypted_wrapped_key): """Serializes EncryptedData into a Wrapped EncryptedDataKey. :param key_provider: Info for Wrapping MasterKey :type key_provider: aws_encryption_sdk.structure.MasterKeyInfo :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext_data_key :type wrapping_algorithm: aws_encryption_sdk.identifiers.WrappingAlgorithm :param bytes wrapping_key_id: Key ID of wrapping MasterKey :param encrypted_wrapped_key: Encrypted data key :type encrypted_wrapped_key: aws_encryption_sdk.internal.structures.EncryptedData :returns: Wrapped EncryptedDataKey :rtype: aws_encryption_sdk.structure.EncryptedDataKey """ if encrypted_wrapped_key.iv is None: key_info = wrapping_key_id key_ciphertext = encrypted_wrapped_key.ciphertext else: key_info = struct.pack( '>{key_id_len}sII{iv_len}s'.format( key_id_len=len(wrapping_key_id), iv_len=wrapping_algorithm.algorithm.iv_len), to_bytes(wrapping_key_id), len(encrypted_wrapped_key.tag) * 8, # Tag Length is stored in bits, not bytes wrapping_algorithm.algorithm.iv_len, encrypted_wrapped_key.iv) key_ciphertext = encrypted_wrapped_key.ciphertext + encrypted_wrapped_key.tag return EncryptedDataKey(key_provider=MasterKeyInfo( provider_id=key_provider.provider_id, key_info=key_info), encrypted_data_key=key_ciphertext)
def read(self, b=-1): """Keep reading from source stream until either the source stream is done or the requested number of bytes have been obtained. :param int b: number of bytes to read :return: All bytes read from wrapped stream :rtype: bytes """ remaining_bytes = b data = io.BytesIO() while True: try: chunk = to_bytes(self.__wrapped__.read(remaining_bytes)) except ValueError: if self.__wrapped__.closed: break raise if not chunk: break data.write(chunk) remaining_bytes -= len(chunk) if remaining_bytes <= 0: break return data.getvalue()
def test_default_values(patch_uuid4): mock_uuid = "this is not actually a uuid" patch_uuid4.return_value = mock_uuid test = build_ccmm() assert test.max_messages_encrypted == MAX_MESSAGES_PER_KEY assert test.max_bytes_encrypted == MAX_BYTES_PER_KEY assert test.partition_name == to_bytes(mock_uuid)
def serialize_raw_master_key_prefix(raw_master_key): """Produces the prefix that a RawMasterKey will always use for the key_info value of keys which require additional information. :param raw_master_key: RawMasterKey for which to produce a prefix :type raw_master_key: aws_encryption_sdk.key_providers.raw.RawMasterKey :returns: Serialized key_info prefix :rtype: bytes """ if raw_master_key.config.wrapping_key.wrapping_algorithm.encryption_type is EncryptionType.ASYMMETRIC: return to_bytes(raw_master_key.key_id) return struct.pack( '>{}sII'.format(len(raw_master_key.key_id)), to_bytes(raw_master_key.key_id), raw_master_key.config.wrapping_key.wrapping_algorithm.algorithm.tag_len * 8, # Tag Length is stored in bits, not bytes raw_master_key.config.wrapping_key.wrapping_algorithm.algorithm.iv_len)
def add_master_key(self, key_id): """Adds a single Master Key to this provider. :param bytes key_id: Key ID with which to create MasterKey """ key_id = to_bytes(key_id) if key_id not in self._encrypt_key_index: master_key = self._new_master_key(key_id) self._members.append(master_key) self._encrypt_key_index[key_id] = master_key
def master_key_for_encrypt(self, key_id): """Returns a master key for encrypt based on the specified key_id, adding it to this provider if not already present. :param bytes key_id: Key ID with which to find or create Master Key :returns: Master Key based on key_id :rtype: aws_encryption_sdk.key_providers.base.MasterKey """ key_id = to_bytes(key_id) self.add_master_key(key_id) return self._encrypt_key_index[key_id]
def prep_stream_data(data): """Take an input and prepare it for use as a stream. :param data: Input data :returns: Prepared stream :rtype: io.BytesIO """ if isinstance(data, (six.string_types, six.binary_type)): return io.BytesIO(to_bytes(data)) return data
def _ecc_decode_compressed_point(curve, compressed_point): """Decodes a compressed elliptic curve point as described in SEC-1 v2 section 2.3.4 http://www.secg.org/sec1-v2.pdf :param curve: Elliptic curve type to generate :type curve: cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve :param bytes compressed_point: Encoded compressed elliptic curve point :returns: X and Y coordinates from compressed point :rtype: tuple of longs :raises NotSupportedError: for non-prime curves, unsupported prime curves, and points at infinity """ if not compressed_point: raise NotSupportedError('Points at infinity are not allowed') yp_map = {b'\x02': 0, b'\x03': 1} X = compressed_point[1:] X = to_bytes(X) x = cryptography.utils.int_from_bytes(X, 'big') Y = compressed_point[0] # In Python3, bytes index calls return int values rather than strings if isinstance(Y, six.integer_types): Y = six.b(chr(Y)) elif isinstance(Y, six.string_types): Y = six.b(Y) yp = yp_map[Y] # If curve in prime field. if curve.name.startswith('secp'): try: params = _ECC_CURVE_PARAMETERS[curve.name] except KeyError: raise NotSupportedError( 'Curve {name} is not supported at this time'.format( name=curve.name)) alpha = (pow(x, 3, params.p) + (params.a * x % params.p) + params.b) % params.p # Only works for p % 4 == 3 at this time. # TODO: This is the case for all currently supported algorithms # This will need to be expanded if curves which do not match this are added. # Python-ecdsa has these algorithms implemented. Copy or reference? # https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm # Handbook of Applied Cryptography, algorithms 3.34 - 3.39 if params.p % 4 == 3: beta = pow(alpha, (params.p + 1) // 4, params.p) else: raise NotSupportedError( 'S not 1 :: Curve not supported at this time') if beta % 2 == yp: y = beta else: y = params.p - beta else: raise NotSupportedError( 'Non-prime curves are not supported at this time') return x, y
def prep_stream_data(data): """Takes an input str, bytes, io.IOBase, or file object and returns an appropriate stream for _EncryptionStream objects. :param data: Input data :type data: str, bytes, io.IOBase, or file :returns: Prepared stream :rtype: io.BytesIO """ if isinstance(data, (_FILE_TYPE, io.IOBase, six.StringIO)): return data return io.BytesIO(to_bytes(data))
def prep_stream_data(data): """Take an input and prepare it for use as a stream. :param data: Input data :returns: Prepared stream :rtype: InsistentReaderBytesIO """ if isinstance(data, (six.string_types, six.binary_type)): stream = io.BytesIO(to_bytes(data)) else: stream = data return InsistentReaderBytesIO(stream)
def master_key_for_decrypt(self, key_info): """Returns a master key for decrypt based on the specified key_info. This is only added to this master key provider for the decrypt path. :param bytes key_info: Key info from encrypted data key :returns: Master Key based on key_info :rtype: aws_encryption_sdk.key_providers.base.MasterKey """ key_info = to_bytes(key_info) try: return self._encrypt_key_index[key_info] except KeyError: pass # Not found in encrypt key index try: return self._decrypt_key_index[key_info] except KeyError: pass # Not found in decrypt key index decrypt_master_key = self._new_master_key(key_info) self._decrypt_key_index[key_info] = decrypt_master_key return decrypt_master_key
def __attrs_post_init__(self): """Applies post-processing which cannot be handled by attrs.""" if self.max_messages_encrypted < 1: raise ValueError("max_messages_encrypted cannot be less than 1") if self.max_bytes_encrypted < 0: raise ValueError("max_bytes_encrypted cannot be less than 0") if self.max_messages_encrypted > MAX_MESSAGES_PER_KEY: raise ValueError("max_messages_encrypted cannot exceed {}".format( MAX_MESSAGES_PER_KEY)) if self.max_bytes_encrypted > MAX_BYTES_PER_KEY: raise ValueError("max_bytes_encrypted cannot exceed {}".format( MAX_BYTES_PER_KEY)) if self.max_age <= 0.0: raise ValueError("max_age cannot be less than or equal to 0") options_provided = [ option is not None for option in (self.backing_materials_manager, self.keyring, self.master_key_provider) ] provided_count = len([is_set for is_set in options_provided if is_set]) if provided_count != 1: raise TypeError( "Exactly one of 'backing_materials_manager', 'keyring', or 'key_provider' must be provided" ) if self.backing_materials_manager is None: if self.master_key_provider is not None: self.backing_materials_manager = DefaultCryptoMaterialsManager( master_key_provider=self.master_key_provider) else: self.backing_materials_manager = DefaultCryptoMaterialsManager( keyring=self.keyring) if self.partition_name is None: self.partition_name = to_bytes(str(uuid.uuid4()))
def serialize_header(header, signer=None): """Serializes a header object. :param header: Header to serialize :type header: aws_encryption_sdk.structure.MessageHeader :param signer: Cryptographic signer object (optional) :type signer: aws_encryption_sdk.internal.crypto.Signer :returns: Serialized header :rtype: bytes """ ec_serialized = aws_encryption_sdk.internal.formatting.encryption_context.serialize_encryption_context( header.encryption_context) header_start_format = ( '>' # big endian 'B' # version 'B' # type 'H' # algorithm ID '16s' # message ID 'H' # encryption context length '{}s' # serialized encryption context ).format(len(ec_serialized)) header_bytes = bytearray() header_bytes.extend( struct.pack(header_start_format, header.version.value, header.type.value, header.algorithm.algorithm_id, header.message_id, len(ec_serialized), ec_serialized)) encrypted_data_key_format = ( '>' # bit endian 'H' # key provider ID length '{provider_id_len}s' # key provider ID 'H' # key info length '{provider_info_len}s' # key info 'H' # encrypted data key length '{enc_data_key_len}s' # encrypted data key ) serialized_data_keys = bytearray() for data_key in header.encrypted_data_keys: serialized_data_keys.extend( struct.pack( encrypted_data_key_format.format( provider_id_len=len(data_key.key_provider.provider_id), provider_info_len=len(data_key.key_provider.key_info), enc_data_key_len=len(data_key.encrypted_data_key)), len(data_key.key_provider.provider_id), to_bytes(data_key.key_provider.provider_id), len(data_key.key_provider.key_info), to_bytes(data_key.key_provider.key_info), len(data_key.encrypted_data_key), data_key.encrypted_data_key)) header_bytes.extend(struct.pack('>H', len(header.encrypted_data_keys))) header_bytes.extend(serialized_data_keys) header_close_format = ( '>' # big endian 'B' # content type (no framing vs framing) '4x' # reserved (formerly content AAD length) 'B' # nonce/IV length, this applies to all IVs in this message 'I' # frame length ) header_bytes.extend( struct.pack(header_close_format, header.content_type.value, header.algorithm.iv_len, header.frame_length)) output = bytes(header_bytes) if signer is not None: signer.update(output) return output