Browse Source

refactor API, expose `decodeECPrivateKey(byte[])`

Sebastian Stenzel 1 year ago
parent
commit
e9ee17493b
1 changed files with 26 additions and 12 deletions
  1. 26 12
      src/main/java/org/cryptomator/ui/keyloading/hub/JWEHelper.java

+ 26 - 12
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);
+		}
+	}
 }