def test_wrap_invalid_key_to_wrap_length(self, backend): # Keys to wrap must be at least 16 bytes long with pytest.raises(ValueError): keywrap.aes_key_wrap(b"sixteen_byte_key", b"\x00" * 15, backend) # Keys to wrap must be a multiple of 8 bytes with pytest.raises(ValueError): keywrap.aes_key_wrap(b"sixteen_byte_key", b"\x00" * 23, backend)
def generate_data_key(self): # -> tuple[bytes, bytes]: data_key = os.urandom(32) encrypted_data_key = aes_key_wrap( wrapping_key=self._key_bytes, key_to_wrap=data_key, ) return data_key, encrypted_data_key
def wrap(self, key, bitsize, cek, headers): rk = self._get_key(key, 'encrypt') if not cek: cek = _randombits(bitsize) ek = aes_key_wrap(rk, cek, default_backend()) return {'cek': cek, 'ek': ek}
def aes_key_wrap(self, kek: bytes, key_to_wrap: bytes) -> bytes: """Wraps a key using a key-encrypting key (KEK). :param kek: The key-encrypting key :param key_to_wrap: Plain data :return: Wrapped key """ return keywrap.aes_key_wrap(kek, key_to_wrap, default_backend())
def wrap_unwrap(key_1, key_2): # Function to wrap and unwrap keys backend = default_backend() wrapped_key = keywrap.aes_key_wrap( key_2, key_1, backend=backend) # Wrap key 1 with key 2 unwrapped_key = keywrap.aes_key_unwrap( key_2, wrapped_key, backend=backend) # Unwrapped the wrapped key with the key 2 return wrapped_key, unwrapped_key
def wrap_key(security_control: SecurityControlField, wrapping_key: bytes, key_to_wrap: bytes): """ Simple function to wrap a key for transfer """ validate_key(security_control.security_suite, wrapping_key) validate_key(security_control.security_suite, key_to_wrap) wrapped_key = aes_key_wrap(wrapping_key, key_to_wrap) return wrapped_key
def test_wrap(self, backend, subtests): params = _load_all_params( os.path.join("keywrap", "kwtestvectors"), ["KW_AE_128.txt", "KW_AE_192.txt", "KW_AE_256.txt"], load_nist_vectors, ) for param in params: with subtests.test(): wrapping_key = binascii.unhexlify(param["k"]) key_to_wrap = binascii.unhexlify(param["p"]) wrapped_key = keywrap.aes_key_wrap(wrapping_key, key_to_wrap, backend) assert param["c"] == binascii.hexlify(wrapped_key)
def encrypt(cls, pk, *args): """ For convenience, the synopsis of the encoding method is given below; however, this section, [NIST-SP800-56A], and [RFC3394] are the normative sources of the definition. Obtain the authenticated recipient public key R Generate an ephemeral key pair {v, V=vG} Compute the shared point S = vR; m = symm_alg_ID || session key || checksum || pkcs5_padding; curve_OID_len = (byte)len(curve_OID); Param = curve_OID_len || curve_OID || public_key_alg_ID || 03 || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous Sender " || recipient_fingerprint; Z_len = the key size for the KEK_alg_ID used with AESKeyWrap Compute Z = KDF( S, Z_len, Param ); Compute C = AESKeyWrap( Z, m ) as per [RFC3394] VB = convert point V to the octet string Output (MPI(VB) || len(C) || C). The decryption is the inverse of the method given. Note that the recipient obtains the shared secret by calculating """ # *args should be: # - m # _m, = args # m may need to be PKCS5-padded padder = PKCS7(64).padder() m = padder.update(_m) + padder.finalize() km = pk.keymaterial ct = cls() # generate ephemeral key pair, then store it in ct v = ec.generate_private_key(km.oid.curve(), default_backend()) ct.vX = MPI(v.public_key().public_numbers().x) ct.vY = MPI(v.public_key().public_numbers().y) # compute the shared point S s = v.exchange(ec.ECDH(), km.__pubkey__()) # derive the wrapping key z = km.kdf.derive_key(s, km.oid, PubKeyAlgorithm.ECDH, pk.fingerprint) # compute C ct.c = aes_key_wrap(z, m, default_backend()) return ct
def wrap_key_aes(key_to_wrap, wrapping_key=None): """ Wraps a key using the AES key wrapping mode of operation as specified in https://www.ietf.org/rfc/rfc3394.txt :param key_to_wrap: the key to be wrapped in the process. :param wrapping_key: the key to be used to wrap the key = KEK, If non is provided, it is generated randomly :return: the wrapped key as well as the used key as (wrapped_result, wrapping_key) """ # checking if key needs to be generated if wrapping_key is None: wrapping_key = os.urandom(len(key_to_wrap)) return keywrap.aes_key_wrap(wrapping_key, key_to_wrap, default_backend()), wrapping_key
def test_keywrap(backend, wycheproof): wrapping_key = binascii.unhexlify(wycheproof.testcase["key"]) key_to_wrap = binascii.unhexlify(wycheproof.testcase["msg"]) expected = binascii.unhexlify(wycheproof.testcase["ct"]) if (wycheproof.valid or (wycheproof.acceptable and wycheproof.testcase["comment"] != "invalid size of wrapped key")): result = keywrap.aes_key_wrap(wrapping_key, key_to_wrap, backend) assert result == expected if wycheproof.valid or wycheproof.acceptable: result = keywrap.aes_key_unwrap(wrapping_key, expected, backend) assert result == key_to_wrap else: with pytest.raises(keywrap.InvalidUnwrap): keywrap.aes_key_unwrap(wrapping_key, expected, backend)
def encrypt(self, key, iv="", cek="", **kwargs): """ Produces a JWE as defined in RFC7516 using symmetric keys :param key: Shared symmetric key :param iv: Initialization vector :param cek: Content master key :param kwargs: Extra keyword arguments, just ignore for now. :return: """ _msg = as_bytes(self.msg) _args = self._dict try: _args["kid"] = kwargs["kid"] except KeyError: pass jwe = JWEnc(**_args) # If no iv and cek are given generate them iv = self._generate_iv(self["enc"], iv) cek = self._generate_key(self["enc"], cek) if isinstance(key, SYMKey): try: kek = key.key.encode("utf8") except AttributeError: kek = key.key elif isinstance(key, bytes): kek = key else: kek = intarr2str(key) # The iv for this function must be 64 bit # Which is certainly different from the one above jek = aes_key_wrap(kek, cek, default_backend()) _enc = self["enc"] _auth_data = jwe.b64_encode_header() ctxt, tag, cek = self.enc_setup(_enc, _msg, auth_data=_auth_data, key=cek, iv=iv) return jwe.pack(parts=[jek, iv, ctxt, tag])
def wrap(self, wrapping_key, key_to_wrap): # type: (bytes, bytes) -> bytes """Wrap key using AES keywrap. :param bytes wrapping_key: Loaded key with which to wrap :param bytes key_to_wrap: Raw key to wrap :returns: Wrapped key :rtype: bytes """ if self.java_name not in ("AES", "AESWrap"): raise NotImplementedError('"wrap" is not supported by the "{}" cipher'.format(self.java_name)) try: return keywrap.aes_key_wrap(wrapping_key=wrapping_key, key_to_wrap=key_to_wrap, backend=default_backend()) except Exception: error_message = "Key wrap failed" _LOGGER.exception(error_message) raise WrappingError(error_message)
def test_keywrap(backend, wycheproof): wrapping_key = binascii.unhexlify(wycheproof.testcase["key"]) key_to_wrap = binascii.unhexlify(wycheproof.testcase["msg"]) expected = binascii.unhexlify(wycheproof.testcase["ct"]) if ( wycheproof.valid or ( wycheproof.acceptable and wycheproof.testcase["comment"] != "invalid size of wrapped key" ) ): result = keywrap.aes_key_wrap(wrapping_key, key_to_wrap, backend) assert result == expected if wycheproof.valid or wycheproof.acceptable: result = keywrap.aes_key_unwrap(wrapping_key, expected, backend) assert result == key_to_wrap else: with pytest.raises(keywrap.InvalidUnwrap): keywrap.aes_key_unwrap(wrapping_key, expected, backend)
def wrap_key(self, key_data): key_data = six.ensure_binary(key_data) cipher_text = aes_key_wrap(self._key, key_data, default_backend()) return cipher_text # IV, cipher text, auth tag
def wrap_key(self, key, algorithm='A256KW'): if algorithm == 'A256KW': return aes_key_wrap(self.kek, key, self.backend) else: raise ValueError(_ERROR_UNKNOWN_KEY_WRAP_ALGORITHM)
def wrap(self, cek, headers, key): op_key = key.get_op_key('wrapKey') self._check_key(op_key) ek = aes_key_wrap(op_key, cek, default_backend()) return ek
def wrap_key(cls, wrapping_key, key_to_wrap): return aes_key_wrap(wrapping_key, key_to_wrap, default_backend())
def wrap(self, cek, headers, key): self._check_key(key) ek = aes_key_wrap(key, cek, default_backend()) return ek
def encrypt(self, data_key: bytes) -> bytes: encrypted_data_key = aes_key_wrap( wrapping_key=self._key_bytes, key_to_wrap=data_key, ) return encrypted_data_key
def AESKeyWrap(): print("\n\n\n===========================================") print("Welcome to Key Wrap (KW) Mode of Operation") print("===========================================") print(" ") print( "Key wrapping and un-wrapping requires 3 parameters in order to function correctly:\n" ) print( "\n1) The key encrytion key or 'the wrapping key', which must be of 16, 24 or 32 bytes in value in order for AES to function." ) print( "2) The key that is to be wrapped 'key to wrap', this is also of 16, 24 or 32 bytes in value." ) print( "3) Finally, the wrapped key, this is the encrypted value of the key which is also used in the unwrapping process." ) print( "\nFor simplicity's sake, we have already defined a value for the key encryption key to be b'1234567890123456'." ) wrappingKey = b'1234567890123456' # Must be 16,24,32 bytes userYN = input("Do you wish to change this value?(y/n):") if (userYN == "y"): wrappingKey = input( "Enter a new value for the wrapping key(MUST BE OF 16, 24 OR 32 BYTES):" ) wrappingKey = wrappingKey.encode('utf-8') while (True): if ((len(wrappingKey) % 8 == 0) and len(wrappingKey) >= 16 and len(wrappingKey) <= 32): break print("The wrapping key must be a valid AES key length") wrappingKey = input( "Enter a new value for the wrapping key.(MUST BE OF 16, 24 OR 32 BYTES):" ) wrappingKey = wrappingKey.encode('utf-8') print( "\nAnd again, for simplicity's sake we've defined the key that is to be wrapped to be b'wow-this-is-fun!'" ) keyToWrap = b'wow-this-is-fun!' # Must be 16,24,32 bytes userYN = input("Do you wish to change this value?(y/n):") if (userYN == "y"): keyToWrap = input( "Enter a new value for key to be wrapped.(MUST BE OF 16, 24 OR 32 BYTES):" ) keyToWrap = keyToWrap.encode('utf-8') while (True): if ((len(keyToWrap) % 8 == 0) and len(keyToWrap) >= 16 and len(keyToWrap) <= 32): break print("The wrapping key must be a valid AES key length") keyToWrap = input( "Enter a new value for the wrapping key(MUST BE OF 16, 24 OR 32 BYTES):" ) keyToWrap = keyToWrap.encode('utf-8') wrappedKey = keywrap.aes_key_wrap(wrappingKey, keyToWrap, backend=default_backend()) print("\nThe encrypted value for the wrapped key is:", wrappedKey) input("Press Enter to see how we computed the wrapped key value...") print("\nWhat just happened?") print("-------------------------------------") print( "\nSo to go over how we got the encrypted value, lets take a moment to recall all the components involved." ) print( "First off, when the program asked about setting a key encryption key, this key value is what's going to remain constant in both wrapping and un-wrapping the new key (Defaulted to b'1234567890123456' if no input)." ) print( "The 'new key' is essentially the symmetric key we are wrapping so that we have a safe transfer of keys from the sender side to the receiver." ) print( "This 'new key', we will dub it as the 'keyToWrap' value and this is the second value the program asked for your input. It was defaulted to b'wow-this-is-fun!' if there was no input." ) print("\nSo now we have the following: ") print( "1) Key Encryption Key 'wrappinKey' = b'1234567890123456' or whatever you inputted." ) print( "2) New Symmetric Key 'keyToWrap' = b'wow-this-is-fun!' or whatever you inputted." ) print( "\nFinally, the program used the 'wrappingKey' to encrypt the 'keyToWrap' and that's how we got our 'WrappedKey' value." ) print("To clarify, the wrapped key is:", wrappedKey) input( "Press Enter to see how we can return back to our 'keyToWrap' value..." ) print("\nWhat about un-wrapping?") print("-------------------------------------") print( "\nNow if we wanted to get back our 'keyToWrap' which would be the symmetric key we wanted to exchange, it is actually quite simple given the parameters and values." ) print( "This is most helpful when trying to decrypt the wrapped key as the receiver of the new symmetric key." ) print( "\nJust like what we stated above when figuring out our wrapped key value, lets see what we have:" ) print( "1) Key Encrytion key 'wrappingKey' = b'1234567890123456' or whatever it was you inputted. (REMEMBER THIS PARAMETER REMAINS CONSTANT FOR BOTH OPERATIONS)" ) print("2) 'wrappedKey' = ", wrappedKey) print( "\nJust like before, using the two values and then decrypting using AES, we get back our 'keyToWrap' value" ) c = keywrap.aes_key_unwrap(wrappingKey, wrappedKey, backend=default_backend()) print( "After decrypting we end up with the symmetric key that was to be exchanged between sender and receiver:", c)
def enc_setup(self, msg, key=None, auth_data=b'', **kwargs): """ :param msg: Message to be encrypted :param auth_data: :param key: An EC key :param kwargs: :return: """ encrypted_key = "" self.msg = msg self.auth_data = auth_data # Generate the input parameters try: apu = b64d(kwargs["apu"]) except KeyError: apu = get_random_bytes(16) try: apv = b64d(kwargs["apv"]) except KeyError: apv = get_random_bytes(16) # Handle Local Key and Ephemeral Public Key if not key or not isinstance(key, ECKey): raise ValueError( "EC Key Required for ECDH-ES JWE Encryption Setup") # epk is either an Elliptic curve key instance or a JWK description of # one. This key belongs to the entity on the other side. try: _epk = kwargs['epk'] except KeyError: _epk = ec.generate_private_key(NIST2SEC[as_unicode(key.crv)], default_backend()) epk = ECKey().load_key(_epk.public_key()) else: if isinstance(_epk, ec.EllipticCurvePrivateKey): epk = ECKey().load_key(_epk) elif isinstance(_epk, ECKey): epk = _epk _epk = epk.private_key() else: raise ValueError("epk of a type I can't handle") params = { "apu": b64e(apu), "apv": b64e(apv), "epk": epk.serialize(False) } cek = iv = None if 'cek' in kwargs and kwargs['cek']: cek = kwargs['cek'] if 'iv' in kwargs and kwargs['iv']: iv = kwargs['iv'] iv = self._generate_iv(self.enc, iv=iv) if self.alg == "ECDH-ES": try: dk_len = KEY_LEN[self.enc] except KeyError: raise ValueError("Unknown key length for algorithm %s" % self.enc) cek = ecdh_derive_key(_epk, key.pub_key, apu, apv, str(self.enc).encode(), dk_len) elif self.alg in [ "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW" ]: _pre, _post = self.alg.split("+") klen = int(_post[1:4]) kek = ecdh_derive_key(_epk, key.pub_key, apu, apv, str(_post).encode(), klen) cek = self._generate_key(self.enc, cek=cek) encrypted_key = aes_key_wrap(kek, cek, default_backend()) else: raise Exception("Unsupported algorithm %s" % self.alg) return cek, encrypted_key, iv, params, epk
def key_wrap(cls, kek: 'SK', data: bytes): if cls.get_key_length() != len(kek.k): raise ValueError("Key has the wrong length") return aes_key_wrap(wrapping_key=kek.k, key_to_wrap=data, backend=default_backend())
def wrap_key(self, key_to_wrap: bytes) -> bytes: try: return aes_key_wrap(self._key, key_to_wrap) except Exception as err: raise EncodeError("Failed to wrap key.") from err
def test_wrap(self, backend, params): wrapping_key = binascii.unhexlify(params["k"]) key_to_wrap = binascii.unhexlify(params["p"]) wrapped_key = keywrap.aes_key_wrap(wrapping_key, key_to_wrap, backend) assert params["c"] == binascii.hexlify(wrapped_key)
def wrap(self, enc_alg, headers, key): cek = enc_alg.generate_cek() op_key = key.get_op_key('wrapKey') self._check_key(op_key) ek = aes_key_wrap(op_key, cek, default_backend()) return {'ek': ek, 'cek': cek}
def wrap_data_key(self, data_key: bytes) -> bytes: return aes_key_wrap( wrapping_key=self._wrapping_key, key_to_wrap=data_key, )
def wrap_key(self, key, algorithm='A256KW'): if algorithm == 'A256KW': return aes_key_wrap(self.kek, key, self.backend) raise ValueError('Unknown key wrap algorithm.')
def test_wrap_invalid_key_length(self, backend): # The wrapping key must be of length [16, 24, 32] with pytest.raises(ValueError): keywrap.aes_key_wrap(b"badkey", b"sixteen_byte_key", backend)
def key_wrap(wrapping_key, key_to_wrap): return aes_key_wrap(wrapping_key, key_to_wrap, _BACKEND)
def wrap_cek(self, cek, key): op_key = key.get_op_key('wrapKey') self._check_key(op_key) ek = aes_key_wrap(op_key, cek, default_backend()) return {'ek': ek, 'cek': cek}
def transform(self, data): aes_key_wrap(self._key, data, default_backend())