From 7e4fdd54046e1e550c5cdf3abf757f0932090731 Mon Sep 17 00:00:00 2001 From: zihluwang Date: Sat, 27 Jul 2024 10:10:44 +0800 Subject: [PATCH] feat: load ECDSA key pairs with pem-formatted text --- .../com/onixbyte/keypairloader/KeyLoader.java | 74 ------------- .../java/com/onixbyte/security/KeyLoader.java | 100 ++++++++++++++++++ .../exception/KeyLoadingException.java | 2 +- .../KeyPairLoaderTest.java | 2 +- 4 files changed, 102 insertions(+), 76 deletions(-) delete mode 100644 key-pair-loader/src/main/java/com/onixbyte/keypairloader/KeyLoader.java create mode 100644 key-pair-loader/src/main/java/com/onixbyte/security/KeyLoader.java rename key-pair-loader/src/main/java/com/onixbyte/{keypairloader => security}/exception/KeyLoadingException.java (96%) rename key-pair-loader/src/test/java/com/onixbyte/{keypairloader => security}/KeyPairLoaderTest.java (95%) diff --git a/key-pair-loader/src/main/java/com/onixbyte/keypairloader/KeyLoader.java b/key-pair-loader/src/main/java/com/onixbyte/keypairloader/KeyLoader.java deleted file mode 100644 index a2bdcf3..0000000 --- a/key-pair-loader/src/main/java/com/onixbyte/keypairloader/KeyLoader.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2024-2024 OnixByte. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.onixbyte.keypairloader; - -import com.onixbyte.keypairloader.exception.KeyLoadingException; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Base64; -import java.util.Optional; - -/** - * KeyLoader can load key pairs from PEM formated content. - * - * @author zihluwang - * @version 1.6.0 - * @since 1.6.0 - */ -@Slf4j -public class KeyLoader { - - /** - * Private constructor prevents from being initialised. - */ - private KeyLoader() { - } - - public ECPrivateKey loadEcdsaPrivateKey(String pemKeyText) { - return Optional.ofNullable(pemKeyText) - .map(Base64.getDecoder()::decode) - .map(PKCS8EncodedKeySpec::new) - .map((keySpec) -> { - try { - var kf = KeyFactory.getInstance("EC"); - return kf.generatePrivate(keySpec); - } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { - throw new KeyLoadingException("Unable to load key from text.", e); - } - }).map((publicKey) -> { - if (publicKey instanceof ECPrivateKey privateKey) { - return privateKey; - } - return null; - }) - .orElse(null); - } - - // public ECPublicKey loadEcdsaPublicKey(String pemKeyText) { - // - // } - -} diff --git a/key-pair-loader/src/main/java/com/onixbyte/security/KeyLoader.java b/key-pair-loader/src/main/java/com/onixbyte/security/KeyLoader.java new file mode 100644 index 0000000..0e3c8ac --- /dev/null +++ b/key-pair-loader/src/main/java/com/onixbyte/security/KeyLoader.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2024-2024 OnixByte. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.onixbyte.security; + +import com.onixbyte.security.exception.KeyLoadingException; +import lombok.extern.slf4j.Slf4j; + +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +/** + * KeyLoader can load key pairs from PEM formated content. + * + * @author zihluwang + * @version 1.6.0 + * @since 1.6.0 + */ +@Slf4j +public class KeyLoader { + + /** + * Private constructor prevents from being initialised. + */ + private KeyLoader() { + } + + /** + * Load ECDSA private key from pem-formatted key text. + * + * @param pemKeyText pem-formatted key text + * @return loaded private key + * @throws KeyLoadingException if the generated key is not a {@link ECPrivateKey} instance, or EC Key Factory is + * not loaded, or key spec is invalid + */ + public ECPrivateKey loadEcdsaPrivateKey(String pemKeyText) { + try { + var decodedKeyString = Base64.getDecoder().decode(pemKeyText); + var keySpec = new PKCS8EncodedKeySpec(decodedKeyString); + var keyFactory = KeyFactory.getInstance("EC"); + var _key = keyFactory.generatePrivate(keySpec); + if (_key instanceof ECPrivateKey privateKey) { + return privateKey; + } else { + throw new KeyLoadingException("Unable to load private key from pem-formatted key text."); + } + } catch (NoSuchAlgorithmException e) { + throw new KeyLoadingException("Cannot get EC Key Factory.", e); + } catch (InvalidKeySpecException e) { + throw new KeyLoadingException("Key spec is invalid.", e); + } + } + + /** + * Load ECDSA public key from pem-formatted key text. + * + * @param pemKeyText pem-formatted key text + * @return loaded private key + * @throws KeyLoadingException if the generated key is not a {@link ECPrivateKey} instance, or EC Key Factory is + * not loaded, or key spec is invalid + */ + public ECPublicKey loadEcdsaPublicKey(String pemKeyText) { + try { + var keyBytes = Base64.getDecoder().decode(pemKeyText); + var spec = new X509EncodedKeySpec(keyBytes); + var keyFactory = KeyFactory.getInstance("EC"); + var key = keyFactory.generatePublic(spec); + if (key instanceof ECPublicKey publicKey) { + return publicKey; + } else { + throw new KeyLoadingException("Unable to load private key from pem-formatted key text."); + } + } catch (NoSuchAlgorithmException e) { + throw new KeyLoadingException("Cannot get EC Key Factory.", e); + } catch (InvalidKeySpecException e) { + throw new KeyLoadingException("Key spec is invalid.", e); + } + } + +} diff --git a/key-pair-loader/src/main/java/com/onixbyte/keypairloader/exception/KeyLoadingException.java b/key-pair-loader/src/main/java/com/onixbyte/security/exception/KeyLoadingException.java similarity index 96% rename from key-pair-loader/src/main/java/com/onixbyte/keypairloader/exception/KeyLoadingException.java rename to key-pair-loader/src/main/java/com/onixbyte/security/exception/KeyLoadingException.java index 3a72811..4682d67 100644 --- a/key-pair-loader/src/main/java/com/onixbyte/keypairloader/exception/KeyLoadingException.java +++ b/key-pair-loader/src/main/java/com/onixbyte/security/exception/KeyLoadingException.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.onixbyte.keypairloader.exception; +package com.onixbyte.security.exception; public class KeyLoadingException extends RuntimeException { diff --git a/key-pair-loader/src/test/java/com/onixbyte/keypairloader/KeyPairLoaderTest.java b/key-pair-loader/src/test/java/com/onixbyte/security/KeyPairLoaderTest.java similarity index 95% rename from key-pair-loader/src/test/java/com/onixbyte/keypairloader/KeyPairLoaderTest.java rename to key-pair-loader/src/test/java/com/onixbyte/security/KeyPairLoaderTest.java index 5a5abdd..edfc670 100644 --- a/key-pair-loader/src/test/java/com/onixbyte/keypairloader/KeyPairLoaderTest.java +++ b/key-pair-loader/src/test/java/com/onixbyte/security/KeyPairLoaderTest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.onixbyte.keypairloader; +package com.onixbyte.security; import org.junit.jupiter.api.Test;