Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
    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()
Exemplo n.º 6
0
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)
Exemplo n.º 7
0
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)
Exemplo n.º 8
0
    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
Exemplo n.º 9
0
    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]
Exemplo n.º 10
0
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
Exemplo n.º 11
0
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
Exemplo n.º 12
0
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))
Exemplo n.º 13
0
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)
Exemplo n.º 14
0
    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
Exemplo n.º 15
0
    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()))
Exemplo n.º 16
0
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