@Override public boolean validateSignature(SignedJWT jwt) { for (JWSVerifier verifier : verifiers.values()) { try { if (jwt.verify(verifier)) { return true; } } catch (JOSEException e) { logger.error("Failed to validate signature with " + verifier + " error message: " + e.getMessage()); } } return false; }
@Override public PrivateKey toPrivateKey() throws JOSEException { throw new JOSEException("Export to java.security.PrivateKey not supported"); }
/** * Decrypts the specified encrypted Content Encryption Key (CEK). * * @param priv The private RSA key. Must not be {@code null}. * @param encryptedCEK The encrypted Content Encryption Key (CEK) to * decrypt. Must not be {@code null}. * @param provider The JCA provider, or {@code null} to use the * default one. * * @return The decrypted Content Encryption Key (CEK). * * @throws JOSEException If decryption failed. */ public static SecretKey decryptCEK(final PrivateKey priv, final byte[] encryptedCEK, final Provider provider) throws JOSEException { try { Cipher cipher = CipherHelper.getInstance(RSA_OEAP_JCA_ALG, provider); cipher.init(Cipher.DECRYPT_MODE, priv); return new SecretKeySpec(cipher.doFinal(encryptedCEK), "AES"); } catch (Exception e) { // java.security.NoSuchAlgorithmException // java.security.NoSuchPaddingException // java.security.InvalidKeyException // javax.crypto.IllegalBlockSizeException // javax.crypto.BadPaddingException throw new JOSEException(e.getMessage(), e); } }
cipher = Cipher.getInstance("AES/GCM/NoPadding", provider); } else { cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, aesKey, gcmSpec); throw new JOSEException("Couldn't create AES/GCM/NoPadding cipher: " + e.getMessage(), e); throw new JOSEException("AES/GCM/NoPadding decryption failed: " + e.getMessage(), e);
/** * Encrypts the specified Content Encryption Key (CEK). * * @param pub The public RSA key. Must not be {@code null}. * @param cek The Content Encryption Key (CEK) to encrypt. Must * not be {@code null}. * @param provider The JCA provider, or {@code null} to use the default * one. * * @return The encrypted Content Encryption Key (CEK). * * @throws JOSEException If encryption failed. */ public static byte[] encryptCEK(final RSAPublicKey pub, final SecretKey cek, Provider provider) throws JOSEException { try { Cipher cipher = CipherHelper.getInstance("RSA/ECB/PKCS1Padding", provider); cipher.init(Cipher.ENCRYPT_MODE, pub); return cipher.doFinal(cek.getEncoded()); } catch (IllegalBlockSizeException e) { throw new JOSEException("RSA block size exception: The RSA key is too short, try a longer one", e); } catch (Exception e) { // java.security.NoSuchAlgorithmException // java.security.InvalidKeyException throw new JOSEException("Couldn't encrypt Content Encryption Key (CEK): " + e.getMessage(), e); } }
cipher = Cipher.getInstance("AESWrap", provider); } else { cipher = Cipher.getInstance("AESWrap"); cipher.init(Cipher.WRAP_MODE, kek); return cipher.wrap(cek); throw new JOSEException("Couldn't wrap AES key: " + e.getMessage(), e);
cipher = Cipher.getInstance("AESWrap", provider); } else { cipher = Cipher.getInstance("AESWrap"); cipher.init(Cipher.UNWRAP_MODE, KeyUtils.toAESKey(kek)); // Make sure key alg is "AES" return (SecretKey)cipher.unwrap(encryptedCEK, "AES", Cipher.SECRET_KEY); throw new JOSEException("Couldn't unwrap AES key: " + e.getMessage(), e);
cipher = CipherHelper.getInstance("AES/CBC/PKCS5Padding", provider); SecretKeySpec keyspec = new SecretKeySpec(secretKey.getEncoded(), "AES"); cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivSpec); cipher.init(Cipher.DECRYPT_MODE, keyspec, ivSpec); throw new JOSEException(e.getMessage(), e);
/** * Enumeration of the Elliptic Curve Diffie-Hellman Ephemeral Static * algorithm modes. */ public enum AlgorithmMode { /** * Direct key agreement mode. */ DIRECT, /** * Key wrapping mode. */ KW }
/** * Generates a Content Encryption Key (CEK) for the specified JOSE * encryption method. * * @param enc The encryption method. Must not be {@code null}. * @param randomGen The secure random generator to use. Must not be * {@code null}. * * @return The generated CEK (with algorithm "AES"). * * @throws JOSEException If the encryption method is not supported. */ public static SecretKey generateCEK(final EncryptionMethod enc, final SecureRandom randomGen) throws JOSEException { if (! SUPPORTED_ENCRYPTION_METHODS.contains(enc)) { throw new JOSEException(AlgorithmSupportMessage.unsupportedEncryptionMethod(enc, SUPPORTED_ENCRYPTION_METHODS)); } final byte[] cekMaterial = new byte[ByteUtils.byteLength(enc.cekBitLength())]; randomGen.nextBytes(cekMaterial); return new SecretKeySpec(cekMaterial, "AES"); }
/** * Decrypts the specified cipher text using AES/CBC/PKCS5Padding. * * @param secretKey The AES key. Must not be {@code null}. * @param iv The initialisation vector (IV). Must not be * {@code null}. * @param cipherText The cipher text. Must not be {@code null}. * @param provider The JCA provider, or {@code null} to use the * default one. * * @return The decrypted plain text. * * @throws JOSEException If decryption failed. */ public static byte[] decrypt(final SecretKey secretKey, final byte[] iv, final byte[] cipherText, final Provider provider) throws JOSEException { Cipher cipher = createAESCBCCipher(secretKey, false, iv, provider); try { return cipher.doFinal(cipherText); } catch (Exception e) { throw new JOSEException(e.getMessage(), e); } }
public static Mac getInitMac(final SecretKey secretKey, final Provider provider) throws JOSEException { Mac mac; try { if (provider != null) { mac = Mac.getInstance(secretKey.getAlgorithm(), provider); } else { mac = Mac.getInstance(secretKey.getAlgorithm()); } mac.init(secretKey); } catch (NoSuchAlgorithmException e) { throw new JOSEException("Unsupported HMAC algorithm: " + e.getMessage(), e); } catch (InvalidKeyException e) { throw new JOSEException("Invalid HMAC key: " + e.getMessage(), e); } return mac; }
throw new JOSEException("Couldn't compute JWK thumbprint: Unsupported hash algorithm: " + e.getMessage(), e); return Base64URL.encode(md.digest());
/** * Generates a new ephemeral EC key pair with the specified curve. * * @param ecParameterSpec The EC key spec. Must not be {@code null}. * * @return The EC key pair. * * @throws JOSEException If the EC key pair couldn't be generated. */ private KeyPair generateEphemeralKeyPair(final ECParameterSpec ecParameterSpec) throws JOSEException { Provider keProvider = getJCAContext().getKeyEncryptionProvider(); try { KeyPairGenerator generator; if (keProvider != null) { generator = KeyPairGenerator.getInstance("EC", keProvider); } else { generator = KeyPairGenerator.getInstance("EC"); } generator.initialize(ecParameterSpec); return generator.generateKeyPair(); } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { throw new JOSEException("Couldn't generate ephemeral EC key pair: " + e.getMessage(), e); } } }
/** * Returns a standard {@code java.security.interfaces.RSAPublicKey} * representation of this RSA JWK. * * @return The public RSA key. * * @throws JOSEException If RSA is not supported by the underlying Java * Cryptography (JCA) provider or if the JWK * parameters are invalid for a public RSA key. */ public RSAPublicKey toRSAPublicKey() throws JOSEException { BigInteger modulus = n.decodeToBigInteger(); BigInteger exponent = e.decodeToBigInteger(); RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); try { KeyFactory factory = KeyFactory.getInstance("RSA"); return (RSAPublicKey) factory.generatePublic(spec); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { throw new JOSEException(e.getMessage(), e); } }
@Override public Base64URL sign(final JWSHeader header, final byte[] signingInput) throws JOSEException { // Check alg field in header final JWSAlgorithm alg = header.getAlgorithm(); if (! JWSAlgorithm.EdDSA.equals(alg)) { throw new JOSEException("Ed25519Signer requires alg=EdDSA in JWSHeader"); } final byte[] jwsSignature; try { jwsSignature = tinkSigner.sign(signingInput); } catch (GeneralSecurityException e) { throw new JOSEException(e.getMessage(), e); } return Base64URL.encode(jwsSignature); } }
/** * Retrieves the actual AES GCM parameters used by the specified * cipher. * * @param cipher The cipher to interrogate. Non-{@code null}. * * @return The AES GCM parameters. Non-{@code null}. * * @throws JOSEException If the parameters cannot be retrieved, are * uninitialized, or are not in the correct form. We want to have the * actual parameters used by the cipher and not rely on the assumption * that they were the same as those we supplied it with. If at runtime * the assumption is incorrect, the ciphertext would not be * decryptable. */ private static GCMParameterSpec actualParamsOf(final Cipher cipher) throws JOSEException { AlgorithmParameters algorithmParameters = cipher.getParameters(); if (algorithmParameters == null) { throw new JOSEException("AES GCM ciphers are expected to make use of algorithm parameters"); } try { // Note: GCMParameterSpec appears in Java 7 return algorithmParameters.getParameterSpec(GCMParameterSpec.class); } catch (InvalidParameterSpecException shouldNotHappen) { throw new JOSEException(shouldNotHappen.getMessage(), shouldNotHappen); } }
@Override public Base64URL sign(final JWSHeader header, final byte[] signingInput) throws JOSEException { Signature signer = RSASSA.getSignerAndVerifier(header.getAlgorithm(), getJCAContext().getProvider()); try { signer.initSign(privateKey); signer.update(signingInput); return Base64URL.encode(signer.sign()); } catch (InvalidKeyException e) { throw new JOSEException("Invalid private RSA key: " + e.getMessage(), e); } catch (SignatureException e) { throw new JOSEException("RSA signature exception: " + e.getMessage(), e); } } }
@Override public boolean verify(final JWSHeader header, final byte[] signedContent, final Base64URL signature) throws JOSEException { if (! critPolicy.headerPasses(header)) { return false; } final Signature verifier = RSASSA.getSignerAndVerifier(header.getAlgorithm(), getJCAContext().getProvider()); try { verifier.initVerify(publicKey); } catch (InvalidKeyException e) { throw new JOSEException("Invalid public RSA key: " + e.getMessage(), e); } try { verifier.update(signedContent); return verifier.verify(signature.decode()); } catch (SignatureException e) { return false; } } }