Esempio n. 1
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)
Esempio n. 2
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)