コード例 #1
0
def decrypt(enc, key, iv, aad, ct, tag):
    """
    Decrypt JWE content.

    @type  enc: string
    @param enc: The JWE "enc" value specifying the encryption algorithm
    @type  key: bytes
    @param key: Key (CEK)
    @type  iv : bytes
    @param iv : Initialization vector
    @type  aad: bytes
    @param aad: Additional authenticated data
    @type  ct : bytes
    @param ct : Ciphertext
    @type  tag: bytes
    @param tag: Authentication tag
    @rtype: tuple
    @return: (ciphertext, tag), both as bytes
    """
    if enc in ["A128GCM", "A192GCM", "A256GCM"]:
        gcm = AES_GCM(bytes_to_long(key))
        try:
            pt = gcm.decrypt(bytes_to_long(iv), ct, bytes_to_long(tag), aad)
            return (pt, True)
        except InvalidTagException:
            return (None, False)
    elif enc in ["A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512"]:
        return polyfills.AES_CBC_HMAC_decrypt( key, iv, aad, ct, tag )
    else: 
        raise Exception("Unsupported encryption algorithm {}".format(enc))
コード例 #2
0
def encrypt(enc, key, iv, aad, pt):
    """
    Encrypt JWE content.

    @type  enc: string
    @param enc: The JWE "enc" value specifying the encryption algorithm
    @type  key: bytes
    @param key: Key (CEK)
    @type  iv : bytes
    @param iv : Initialization vector
    @type  aad: bytes
    @param aad: Additional authenticated data
    @type  pt : bytes
    @param pt : Plaintext
    @rtype: tuple
    @return: (ciphertext, tag), both as bytes
    """
    if enc in ["A128GCM", "A192GCM", "A256GCM"]:
        gcm = AES_GCM(bytes_to_long(key))
        (ct, tag) = gcm.encrypt(bytes_to_long(iv), pt, aad)
        return (ct, long_to_bytes(tag, 16))
    elif enc in ["A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512"]:
        return polyfills.AES_CBC_HMAC_encrypt( key, iv, aad, pt )
    else: 
        raise Exception("Unsupported encryption algorithm {}".format(enc))
コード例 #3
0
ファイル: jwe.py プロジェクト: johanlundberg/pyjwkest
    def _decrypt(enc, key, ctxt, auth_data, iv, tag):
        """ Decrypt JWE content.

        :param enc: The JWE "enc" value specifying the encryption algorithm
        :param key: Key (CEK)
        :param iv : Initialization vector
        :param auth_data: Additional authenticated data
        :param ctxt : Ciphertext
        :param tag: Authentication tag
        :return: plain text message or None if decryption failed
        """
        if enc in ["A128GCM", "A192GCM", "A256GCM"]:
            gcm = AES_GCM(bytes_to_long(key))
            try:
                text = gcm.decrypt(bytes_to_long(iv), ctxt, bytes_to_long(tag),
                                   auth_data)
                return text, True
            except DecryptionFailed:
                return None, False
        elif enc in ["A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512"]:
            return aes_cbc_hmac_decrypt(key, iv, auth_data, ctxt, tag)
        else:
            raise Exception("Unsupported encryption algorithm %s" % enc)
コード例 #4
0
ファイル: jwe.py プロジェクト: dv10den/pyjwkest
    def _decrypt(enc, key, ctxt, auth_data, iv, tag):
        """ Decrypt JWE content.

        :param enc: The JWE "enc" value specifying the encryption algorithm
        :param key: Key (CEK)
        :param iv : Initialization vector
        :param auth_data: Additional authenticated data
        :param ctxt : Ciphertext
        :param tag: Authentication tag
        :return: plain text message or None if decryption failed
        """
        if enc in ["A128GCM", "A192GCM", "A256GCM"]:
            gcm = AES_GCM(bytes_to_long(key))
            try:
                text = gcm.decrypt(bytes_to_long(iv), ctxt, bytes_to_long(tag),
                                   auth_data)
                return text, True
            except DecryptionFailed:
                return None, False
        elif enc in ["A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512"]:
            return aes_cbc_hmac_decrypt(key, iv, auth_data, ctxt, tag)
        else:
            raise Exception("Unsupported encryption algorithm %s" % enc)
コード例 #5
0
ファイル: jwe.py プロジェクト: johanlundberg/pyjwkest
    def enc_setup(self, enc_alg, msg, auth_data, key=None, iv=""):
        """ Encrypt JWE content.

        :param enc_alg: The JWE "enc" value specifying the encryption algorithm
        :param msg: The plain text message
        :param auth_data: Additional authenticated data
        :param key: Key (CEK)
        :return: Tuple (ciphertext, tag), both as bytes
        """

        key, iv = self._generate_key_and_iv(enc_alg, key, iv)

        if enc_alg == "A256GCM":
            gcm = AES_GCM(bytes_to_long(key))
            ctxt, tag = gcm.encrypt(bytes_to_long(iv), msg, auth_data)
            tag = long_to_bytes(tag)
        elif enc_alg in ["A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512"]:
            assert enc_alg in SUPPORTED["enc"]
            #ealg, hashf = enc.split("-")
            ctxt, tag = aes_cbc_hmac_encrypt(key, iv, auth_data, msg)
        else:
            raise NotSupportedAlgorithm(enc_alg)

        return ctxt, tag, key
コード例 #6
0
ファイル: jwe.py プロジェクト: dv10den/pyjwkest
    def enc_setup(self, enc_alg, msg, auth_data, key=None, iv=""):
        """ Encrypt JWE content.

        :param enc_alg: The JWE "enc" value specifying the encryption algorithm
        :param msg: The plain text message
        :param auth_data: Additional authenticated data
        :param key: Key (CEK)
        :return: Tuple (ciphertext, tag), both as bytes
        """

        key, iv = self._generate_key_and_iv(enc_alg, key, iv)

        if enc_alg == "A256GCM":
            gcm = AES_GCM(bytes_to_long(key))
            ctxt, tag = gcm.encrypt(bytes_to_long(iv), msg, auth_data)
            tag = long_to_bytes(tag)
        elif enc_alg in ["A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512"]:
            assert enc_alg in SUPPORTED["enc"]
            #ealg, hashf = enc.split("-")
            ctxt, tag = aes_cbc_hmac_encrypt(key, iv, auth_data, msg)
        else:
            raise NotSupportedAlgorithm(enc_alg)

        return ctxt, tag, key
コード例 #7
0
ファイル: test_2_jwe.py プロジェクト: reedobrien/pyjwkest
def test_jwe_09_a1():
    # RSAES OAEP and AES GCM
    msg = "The true sign of intelligence is not knowledge but imagination."

    # A.1.1
    header = '{"alg":"RSA-OAEP","enc":"A256GCM"}'
    b64_header = b64e(header)

    # A.1.2
    assert b64_header == "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ"

    # A.1.3
    cek = intarr2long([
        177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154, 212,
        246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122, 234, 64,
        252
    ])

    # A.1.4 Key Encryption
    enc_key = [
        56, 163, 154, 192, 58, 53, 222, 4, 105, 218, 136, 218, 29, 94, 203, 22,
        150, 92, 129, 94, 211, 232, 53, 89, 41, 60, 138, 56, 196, 216, 82, 98,
        168, 76, 37, 73, 70, 7, 36, 8, 191, 100, 136, 196, 244, 220, 145, 158,
        138, 155, 4, 117, 141, 230, 199, 247, 173, 45, 182, 214, 74, 177, 107,
        211, 153, 11, 205, 196, 171, 226, 162, 128, 171, 182, 13, 237, 239, 99,
        193, 4, 91, 219, 121, 223, 107, 167, 61, 119, 228, 173, 156, 137, 134,
        200, 80, 219, 74, 253, 56, 185, 91, 177, 34, 158, 89, 154, 205, 96, 55,
        18, 138, 43, 96, 218, 215, 128, 124, 75, 138, 243, 85, 25, 109, 117,
        140, 26, 155, 249, 67, 167, 149, 231, 100, 6, 41, 65, 214, 251, 232,
        87, 72, 40, 182, 149, 154, 168, 31, 193, 126, 215, 89, 28, 111, 219,
        125, 182, 139, 235, 195, 197, 23, 234, 55, 58, 63, 180, 68, 202, 206,
        149, 75, 205, 248, 176, 67, 39, 178, 60, 98, 193, 32, 238, 122, 96,
        158, 222, 57, 183, 111, 210, 55, 188, 215, 206, 180, 166, 150, 166,
        106, 250, 55, 229, 72, 40, 69, 214, 216, 104, 23, 40, 135, 212, 28,
        127, 41, 80, 175, 174, 168, 115, 171, 197, 89, 116, 92, 103, 246, 83,
        216, 182, 176, 84, 37, 147, 35, 45, 219, 172, 99, 226, 233, 73, 37,
        124, 42, 72, 49, 242, 35, 127, 184, 134, 117, 114, 135, 206
    ]

    b64_ejek = "ApfOLCaDbqs_JXPYy2I937v_xmrzj-Iss1mG6NAHmeJViM6j2l0MHvfseIdHVyU2BIoGVu9ohvkkWiRq5DL2jYZTPA9TAdwq3FUIVyoH-Pedf6elHIVFi2KGDEspYMtQARMMSBcS7pslx6flh1Cfh3GBKysztVMEhZ_maFkm4PYVCsJsvq6Ct3fg2CJPOs0X1DHuxZKoIGIqcbeK4XEO5a0h5TAuJObKdfO0dKwfNSSbpu5sFrpRFwV2FTTYoqF4zI46N9-_hMIznlEpftRXhScEJuZ9HG8C8CHB1WRZ_J48PleqdhF4o7fB5J1wFqUXBtbtuGJ_A2Xe6AEhrlzCOw"

    iv = intarr2long([227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219])

    aadp = b64_header + b'.' + b64_ejek

    gcm = AES_GCM(cek)
    ctxt, tag = gcm.encrypt(iv, msg, aadp)

    _va = [ord(c) for c in ctxt]
    assert _va == [
        229, 236, 166, 241, 53, 191, 115, 196, 174, 43, 73, 109, 39, 122, 233,
        96, 140, 206, 120, 52, 51, 237, 48, 11, 190, 219, 186, 80, 111, 104,
        50, 142, 47, 167, 59, 61, 181, 127, 196, 21, 40, 82, 242, 32, 123, 143,
        168, 226, 73, 216, 176, 144, 138, 247, 106, 60, 16, 205, 160, 109, 64,
        63, 192
    ]

    assert byte_arr(tag) == [
        130, 17, 32, 198, 120, 167, 144, 113, 0, 50, 158, 49, 102, 208, 118,
        152
    ]

    tag = long2hexseq(tag)
    iv = long2hexseq(iv)
    res = b".".join([b64_header, b64_ejek, b64e(iv), b64e(ctxt), b64e(tag)])

    assert res == "".join([
        "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.",
        "ApfOLCaDbqs_JXPYy2I937v_xmrzj-Iss1mG6NAHmeJViM6j2l0MHvfseIdHVyU2",
        "BIoGVu9ohvkkWiRq5DL2jYZTPA9TAdwq3FUIVyoH-Pedf6elHIVFi2KGDEspYMtQ",
        "ARMMSBcS7pslx6flh1Cfh3GBKysztVMEhZ_maFkm4PYVCsJsvq6Ct3fg2CJPOs0X",
        "1DHuxZKoIGIqcbeK4XEO5a0h5TAuJObKdfO0dKwfNSSbpu5sFrpRFwV2FTTYoqF4",
        "zI46N9-_hMIznlEpftRXhScEJuZ9HG8C8CHB1WRZ_J48PleqdhF4o7fB5J1wFqUX",
        "BtbtuGJ_A2Xe6AEhrlzCOw.", "48V1_ALb6US04U3b.",
        "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji",
        "SdiwkIr3ajwQzaBtQD_A.", "ghEgxninkHEAMp4xZtB2mA"
    ])
コード例 #8
0
ファイル: test_2_jwe.py プロジェクト: dlg-yahoo/pyjwkest
def test_jwe_09_a1():
    # RSAES OAEP and AES GCM
    msg = "The true sign of intelligence is not knowledge but imagination."

    # A.1.1
    header = '{"alg":"RSA-OAEP","enc":"A256GCM"}'
    b64_header = b64e(header)

    # A.1.2
    assert b64_header == "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ"

    # A.1.3
    cek = intarr2long([177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255,
                      107, 154, 212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47,
                      130, 203, 46, 122, 234, 64, 252])

    # A.1.4 Key Encryption
    enc_key = [
        56, 163, 154, 192, 58, 53, 222, 4, 105, 218, 136, 218, 29, 94, 203,
        22, 150, 92, 129, 94, 211, 232, 53, 89, 41, 60, 138, 56, 196, 216,
        82, 98, 168, 76, 37, 73, 70, 7, 36, 8, 191, 100, 136, 196, 244, 220,
        145, 158, 138, 155, 4, 117, 141, 230, 199, 247, 173, 45, 182, 214,
        74, 177, 107, 211, 153, 11, 205, 196, 171, 226, 162, 128, 171, 182,
        13, 237, 239, 99, 193, 4, 91, 219, 121, 223, 107, 167, 61, 119, 228,
        173, 156, 137, 134, 200, 80, 219, 74, 253, 56, 185, 91, 177, 34, 158,
        89, 154, 205, 96, 55, 18, 138, 43, 96, 218, 215, 128, 124, 75, 138,
        243, 85, 25, 109, 117, 140, 26, 155, 249, 67, 167, 149, 231, 100, 6,
        41, 65, 214, 251, 232, 87, 72, 40, 182, 149, 154, 168, 31, 193, 126,
        215, 89, 28, 111, 219, 125, 182, 139, 235, 195, 197, 23, 234, 55, 58,
        63, 180, 68, 202, 206, 149, 75, 205, 248, 176, 67, 39, 178, 60, 98,
        193, 32, 238, 122, 96, 158, 222, 57, 183, 111, 210, 55, 188, 215,
        206, 180, 166, 150, 166, 106, 250, 55, 229, 72, 40, 69, 214, 216,
        104, 23, 40, 135, 212, 28, 127, 41, 80, 175, 174, 168, 115, 171, 197,
        89, 116, 92, 103, 246, 83, 216, 182, 176, 84, 37, 147, 35, 45, 219,
        172, 99, 226, 233, 73, 37, 124, 42, 72, 49, 242, 35, 127, 184, 134,
        117, 114, 135, 206]

    b64_ejek = "ApfOLCaDbqs_JXPYy2I937v_xmrzj-Iss1mG6NAHmeJViM6j2l0MHvfseIdHVyU2BIoGVu9ohvkkWiRq5DL2jYZTPA9TAdwq3FUIVyoH-Pedf6elHIVFi2KGDEspYMtQARMMSBcS7pslx6flh1Cfh3GBKysztVMEhZ_maFkm4PYVCsJsvq6Ct3fg2CJPOs0X1DHuxZKoIGIqcbeK4XEO5a0h5TAuJObKdfO0dKwfNSSbpu5sFrpRFwV2FTTYoqF4zI46N9-_hMIznlEpftRXhScEJuZ9HG8C8CHB1WRZ_J48PleqdhF4o7fB5J1wFqUXBtbtuGJ_A2Xe6AEhrlzCOw"

    iv = intarr2long([227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219])

    aadp = b64_header + b'.' + b64_ejek

    gcm = AES_GCM(cek)
    ctxt, tag = gcm.encrypt(iv, msg, aadp)

    _va = [ord(c) for c in ctxt]
    assert _va == [229, 236, 166, 241, 53, 191, 115, 196, 174, 43, 73, 109, 39,
                   122, 233, 96, 140, 206, 120, 52, 51, 237, 48, 11, 190, 219,
                   186, 80, 111, 104, 50, 142, 47, 167, 59, 61, 181, 127, 196,
                   21, 40, 82, 242, 32, 123, 143, 168, 226, 73, 216, 176, 144,
                   138, 247, 106, 60, 16, 205, 160, 109, 64, 63, 192]

    assert byte_arr(tag) == [130, 17, 32, 198, 120, 167, 144, 113, 0,
                             50, 158, 49, 102, 208, 118, 152]

    tag = long2hexseq(tag)
    iv = long2hexseq(iv)
    res = b".".join([b64_header, b64_ejek, b64e(iv), b64e(ctxt), b64e(tag)])

    assert res == "".join([
        "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.",
        "ApfOLCaDbqs_JXPYy2I937v_xmrzj-Iss1mG6NAHmeJViM6j2l0MHvfseIdHVyU2",
        "BIoGVu9ohvkkWiRq5DL2jYZTPA9TAdwq3FUIVyoH-Pedf6elHIVFi2KGDEspYMtQ",
        "ARMMSBcS7pslx6flh1Cfh3GBKysztVMEhZ_maFkm4PYVCsJsvq6Ct3fg2CJPOs0X",
        "1DHuxZKoIGIqcbeK4XEO5a0h5TAuJObKdfO0dKwfNSSbpu5sFrpRFwV2FTTYoqF4",
        "zI46N9-_hMIznlEpftRXhScEJuZ9HG8C8CHB1WRZ_J48PleqdhF4o7fB5J1wFqUX",
        "BtbtuGJ_A2Xe6AEhrlzCOw.",
        "48V1_ALb6US04U3b.",
        "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji",
        "SdiwkIr3ajwQzaBtQD_A.",
        "ghEgxninkHEAMp4xZtB2mA"])
コード例 #9
0
def decryptKey(alg, enc, jwk, encryptedKey, header={}):
    """
    Decrypt a JWE encrypted key.
    
    @type  alg: string
    @param alg: The JWE "alg" value specifying the key management algorithm
    @type  enc: string
    @param enc: The JWE "enc" value specifying the encryption algorithm
    @type  jwk: dict
    @param jwk: The key to be used, as an unserialized JWK object
    @type  encryptedKey: bytes
    @param encryptedKey: The key to decrypt
    @type  header: dict
    @param header: A header object containing additional parameters
    @rtype: bytes
    @return: The decrypted key
    """
    key = importKey(jwk, private=True)
    if alg == "RSA1_5":
        sentinel = "fnord"
        cipher = PKCS1_v1_5.new(key)
        CEK = cipher.decrypt(encryptedKey, sentinel)
        if CEK == sentinel:
            raise Exception("Unable to unwrap key")
        return CEK
    elif alg == "RSA-OAEP":
        cipher = PKCS1_OAEP.new(key)
        CEK = cipher.decrypt(encryptedKey)
        return CEK
    elif alg in ["A128KW", "A192KW", "A256KW"]:
        return polyfills.aes_key_unwrap(key, encryptedKey)
    elif alg == "dir":
        if encryptedKey and len(encryptedKey) > 0:
            raise Exception("Direct encryption with non-empty encrypted key")
        return key
    elif alg in ["ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW"]:
        # Pull the input parameters 
        epk = importKey(getOrRaise(header, "epk"))
        apu = b64dec(getOrRaise(header, "apu"))
        apv = b64dec(getOrRaise(header, "apv"))
        # Select the curve
        curve = NISTEllipticCurve.byName(getOrRaise(header["epk"], "crv"))
        # Derive the KEK and decrypt
        if alg == "ECDH-ES":
            dkLen = keyLength(enc)
            return polyfills.ECDH_deriveKey(curve, key, epk, apu, apv, enc, dkLen)
        elif alg == "ECDH-ES+A128KW":
            kek = polyfills.ECDH_deriveKey(curve, key, epk, apu, apv, "A128KW", 128)
            return polyfills.aes_key_unwrap(kek, encryptedKey)
        elif alg == "ECDH-ES+A192KW":
            kek = polyfills.ECDH_deriveKey(curve, key, epk, apu, apv, "A192KW", 192)
            return polyfills.aes_key_unwrap(kek, encryptedKey)
        elif alg == "ECDH-ES+A256KW":
            kek = polyfills.ECDH_deriveKey(curve, key, epk, apu, apv, "A256KW", 256)
            return polyfills.aes_key_unwrap(kek, encryptedKey)
    elif alg in ["A128GCMKW", "A192GCMKW", "A256GCMKW"]:
        iv = b64dec(getOrRaise(header, "iv"))
        tag = b64dec(getOrRaise(header, "tag"))
        gcm = AES_GCM(bytes_to_long(key))
        return gcm.decrypt(bytes_to_long(iv), encryptedKey, bytes_to_long(tag), '')
    elif alg == "PBES2-HS256+A128KW":
        return polyfills.PBKDF_key_unwrap(key, encryptedKey, SHA256, 16, header)
    elif alg == "PBES2-HS384+A192KW":
        return polyfills.PBKDF_key_unwrap(key, encryptedKey, SHA384, 24, header)
    elif alg == "PBES2-HS512+A256KW":
        return polyfills.PBKDF_key_unwrap(key, encryptedKey, SHA512, 32, header)
    else: 
        raise Exception("Unsupported key management algorithm " + alg)
コード例 #10
0
def generateSenderParams(alg, enc, jwk, header={}, inCEK=None):
    """
    Generate parameters for the sender of a JWE.  This is essentially an 
    encryptKey method, except (1) in some cases, the key is specified directly
    or derived ("dir", "ECDH"), and (2) other parameters besides the encrypted
    key are generated (e.g., the IV).

    This method returns several things:
      - A random CEK (can be overridden with the inCEK parameter)
      - The encrypted CEK
      - A random IV
      - A dictionary of parameters generated within this function

    The idea is that the parameters generated within this function (e.g.,
    "epk", "p2s") should be added back to the JWE header

    @type  alg: string
    @param alg: The JWE "alg" value specifying the key management algorithm
    @type  enc: string
    @param enc: The JWE "enc" value specifying the encryption algorithm
    @type  jwk: dict
    @param jwk: The key to be used, as an unserialized JWK object
    @type  header: dict
    @param header: A header object with additional parameters
    @type  inCEK: bytes
    @param inCEK: A fixed CEK (overrides random CEK generation)
    @rtype: tuple
    @return: (CEK, encryptedKey, IV, params), the first three as bytes, 
      params as dict.  
    """
    # Generate a random key/iv for enc
    (CEK, IV) = generateKeyIV(enc)
    if inCEK:
        CEK = inCEK
    encryptedKey = ""
    params = {}
    key = importKey(jwk, private=False)

    # Encrypt key / generate params as defined by alg
    if alg == "RSA1_5":
        cipher = PKCS1_v1_5.new(key)
        encryptedKey = cipher.encrypt(CEK)
    elif alg == "RSA-OAEP":
        (CEK, IV) = generateKeyIV(enc)
        cipher = PKCS1_OAEP.new(key)
        encryptedKey = cipher.encrypt(CEK)
    elif alg in ["A128KW", "A192KW", "A256KW"]:
        encryptedKey = polyfills.aes_key_wrap(key, CEK)
    elif alg == "dir":
        CEK = key
    elif alg in ["ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW"]:
        # Generate the input parameters 
        apu = b64dec(header["apu"]) if "apu" in header else Random.get_random_bytes(16) 
        apv = b64dec(header["apv"]) if "apv" in header else Random.get_random_bytes(16) 
        # Generate an ephemeral key pair
        curve = NISTEllipticCurve.byName(getOrRaise(jwk, "crv"))
        if "epk" in header:
            epk = importKey(header["epk"], private=False)
            eprivk = importKey(header["epk"], private=True)
        else:
            (eprivk, epk) = curve.keyPair()
        # Derive the KEK and encrypt
        params = {
            "apu": b64enc(apu),
            "apv": b64enc(apv),
            "epk": exportKey(epk, "EC", curve)
        }
        if alg == "ECDH-ES":
            dkLen = keyLength(enc)
            CEK = polyfills.ECDH_deriveKey(curve, eprivk, key, apu, apv, enc, dkLen)
        elif alg == "ECDH-ES+A128KW":
            kek = polyfills.ECDH_deriveKey(curve, eprivk, key, apu, apv, "A128KW", 128)
            encryptedKey = polyfills.aes_key_wrap(kek, CEK)
        elif alg == "ECDH-ES+A192KW":
            kek = polyfills.ECDH_deriveKey(curve, eprivk, key, apu, apv, "A192KW", 192)
            encryptedKey = polyfills.aes_key_wrap(kek, CEK)
        elif alg == "ECDH-ES+A256KW":
            kek = polyfills.ECDH_deriveKey(curve, eprivk, key, apu, apv, "A256KW", 256)
            encryptedKey = polyfills.aes_key_wrap(kek, CEK)
    elif alg in ["A128GCMKW", "A192GCMKW", "A256GCMKW"]:
        iv = Random.get_random_bytes(12)
        gcm = AES_GCM(bytes_to_long(key))
        encryptedKey, tag = gcm.encrypt(bytes_to_long(iv), CEK, '')
        params = { "iv": b64enc(iv), "tag": b64enc(long_to_bytes(tag,16)) }
    elif alg == "PBES2-HS256+A128KW":
        (CEK, IV) = generateKeyIV(enc)
        (encryptedKey, params) = \
            polyfills.PBKDF_key_wrap( key, CEK, SHA256, 16, header )
    elif alg == "PBES2-HS384+A192KW":
        (CEK, IV) = generateKeyIV(enc)
        (encryptedKey, params) = \
            polyfills.PBKDF_key_wrap( key, CEK, SHA384, 24, header )
    elif alg == "PBES2-HS512+A256KW":
        (CEK, IV) = generateKeyIV(enc)
        (encryptedKey, params) = \
            polyfills.PBKDF_key_wrap( key, CEK, SHA512, 32, header )
    else: 
        raise Exception("Unsupported key management algorithm " + alg)
    
    return (CEK, encryptedKey, IV, params)