From cf7e5efa62fbb821461c865dcd30e39c854e07e0 Mon Sep 17 00:00:00 2001 From: zihluwang Date: Sun, 26 Jan 2025 20:05:06 +0800 Subject: [PATCH] test: tested loading ECDSA key pair from text --- key-pair-loader/README.md | 64 +++++++++++++++++++ .../onixbyte/security/impl/EcKeyLoader.java | 21 +++--- .../onixbyte/security/KeyPairLoaderTest.java | 16 ++++- .../src/test/resources/ec_private_key.pem | 5 ++ .../test/resources/ec_private_key_pkcs8.pem | 5 ++ .../src/test/resources/ec_public_key.pem | 4 ++ .../authzero/AuthzeroTokenResolver.java | 1 + 7 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 key-pair-loader/README.md create mode 100644 key-pair-loader/src/test/resources/ec_private_key.pem create mode 100644 key-pair-loader/src/test/resources/ec_private_key_pkcs8.pem create mode 100644 key-pair-loader/src/test/resources/ec_public_key.pem diff --git a/key-pair-loader/README.md b/key-pair-loader/README.md new file mode 100644 index 0000000..2a8186d --- /dev/null +++ b/key-pair-loader/README.md @@ -0,0 +1,64 @@ +# KeyLoader + +KeyLoader provides utility methods to load keys from pem-formatted key texts. + +## ECDSA-based algorithm + +### Generate key pair + +#### Generate private key + +Generate a private key by `genpkey` command provided by OpenSSL: + +```shell +openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out ec_private_key.pem +``` + +The output of this command is a file called `ec_private_key.pem` and its content looks like the +following: + +```text +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs79JlARgXEf6EDV7 ++PHQCTHEMtqIoHOy1GZ1+ynQJ6yhRANCAARkA7GRY2i4gg8qx0XViAXUP9cPw9pn +Jg1wfrQ41FaMyqVBejNYxvaLtamErF/ySimnjafMJ+VZCh34lBj6Ez8R +-----END PRIVATE KEY----- +``` + +#### Generate public key by private key + +Export public key from private key with `ec` command provided by OpenSSL: + +```shell +openssl ec -in ec_private_key.pem -pubout -out ec_public_key.pem +``` + +The output of this command is a file called `ec_public_key.pem` and its content looks like the +following: + +```text +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZAOxkWNouIIPKsdF1YgF1D/XD8Pa +ZyYNcH60ONRWjMqlQXozWMb2i7WphKxf8kopp42nzCflWQod+JQY+hM/EQ== +-----END PUBLIC KEY----- +``` + +#### Convert private key to EC formats which could be acceptable by Java + +Java's `PKCS8EncodedKeySpec` requires the private key to be in PKCS#8 format, while OpenSSL by +default generates private keys in traditional PEM format. To convert the private key, run the +following command: + +```shell +openssl pkcs8 -topk8 -inform PEM -outform PEM -in ec_private_key.pem -out ec_private_key_pkcs8.pem -nocrypt +``` + +The converted private key will look like this: + +```text +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs79JlARgXEf6EDV7 ++PHQCTHEMtqIoHOy1GZ1+ynQJ6yhRANCAARkA7GRY2i4gg8qx0XViAXUP9cPw9pn +Jg1wfrQ41FaMyqVBejNYxvaLtamErF/ySimnjafMJ+VZCh34lBj6Ez8R +-----END PRIVATE KEY----- +``` \ No newline at end of file diff --git a/key-pair-loader/src/main/java/com/onixbyte/security/impl/EcKeyLoader.java b/key-pair-loader/src/main/java/com/onixbyte/security/impl/EcKeyLoader.java index 9704214..867e968 100644 --- a/key-pair-loader/src/main/java/com/onixbyte/security/impl/EcKeyLoader.java +++ b/key-pair-loader/src/main/java/com/onixbyte/security/impl/EcKeyLoader.java @@ -55,12 +55,13 @@ public class EcKeyLoader implements KeyLoader { /** * Initialise a key loader for EC-based algorithms. - * - * @throws NoSuchAlgorithmException if no {@code Provider} supports a {@code KeyFactorySpi} - * implementation for the specified algorithm */ - public EcKeyLoader() throws NoSuchAlgorithmException { - this.keyFactory = KeyFactory.getInstance("EC"); + public EcKeyLoader() { + try { + this.keyFactory = KeyFactory.getInstance("EC"); + } catch (NoSuchAlgorithmException e) { + throw new KeyLoadingException(e); + } } /** @@ -76,8 +77,8 @@ public class EcKeyLoader implements KeyLoader { try { // remove all unnecessary parts of the pem key text pemKeyText = pemKeyText - .replaceAll("-----BEGIN EC PRIVATE KEY-----", "") - .replaceAll("-----END EC PRIVATE KEY-----", "") + .replaceAll("-----BEGIN (EC )?PRIVATE KEY-----", "") + .replaceAll("-----END (EC )?PRIVATE KEY-----", "") .replaceAll("\n", ""); var decodedKeyString = Base64.getDecoder().decode(pemKeyText); var keySpec = new PKCS8EncodedKeySpec(decodedKeyString); @@ -106,8 +107,8 @@ public class EcKeyLoader implements KeyLoader { try { // remove all unnecessary parts of the pem key text pemKeyText = pemKeyText - .replaceAll("-----BEGIN EC PUBLIC KEY-----", "") - .replaceAll("-----END EC PUBLIC KEY-----", "") + .replaceAll("-----BEGIN (EC )?PUBLIC KEY-----", "") + .replaceAll("-----END (EC )?PUBLIC KEY-----", "") .replaceAll("\n", ""); var keyBytes = Base64.getDecoder().decode(pemKeyText); var spec = new X509EncodedKeySpec(keyBytes); @@ -115,7 +116,7 @@ public class EcKeyLoader implements KeyLoader { if (key instanceof ECPublicKey publicKey) { return publicKey; } else { - throw new KeyLoadingException("Unable to load private key from pem-formatted key text."); + throw new KeyLoadingException("Unable to load public key from pem-formatted key text."); } } catch (InvalidKeySpecException e) { throw new KeyLoadingException("Key spec is invalid.", e); diff --git a/key-pair-loader/src/test/java/com/onixbyte/security/KeyPairLoaderTest.java b/key-pair-loader/src/test/java/com/onixbyte/security/KeyPairLoaderTest.java index edfc670..c4e11f9 100644 --- a/key-pair-loader/src/test/java/com/onixbyte/security/KeyPairLoaderTest.java +++ b/key-pair-loader/src/test/java/com/onixbyte/security/KeyPairLoaderTest.java @@ -17,13 +17,27 @@ package com.onixbyte.security; +import com.onixbyte.security.impl.EcKeyLoader; import org.junit.jupiter.api.Test; public class KeyPairLoaderTest { @Test public void test() { - + var keyLoader = new EcKeyLoader(); + var privateKey = keyLoader.loadPrivateKey(""" + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs79JlARgXEf6EDV7 + +PHQCTHEMtqIoHOy1GZ1+ynQJ6yhRANCAARkA7GRY2i4gg8qx0XViAXUP9cPw9pn + Jg1wfrQ41FaMyqVBejNYxvaLtamErF/ySimnjafMJ+VZCh34lBj6Ez8R + -----END PRIVATE KEY----- + """); + var publicKey = keyLoader.loadPublicKey(""" + -----BEGIN PUBLIC KEY----- + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZAOxkWNouIIPKsdF1YgF1D/XD8Pa + ZyYNcH60ONRWjMqlQXozWMb2i7WphKxf8kopp42nzCflWQod+JQY+hM/EQ== + -----END PUBLIC KEY----- + """); } } diff --git a/key-pair-loader/src/test/resources/ec_private_key.pem b/key-pair-loader/src/test/resources/ec_private_key.pem new file mode 100644 index 0000000..02dfcc8 --- /dev/null +++ b/key-pair-loader/src/test/resources/ec_private_key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs79JlARgXEf6EDV7 ++PHQCTHEMtqIoHOy1GZ1+ynQJ6yhRANCAARkA7GRY2i4gg8qx0XViAXUP9cPw9pn +Jg1wfrQ41FaMyqVBejNYxvaLtamErF/ySimnjafMJ+VZCh34lBj6Ez8R +-----END PRIVATE KEY----- diff --git a/key-pair-loader/src/test/resources/ec_private_key_pkcs8.pem b/key-pair-loader/src/test/resources/ec_private_key_pkcs8.pem new file mode 100644 index 0000000..02dfcc8 --- /dev/null +++ b/key-pair-loader/src/test/resources/ec_private_key_pkcs8.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs79JlARgXEf6EDV7 ++PHQCTHEMtqIoHOy1GZ1+ynQJ6yhRANCAARkA7GRY2i4gg8qx0XViAXUP9cPw9pn +Jg1wfrQ41FaMyqVBejNYxvaLtamErF/ySimnjafMJ+VZCh34lBj6Ez8R +-----END PRIVATE KEY----- diff --git a/key-pair-loader/src/test/resources/ec_public_key.pem b/key-pair-loader/src/test/resources/ec_public_key.pem new file mode 100644 index 0000000..ff0054e --- /dev/null +++ b/key-pair-loader/src/test/resources/ec_public_key.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZAOxkWNouIIPKsdF1YgF1D/XD8Pa +ZyYNcH60ONRWjMqlQXozWMb2i7WphKxf8kopp42nzCflWQod+JQY+hM/EQ== +-----END PUBLIC KEY----- diff --git a/simple-jwt-authzero/src/main/java/com/onixbyte/simplejwt/authzero/AuthzeroTokenResolver.java b/simple-jwt-authzero/src/main/java/com/onixbyte/simplejwt/authzero/AuthzeroTokenResolver.java index 8b18cd7..759054c 100644 --- a/simple-jwt-authzero/src/main/java/com/onixbyte/simplejwt/authzero/AuthzeroTokenResolver.java +++ b/simple-jwt-authzero/src/main/java/com/onixbyte/simplejwt/authzero/AuthzeroTokenResolver.java @@ -43,6 +43,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; +import java.security.NoSuchAlgorithmException; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.time.Duration;