diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/JWEHelper.java b/src/main/java/org/cryptomator/ui/keyloading/hub/JWEHelper.java index a2e45cd71..6ef60610a 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/JWEHelper.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/JWEHelper.java @@ -12,14 +12,13 @@ import com.nimbusds.jose.crypto.ECDHEncrypter; import com.nimbusds.jose.crypto.PasswordBasedDecrypter; import com.nimbusds.jose.jwk.Curve; import com.nimbusds.jose.jwk.gen.ECKeyGenerator; -import com.nimbusds.jose.jwk.gen.JWKGenerator; +import org.cryptomator.cryptolib.api.CryptoException; import org.cryptomator.cryptolib.api.Masterkey; import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.security.KeyFactory; -import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; @@ -36,7 +35,8 @@ class JWEHelper { private static final String JWE_PAYLOAD_KEY_FIELD = "key"; private static final String EC_ALG = "EC"; - private JWEHelper(){} + private JWEHelper() {} + public static JWEObject encryptUserKey(ECPrivateKey userKey, ECPublicKey deviceKey) { try { var encodedUserKey = Base64.getEncoder().encodeToString(userKey.getEncoded()); @@ -55,7 +55,7 @@ class JWEHelper { public static ECPrivateKey decryptUserKey(JWEObject jwe, String setupCode) throws InvalidJweKeyException { try { jwe.decrypt(new PasswordBasedDecrypter(setupCode)); - return decodeUserKey(jwe); + return readKey(jwe, JWE_PAYLOAD_KEY_FIELD, JWEHelper::decodeECPrivateKey); } catch (JOSEException e) { throw new InvalidJweKeyException(e); } @@ -64,17 +64,23 @@ class JWEHelper { public static ECPrivateKey decryptUserKey(JWEObject jwe, ECPrivateKey deviceKey) throws InvalidJweKeyException { try { jwe.decrypt(new ECDHDecrypter(deviceKey)); - return decodeUserKey(jwe); + return readKey(jwe, JWE_PAYLOAD_KEY_FIELD, JWEHelper::decodeECPrivateKey); } catch (JOSEException e) { throw new InvalidJweKeyException(e); } } - private static ECPrivateKey decodeUserKey(JWEObject decryptedJwe) { + /** + * Attempts to decode a DER-encoded EC private key. + * + * @param encoded DER-encoded EC private key + * @return the decoded key + * @throws KeyDecodeFailedException On malformed input + */ + public static ECPrivateKey decodeECPrivateKey(byte[] encoded) throws KeyDecodeFailedException { try { - var keySpec = readKey(decryptedJwe, JWE_PAYLOAD_KEY_FIELD, PKCS8EncodedKeySpec::new); - var factory = KeyFactory.getInstance(EC_ALG); - var privateKey = factory.generatePrivate(keySpec); + KeyFactory factory = KeyFactory.getInstance(EC_ALG); + var privateKey = factory.generatePrivate(new PKCS8EncodedKeySpec(encoded)); if (privateKey instanceof ECPrivateKey ecPrivateKey) { return ecPrivateKey; } else { @@ -83,8 +89,9 @@ class JWEHelper { } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(EC_ALG + " not supported"); } catch (InvalidKeySpecException e) { - LOG.warn("Unexpected JWE payload: {}", decryptedJwe.getPayload()); - throw new MasterkeyLoadingFailedException("Unexpected JWE payload", e); + throw new KeyDecodeFailedException(e); + } + } } } @@ -112,7 +119,7 @@ class JWEHelper { } else { throw new IllegalArgumentException("JWE payload doesn't contain field " + keyField); } - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException | KeyDecodeFailedException e) { LOG.error("Unexpected JWE payload: {}", jwe.getPayload()); throw new MasterkeyLoadingFailedException("Unexpected JWE payload", e); } finally { @@ -126,4 +133,11 @@ class JWEHelper { super("Invalid key", cause); } } + + public static class KeyDecodeFailedException extends CryptoException { + + public KeyDecodeFailedException(Throwable cause) { + super("Malformed key", cause); + } + } }