@@ -0,0 +1,113 @@
|
||||
# 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-----
|
||||
```
|
||||
|
||||
## RSA-based algorithm
|
||||
|
||||
### Generate key pair
|
||||
|
||||
#### Generate private key
|
||||
|
||||
Generate a private key by `genpkey` command provided by OpenSSL:
|
||||
|
||||
```shell
|
||||
openssl genpkey -algorithm RSA -out rsa_private_key.pem -pkeyopt rsa_keygen_bits:2048
|
||||
```
|
||||
|
||||
The output of this command is a file called `rsa_private_key.pem` and its content looks like the
|
||||
following:
|
||||
|
||||
```text
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD4VIFYJFMAs15j
|
||||
J3V3IicHd7sI2TIFqTZME40zlOlVAlPKLZmTQvZFLNgaUAAsvPi5i1DR2ywwK6Al
|
||||
BfnwVnzvmDXC5mKHOz4oxOQVA6Nlp2yVaQMzidmfYNSkMtcv/4HRPsatc7K/M5l6
|
||||
pCP20DVRjkikBdIy8e9w+x6BrIFp5Q8PZc/X2BGNAUMMYACdeYH5R/A0CxqkND13
|
||||
esc4gkynMOrvZrZGHCz51usfSCqyDWWwsN+GG6LYWia4GkNlS0erQnP8gS93dfjl
|
||||
e96BIfy3z7Iv+kUrf5ikNW2P8jMxLAv6LO+dcUAu9k477wIAF7Iq5KMuH/otsDOu
|
||||
+h+2qXmBAgMBAAECggEAdRqcmC0g+y6arxV3fkObthjPGYAa57KBCWUa7B0n30+m
|
||||
pavVRS2Jpttb2SSqwG4ouI6rARti/iBEd9EWqTCP4AieKZetFOpqCJ24lPRPRGus
|
||||
d9S6jr5N4qut+vSCp37NABijZj4uJ540nTH0R7qtuhTnynl4Q0/1wwiYvTvVF1Lg
|
||||
dn+I/8aRbshwDhdAOWOUe6GL7/eaCYgN8/UmlKIpp8tg0w2iWxbaFiR7gZiM41LA
|
||||
M6SXXfcCas+ZVXsGbzQ3SNiVurCGuuRNcCScXS3/WoEDIb3cNtp49iOmQS+nmEoo
|
||||
wh4uiEd+0+BrzxngS4o5+mKnHJnwgY0+veGVYLMR5QKBgQD9WKQmevMDU5c+NPq9
|
||||
8jaR457Fuxq1gwzeFNJdWfOc/K2LEWh+nFNFCb++EboEj6FdxWaWNMxbrmJps5gs
|
||||
EoBUYy/Tl7UycDqDfiYLmDdTsf2pVjjh9jaIADiLcJ8S6wwJMZKub7Tp8UVkenAl
|
||||
535MqShLUC11Y7VxLb3Tsll4XwKBgQD67mm6iCmshr/eszPfNE3ylZ+PiNa7nat7
|
||||
N7lQzBIiRJflT1kmVidC5gE+jASqH728ChkZZKxbHsjxpmWdAhLOITdXoTB4sDsd
|
||||
wtV1lxkXxK9FnrpFvO3y1wZ/QsD3Z2KXxHYZqawkUETO9F3nqAXW0b2GDar5Qiyo
|
||||
J3Tx/43aHwKBgDC0NMJtCoDONhowZy/S+6iqQKC0qprQec3L5PErVMkOTnKYwyTr
|
||||
+pogGKt6ju9HiXcUdvdTaSIK8UJu00dNuzv94XjlBmGO78DNpJTAC4rcge5m9AKE
|
||||
qdEVcclkukARzbuKuy8rrHT4/CUn4J141m/4aRWpcUPLCluato6XD9ozAoGBANvf
|
||||
JhOFFgcPd3YazfvpZ9eE1XA+tfFlYYmxNRcgCU+vjO0oDvSxjutmgHae18N91pG6
|
||||
w21lskSRf/+GDwl5dKLbphOJsOA/gz07qDDGOf2CoRW+1Hcg6drcINxH0K+4DkLv
|
||||
qZApBSY4k2JH6zR+HMeztn6M4WBRZLHfCPC3PUN/AoGAA3AoHbLTZvqMIKSDkP4Y
|
||||
U/tTsSFDY4aYo7LG/jk8af3oPU3KyGh4ZFBd6aMmXbS8f8FjvmrM+/e+y9OOGAlq
|
||||
iOl0hYrs5cJSMLW6i4KnJYuYbMkgmk3bN2t9apu64xKR94gbPrI6AGnPZp+iIzp0
|
||||
hXKe4HcuhQ3G0a2hjayiQ84=
|
||||
-----END PRIVATE KEY-----
|
||||
```
|
||||
|
||||
#### Generate public key by private key
|
||||
|
||||
Export public key from private key by OpenSSL:
|
||||
|
||||
```shell
|
||||
openssl pkey -in rsa_private_key.pem -pubout -out rsa_public_key.pem
|
||||
```
|
||||
|
||||
The output of this command is a file called `rsa_public_key.pem` and its content looks like the
|
||||
following:
|
||||
|
||||
```text
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+FSBWCRTALNeYyd1dyIn
|
||||
B3e7CNkyBak2TBONM5TpVQJTyi2Zk0L2RSzYGlAALLz4uYtQ0dssMCugJQX58FZ8
|
||||
75g1wuZihzs+KMTkFQOjZadslWkDM4nZn2DUpDLXL/+B0T7GrXOyvzOZeqQj9tA1
|
||||
UY5IpAXSMvHvcPsegayBaeUPD2XP19gRjQFDDGAAnXmB+UfwNAsapDQ9d3rHOIJM
|
||||
pzDq72a2Rhws+dbrH0gqsg1lsLDfhhui2FomuBpDZUtHq0Jz/IEvd3X45XvegSH8
|
||||
t8+yL/pFK3+YpDVtj/IzMSwL+izvnXFALvZOO+8CABeyKuSjLh/6LbAzrvoftql5
|
||||
gQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
```
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.
|
||||
*/
|
||||
import java.net.URI
|
||||
|
||||
plugins {
|
||||
java
|
||||
id("java-library")
|
||||
id("maven-publish")
|
||||
id("signing")
|
||||
}
|
||||
|
||||
val artefactVersion: String by project
|
||||
val projectUrl: String by project
|
||||
val projectGithubUrl: String by project
|
||||
val licenseName: String by project
|
||||
val licenseUrl: String by project
|
||||
|
||||
group = "com.onixbyte"
|
||||
version = artefactVersion
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
exclude("logback.xml")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.slf4j)
|
||||
implementation(libs.logback)
|
||||
testImplementation(libs.jwt.core)
|
||||
testImplementation(platform(libs.junit.bom))
|
||||
testImplementation(libs.junit.jupiter)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events("passed", "skipped", "failed")
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("cryptoToolbox") {
|
||||
groupId = group.toString()
|
||||
artifactId = "crypto-toolbox"
|
||||
version = artefactVersion
|
||||
|
||||
pom {
|
||||
name = "OnixByte Crypto Toolbox"
|
||||
description =
|
||||
"This module can easily load key pairs from a PEM content."
|
||||
url = projectUrl
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name = licenseName
|
||||
url = licenseUrl
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection = "scm:git:git://github.com:OnixByte/JDevKit.git"
|
||||
developerConnection = "scm:git:git://github.com:OnixByte/JDevKit.git"
|
||||
url = projectGithubUrl
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id = "zihluwang"
|
||||
name = "Zihlu Wang"
|
||||
email = "really@zihlu.wang"
|
||||
timezone = "Asia/Hong_Kong"
|
||||
}
|
||||
|
||||
developer {
|
||||
id = "siujamo"
|
||||
name = "Siu Jam'o"
|
||||
email = "jamo.siu@outlook.com"
|
||||
timezone = "Asia/Shanghai"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
from(components["java"])
|
||||
|
||||
signing {
|
||||
sign(publishing.publications["cryptoToolbox"])
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "sonatypeNexus"
|
||||
url = URI(providers.gradleProperty("repo.maven-central.host").get())
|
||||
credentials {
|
||||
username = providers.gradleProperty("repo.maven-central.username").get()
|
||||
password = providers.gradleProperty("repo.maven-central.password").get()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.crypto;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
|
||||
/**
|
||||
* The {@code PrivateKeyLoader} interface provides utility methods for loading keys pairs from
|
||||
* PEM-formatted key text. This class supports loading both private and public keys.
|
||||
*
|
||||
* @author zihluwang
|
||||
* @author siujamo
|
||||
* @version 2.0.0
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public interface PrivateKeyLoader {
|
||||
|
||||
/**
|
||||
* Load private key from pem-formatted key text.
|
||||
*
|
||||
* @param pemKeyText pem-formatted key text
|
||||
* @return loaded private key
|
||||
*/
|
||||
PrivateKey loadPrivateKey(String pemKeyText);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.crypto;
|
||||
|
||||
import com.onixbyte.crypto.exception.KeyLoadingException;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author siujamo
|
||||
* @version 3.0.0
|
||||
*/
|
||||
public interface PublicKeyLoader {
|
||||
|
||||
/**
|
||||
* Load public key from pem-formatted key text.
|
||||
*
|
||||
* @param pemKeyText pem-formatted key text
|
||||
* @return loaded private key
|
||||
*/
|
||||
PublicKey loadPublicKey(String pemKeyText);
|
||||
|
||||
/**
|
||||
* Loads an EC public key using the provided x and y coordinates together with the curve name.
|
||||
* <p>
|
||||
* This default implementation throws a {@link KeyLoadingException} to signify that this key
|
||||
* loader does not support loading an EC public key. Implementing classes are expected to
|
||||
* override this method to supply their own loading logic.
|
||||
*
|
||||
* @param xHex the hexadecimal string representing the x coordinate of the EC point
|
||||
* @param yHex the hexadecimal string representing the y coordinate of the EC point
|
||||
* @param curveName the name of the elliptic curve
|
||||
* @return the loaded {@link ECPublicKey} instance
|
||||
* @throws KeyLoadingException if loading is not supported or fails
|
||||
*/
|
||||
default ECPublicKey loadPublicKey(String xHex, String yHex, String curveName) {
|
||||
throw new KeyLoadingException("This key loader does not support loading an EC public key.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an RSA public key using the provided modulus and exponent.
|
||||
* <p>
|
||||
* This default implementation throws a {@link KeyLoadingException} to signify that this key
|
||||
* loader does not support loading an RSA public key. Implementing classes are expected to
|
||||
* override this method to supply their own loading logic.
|
||||
*
|
||||
* @param modulus the modulus value of the RSA public key, usually represented in hexadecimal
|
||||
* or Base64 string format
|
||||
* @param exponent the public exponent value of the RSA public key, usually represented in
|
||||
* hexadecimal or Base64 string format
|
||||
* @return the loaded {@link RSAPublicKey} instance
|
||||
* @throws KeyLoadingException if loading is not supported or fails
|
||||
*/
|
||||
default RSAPublicKey loadPublicKey(String modulus, String exponent) {
|
||||
throw new KeyLoadingException("This key loader does not support loading an RSA public key.");
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.crypto.algorithm.ecdsa;
|
||||
|
||||
import com.onixbyte.crypto.PrivateKeyLoader;
|
||||
import com.onixbyte.crypto.exception.KeyLoadingException;
|
||||
import com.onixbyte.crypto.util.CryptoUtil;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.*;
|
||||
import java.util.Base64;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Key pair loader for loading key pairs for ECDSA-based algorithms.
|
||||
* <p>
|
||||
*
|
||||
* <b>Example usage for ECDSA:</b>
|
||||
* <pre>{@code
|
||||
* PrivateKeyLoader keyLoader = new EcKeyLoader();
|
||||
* String pemPrivateKey = """
|
||||
* -----BEGIN EC PRIVATE KEY-----
|
||||
* ...
|
||||
* -----END EC PRIVATE KEY-----""";
|
||||
* ECPrivateKey privateKey = PrivateKeyLoader.loadEcdsaPrivateKey(pemPrivateKey);
|
||||
*
|
||||
* String pemPublicKey = """
|
||||
* -----BEGIN EC PUBLIC KEY-----
|
||||
* ...
|
||||
* -----END EC PUBLIC KEY-----""";
|
||||
* ECPublicKey publicKey = PrivateKeyLoader.loadPublicKey(pemPublicKey);
|
||||
* }</pre>
|
||||
*
|
||||
* @author zihluwang
|
||||
* @version 2.0.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ECPrivateKeyLoader implements PrivateKeyLoader {
|
||||
|
||||
private final KeyFactory keyFactory;
|
||||
|
||||
private final Base64.Decoder decoder;
|
||||
|
||||
/**
|
||||
* Initialise a key loader for EC-based algorithms.
|
||||
*/
|
||||
public ECPrivateKeyLoader() {
|
||||
try {
|
||||
this.keyFactory = KeyFactory.getInstance("EC");
|
||||
this.decoder = Base64.getDecoder();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new KeyLoadingException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Override
|
||||
public ECPrivateKey loadPrivateKey(String pemKeyText) {
|
||||
try {
|
||||
pemKeyText = CryptoUtil.getRawContent(pemKeyText);
|
||||
var decodedKeyString = decoder.decode(pemKeyText);
|
||||
var keySpec = new PKCS8EncodedKeySpec(decodedKeyString);
|
||||
|
||||
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 (InvalidKeySpecException e) {
|
||||
throw new KeyLoadingException("Key spec is invalid.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.crypto.algorithm.ecdsa;
|
||||
|
||||
import com.onixbyte.crypto.PublicKeyLoader;
|
||||
import com.onixbyte.crypto.exception.KeyLoadingException;
|
||||
import com.onixbyte.crypto.util.CryptoUtil;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.*;
|
||||
import java.util.Base64;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ECPublicKeyLoader implements PublicKeyLoader {
|
||||
|
||||
/**
|
||||
* Supported curves.
|
||||
*/
|
||||
public static final Set<String> SUPPORTED_CURVES = new HashSet<>(Set.of(
|
||||
"secp256r1", "secp384r1", "secp521r1", "secp224r1"
|
||||
));
|
||||
|
||||
private final KeyFactory keyFactory;
|
||||
|
||||
private final Base64.Decoder decoder;
|
||||
|
||||
/**
|
||||
* Initialise a key loader for EC-based algorithms.
|
||||
*/
|
||||
public ECPublicKeyLoader() {
|
||||
try {
|
||||
this.keyFactory = KeyFactory.getInstance("EC");
|
||||
this.decoder = Base64.getDecoder();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new KeyLoadingException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load 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
|
||||
*/
|
||||
@Override
|
||||
public ECPublicKey loadPublicKey(String pemKeyText) {
|
||||
try {
|
||||
pemKeyText = CryptoUtil.getRawContent(pemKeyText);
|
||||
var keyBytes = decoder.decode(pemKeyText);
|
||||
var spec = new X509EncodedKeySpec(keyBytes);
|
||||
var key = keyFactory.generatePublic(spec);
|
||||
if (key instanceof ECPublicKey publicKey) {
|
||||
return publicKey;
|
||||
} else {
|
||||
throw new KeyLoadingException("Unable to load public key from pem-formatted key text.");
|
||||
}
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new KeyLoadingException("Key spec is invalid.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an EC public key from the given hexadecimal x and y coordinates alongside the curve name.
|
||||
* <p>
|
||||
* This method converts the hexadecimal string representations of the EC point coordinates into {@link BigInteger}
|
||||
* instances, then constructs an {@link ECPoint} and retrieves the corresponding {@link ECParameterSpec} for the
|
||||
* named curve. Subsequently, it utilises the {@link KeyFactory} to generate an {@link ECPublicKey}.
|
||||
* <p>
|
||||
* Only curves listed in {@link #SUPPORTED_CURVES} are supported. Should the specified curve name be unsupported,
|
||||
* or if key construction fails due to invalid parameters or unsupported algorithms, a {@link KeyLoadingException}
|
||||
* will be thrown.
|
||||
*
|
||||
* @param xHex the hexadecimal string representing the x-coordinate of the EC point
|
||||
* @param yHex the hexadecimal string representing the y-coordinate of the EC point
|
||||
* @param curveName the name of the elliptic curve
|
||||
* @return the {@link ECPublicKey} generated from the specified coordinates and curve
|
||||
* @throws KeyLoadingException if the curve is unsupported or key generation fails
|
||||
*/
|
||||
@Override
|
||||
public ECPublicKey loadPublicKey(String xHex, String yHex, String curveName) {
|
||||
if (!SUPPORTED_CURVES.contains(curveName)) {
|
||||
throw new KeyLoadingException("Given curve is not supported yet.");
|
||||
}
|
||||
|
||||
try {
|
||||
// Convert hex string coordinates to BigInteger
|
||||
var x = new BigInteger(xHex, 16);
|
||||
var y = new BigInteger(yHex, 16);
|
||||
|
||||
// Create ECPoint with (x, y)
|
||||
var ecPoint = new ECPoint(x, y);
|
||||
|
||||
// Get EC parameter spec for the named curve
|
||||
var parameters = AlgorithmParameters.getInstance("EC");
|
||||
parameters.init(new ECGenParameterSpec(curveName));
|
||||
var ecParameterSpec = parameters.getParameterSpec(ECParameterSpec.class);
|
||||
|
||||
// Create ECPublicKeySpec with point and curve params
|
||||
var pubSpec = new ECPublicKeySpec(ecPoint, ecParameterSpec);
|
||||
|
||||
// Generate public key using KeyFactory
|
||||
var publicKey = keyFactory.generatePublic(pubSpec);
|
||||
|
||||
if (publicKey instanceof ECPublicKey ecPublicKey) {
|
||||
return ecPublicKey;
|
||||
} else {
|
||||
throw new KeyLoadingException("Cannot load EC public key with given x, y and curve name.");
|
||||
}
|
||||
} catch (NoSuchAlgorithmException | InvalidParameterSpecException | InvalidKeySpecException e) {
|
||||
throw new KeyLoadingException("Cannot load EC public key with given x, y and curve name.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.crypto.algorithm.rsa;
|
||||
|
||||
import com.onixbyte.crypto.PrivateKeyLoader;
|
||||
import com.onixbyte.crypto.exception.KeyLoadingException;
|
||||
import com.onixbyte.crypto.util.CryptoUtil;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.*;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* A class responsible for loading RSA keys from PEM formatted text.
|
||||
* <p>
|
||||
* This class implements the {@link PrivateKeyLoader} interface and provides methods to load both private
|
||||
* and public RSA keys. The keys are expected to be in the standard PEM format, which includes
|
||||
* Base64-encoded key content surrounded by header and footer lines. The class handles the decoding
|
||||
* of Base64 content and the generation of keys using the RSA key factory.
|
||||
* <p>
|
||||
* Any exceptions encountered during the loading process are encapsulated in a
|
||||
* {@link KeyLoadingException}, allowing for flexible error handling.
|
||||
*
|
||||
* @author siujamo
|
||||
* @see PrivateKeyLoader
|
||||
* @see KeyLoadingException
|
||||
*/
|
||||
public class RSAPrivateKeyLoader implements PrivateKeyLoader {
|
||||
|
||||
private final Base64.Decoder decoder;
|
||||
|
||||
private final KeyFactory keyFactory;
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@code RsaKeyLoader}.
|
||||
* <p>
|
||||
* This constructor initialises the Base64 decoder and the RSA {@link KeyFactory}. It may throw
|
||||
* a {@link KeyLoadingException} if the RSA algorithm is not available.
|
||||
*/
|
||||
public RSAPrivateKeyLoader() {
|
||||
try {
|
||||
this.decoder = Base64.getDecoder();
|
||||
this.keyFactory = KeyFactory.getInstance("RSA");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new KeyLoadingException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an RSA private key from a given PEM formatted key text.
|
||||
* <p>
|
||||
* This method extracts the raw key content from the provided PEM text, decodes the
|
||||
* Base64-encoded content, and generates an instance of {@link RSAPrivateKey}. If the key cannot
|
||||
* be loaded due to invalid specifications or types, a {@link KeyLoadingException} is thrown.
|
||||
*
|
||||
* @param pemKeyText the PEM formatted private key text
|
||||
* @return an instance of {@link RSAPrivateKey}
|
||||
* @throws KeyLoadingException if the key loading process encounters an error
|
||||
*/
|
||||
@Override
|
||||
public RSAPrivateKey loadPrivateKey(String pemKeyText) {
|
||||
// Extract the raw key content
|
||||
var rawKeyContent = CryptoUtil.getRawContent(pemKeyText);
|
||||
|
||||
// Decode the Base64-encoded content
|
||||
var keyBytes = decoder.decode(rawKeyContent);
|
||||
|
||||
// Create a PKCS8EncodedKeySpec from the decoded bytes
|
||||
var keySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
|
||||
try {
|
||||
// Get an RSA KeyFactory and generate the private key
|
||||
var _key = keyFactory.generatePrivate(keySpec);
|
||||
if (_key instanceof RSAPrivateKey key) {
|
||||
return key;
|
||||
} else {
|
||||
throw new KeyLoadingException("Unable to load private key from pem-formatted key text.");
|
||||
}
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new KeyLoadingException("Key spec is invalid.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.crypto.algorithm.rsa;
|
||||
|
||||
import com.onixbyte.crypto.PublicKeyLoader;
|
||||
import com.onixbyte.crypto.exception.KeyLoadingException;
|
||||
import com.onixbyte.crypto.util.CryptoUtil;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
public class RSAPublicKeyLoader implements PublicKeyLoader {
|
||||
|
||||
private final Base64.Decoder decoder;
|
||||
|
||||
private final Base64.Decoder urlDecoder;
|
||||
|
||||
private final KeyFactory keyFactory;
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@code RsaKeyLoader}.
|
||||
* <p>
|
||||
* This constructor initialises the Base64 decoder and the RSA {@link KeyFactory}. It may throw
|
||||
* a {@link KeyLoadingException} if the RSA algorithm is not available.
|
||||
*/
|
||||
public RSAPublicKeyLoader() {
|
||||
try {
|
||||
this.decoder = Base64.getDecoder();
|
||||
this.urlDecoder = Base64.getUrlDecoder();
|
||||
this.keyFactory = KeyFactory.getInstance("RSA");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new KeyLoadingException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an RSA public key from a given PEM formatted key text.
|
||||
* <p>
|
||||
* This method extracts the raw key content from the provided PEM text, decodes the
|
||||
* Base64-encoded content, and generates an instance of {@link RSAPublicKey}. If the key cannot
|
||||
* be loaded due to invalid specifications or types, a {@link KeyLoadingException} is thrown.
|
||||
*
|
||||
* @param pemKeyText the PEM formatted public key text
|
||||
* @return an instance of {@link RSAPublicKey}
|
||||
* @throws KeyLoadingException if the key loading process encounters an error
|
||||
*/
|
||||
@Override
|
||||
public RSAPublicKey loadPublicKey(String pemKeyText) {
|
||||
// Extract the raw key content
|
||||
var rawKeyContent = CryptoUtil.getRawContent(pemKeyText);
|
||||
|
||||
// Decode the Base64-encoded content
|
||||
var keyBytes = decoder.decode(rawKeyContent);
|
||||
|
||||
// Create an X509EncodedKeySpec from the decoded bytes
|
||||
var keySpec = new X509EncodedKeySpec(keyBytes);
|
||||
|
||||
// Get an RSA KeyFactory and generate the public key
|
||||
try {
|
||||
var _key = keyFactory.generatePublic(keySpec);
|
||||
if (_key instanceof RSAPublicKey key) {
|
||||
return key;
|
||||
} else {
|
||||
throw new KeyLoadingException("Unable to load public key from pem-formatted key text.");
|
||||
}
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new KeyLoadingException("Key spec is invalid.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the public key with given modulus and public exponent.
|
||||
*
|
||||
* @param modulus the modulus
|
||||
* @param exponent the public exponent
|
||||
* @return generated public key object from the provided key specification
|
||||
* @see KeyFactory#getInstance(String)
|
||||
* @see KeyFactory#generatePublic(KeySpec)
|
||||
*/
|
||||
@Override
|
||||
public RSAPublicKey loadPublicKey(String modulus, String exponent) {
|
||||
try {
|
||||
var _modulus = new BigInteger(1, urlDecoder.decode(modulus));
|
||||
var _exponent = new BigInteger(1, urlDecoder.decode(exponent));
|
||||
|
||||
var keySpec = new RSAPublicKeySpec(_modulus, _exponent);
|
||||
var kf = KeyFactory.getInstance("RSA");
|
||||
if (kf.generatePublic(keySpec) instanceof RSAPublicKey rsaPublicKey) {
|
||||
return rsaPublicKey;
|
||||
} else {
|
||||
throw new KeyLoadingException("Cannot generate RSA public key with given modulus and exponent.");
|
||||
}
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
throw new KeyLoadingException("Cannot generate RSA public key with given modulus and exponent.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.crypto.exception;
|
||||
|
||||
/**
|
||||
* The {@code KeyLoadingException} class represents an exception that is thrown when there is an
|
||||
* error loading cryptographic keys. This exception can be used to indicate various issues such as
|
||||
* invalid key specifications, unsupported key algorithms, or other key loading errors.
|
||||
* <p>
|
||||
* This class extends {@link RuntimeException}, allowing it to be thrown without being declared in
|
||||
* a method's {@code throws} clause.
|
||||
* </p>
|
||||
*
|
||||
* <p><b>Example usage:</b></p>
|
||||
* <pre>{@code
|
||||
* try {
|
||||
* PrivateKeyLoader keyLoader = new ECPrivateKeyLoader();
|
||||
* ECPrivateKey privateKey = keyLoader.loadPrivateKey(pemPrivateKey);
|
||||
* } catch (KeyLoadingException e) {
|
||||
* // Handle the exception
|
||||
* e.printStackTrace();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @author zihluwang
|
||||
* @version 3.0.0
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public class KeyLoadingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code KeyLoadingException} without a specific message or cause.
|
||||
*/
|
||||
public KeyLoadingException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code KeyLoadingException} with the specified detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public KeyLoadingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code KeyLoadingException} with the specified detail message
|
||||
* and cause.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause of this exception
|
||||
*/
|
||||
public KeyLoadingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code KeyLoadingException} with the specified cause.
|
||||
*
|
||||
* @param cause the cause of this exception
|
||||
*/
|
||||
public KeyLoadingException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message, cause, suppression enabled
|
||||
* or disabled, and writable stack trace enabled or disabled.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause of this exception
|
||||
* @param enableSuppression whether suppression is enabled or disabled
|
||||
* @param writableStackTrace whether the stack trace should be writable
|
||||
*/
|
||||
public KeyLoadingException(String message,
|
||||
Throwable cause,
|
||||
boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2024-2025 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.crypto.util;
|
||||
|
||||
public final class CryptoUtil {
|
||||
|
||||
private CryptoUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the raw content of a PEM formatted key by removing unnecessary headers, footers,
|
||||
* and new line characters.
|
||||
*
|
||||
* <p>
|
||||
* This method processes the provided PEM key text to return a cleaned string that contains
|
||||
* only the key content. The method strips away the
|
||||
* {@code "-----BEGIN (EC )?(PRIVATE|PUBLIC) KEY-----"} and
|
||||
* {@code "-----END (EC )?(PRIVATE|PUBLIC) KEY-----"} lines, as well as any new line characters,
|
||||
* resulting in a continuous string representation of the key, which can be used for further
|
||||
* cryptographic operations.
|
||||
*
|
||||
* @param pemKeyText the PEM formatted key as a string, which may include headers, footers and
|
||||
* line breaks
|
||||
* @return a string containing the raw key content devoid of any unnecessary formatting
|
||||
* or whitespace
|
||||
*/
|
||||
public static String getRawContent(String pemKeyText) {
|
||||
// remove all unnecessary parts of the pem key text
|
||||
return pemKeyText
|
||||
.replaceAll("-----BEGIN ((EC )|(RSA ))?(PRIVATE|PUBLIC) KEY-----", "")
|
||||
.replaceAll("-----END ((EC )|(RSA ))?(PRIVATE|PUBLIC) KEY-----", "")
|
||||
.replaceAll("\n", "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
<property name="COLOURFUL_OUTPUT" value="%black(%date{'dd MMM, yyyy HH:mm:ss', Asia/Hong_Kong, en-UK}) %highlight(%-5level) %black(---) %black([%10.10t]) %cyan(%-20.20logger{20}) %black(:) %msg%n"/>
|
||||
<property name="STANDARD_OUTPUT" value="%date{'dd MMM, yyyy HH:mm:ss', Asia/Hong_Kong, en-UK} %-5level %black(---) [%10.10t] %-20.20logger{20} : %msg%n"/>
|
||||
|
||||
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${COLOURFUL_OUTPUT}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs79JlARgXEf6EDV7
|
||||
+PHQCTHEMtqIoHOy1GZ1+ynQJ6yhRANCAARkA7GRY2i4gg8qx0XViAXUP9cPw9pn
|
||||
Jg1wfrQ41FaMyqVBejNYxvaLtamErF/ySimnjafMJ+VZCh34lBj6Ez8R
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -0,0 +1,4 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZAOxkWNouIIPKsdF1YgF1D/XD8Pa
|
||||
ZyYNcH60ONRWjMqlQXozWMb2i7WphKxf8kopp42nzCflWQod+JQY+hM/EQ==
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD4VIFYJFMAs15j
|
||||
J3V3IicHd7sI2TIFqTZME40zlOlVAlPKLZmTQvZFLNgaUAAsvPi5i1DR2ywwK6Al
|
||||
BfnwVnzvmDXC5mKHOz4oxOQVA6Nlp2yVaQMzidmfYNSkMtcv/4HRPsatc7K/M5l6
|
||||
pCP20DVRjkikBdIy8e9w+x6BrIFp5Q8PZc/X2BGNAUMMYACdeYH5R/A0CxqkND13
|
||||
esc4gkynMOrvZrZGHCz51usfSCqyDWWwsN+GG6LYWia4GkNlS0erQnP8gS93dfjl
|
||||
e96BIfy3z7Iv+kUrf5ikNW2P8jMxLAv6LO+dcUAu9k477wIAF7Iq5KMuH/otsDOu
|
||||
+h+2qXmBAgMBAAECggEAdRqcmC0g+y6arxV3fkObthjPGYAa57KBCWUa7B0n30+m
|
||||
pavVRS2Jpttb2SSqwG4ouI6rARti/iBEd9EWqTCP4AieKZetFOpqCJ24lPRPRGus
|
||||
d9S6jr5N4qut+vSCp37NABijZj4uJ540nTH0R7qtuhTnynl4Q0/1wwiYvTvVF1Lg
|
||||
dn+I/8aRbshwDhdAOWOUe6GL7/eaCYgN8/UmlKIpp8tg0w2iWxbaFiR7gZiM41LA
|
||||
M6SXXfcCas+ZVXsGbzQ3SNiVurCGuuRNcCScXS3/WoEDIb3cNtp49iOmQS+nmEoo
|
||||
wh4uiEd+0+BrzxngS4o5+mKnHJnwgY0+veGVYLMR5QKBgQD9WKQmevMDU5c+NPq9
|
||||
8jaR457Fuxq1gwzeFNJdWfOc/K2LEWh+nFNFCb++EboEj6FdxWaWNMxbrmJps5gs
|
||||
EoBUYy/Tl7UycDqDfiYLmDdTsf2pVjjh9jaIADiLcJ8S6wwJMZKub7Tp8UVkenAl
|
||||
535MqShLUC11Y7VxLb3Tsll4XwKBgQD67mm6iCmshr/eszPfNE3ylZ+PiNa7nat7
|
||||
N7lQzBIiRJflT1kmVidC5gE+jASqH728ChkZZKxbHsjxpmWdAhLOITdXoTB4sDsd
|
||||
wtV1lxkXxK9FnrpFvO3y1wZ/QsD3Z2KXxHYZqawkUETO9F3nqAXW0b2GDar5Qiyo
|
||||
J3Tx/43aHwKBgDC0NMJtCoDONhowZy/S+6iqQKC0qprQec3L5PErVMkOTnKYwyTr
|
||||
+pogGKt6ju9HiXcUdvdTaSIK8UJu00dNuzv94XjlBmGO78DNpJTAC4rcge5m9AKE
|
||||
qdEVcclkukARzbuKuy8rrHT4/CUn4J141m/4aRWpcUPLCluato6XD9ozAoGBANvf
|
||||
JhOFFgcPd3YazfvpZ9eE1XA+tfFlYYmxNRcgCU+vjO0oDvSxjutmgHae18N91pG6
|
||||
w21lskSRf/+GDwl5dKLbphOJsOA/gz07qDDGOf2CoRW+1Hcg6drcINxH0K+4DkLv
|
||||
qZApBSY4k2JH6zR+HMeztn6M4WBRZLHfCPC3PUN/AoGAA3AoHbLTZvqMIKSDkP4Y
|
||||
U/tTsSFDY4aYo7LG/jk8af3oPU3KyGh4ZFBd6aMmXbS8f8FjvmrM+/e+y9OOGAlq
|
||||
iOl0hYrs5cJSMLW6i4KnJYuYbMkgmk3bN2t9apu64xKR94gbPrI6AGnPZp+iIzp0
|
||||
hXKe4HcuhQ3G0a2hjayiQ84=
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+FSBWCRTALNeYyd1dyIn
|
||||
B3e7CNkyBak2TBONM5TpVQJTyi2Zk0L2RSzYGlAALLz4uYtQ0dssMCugJQX58FZ8
|
||||
75g1wuZihzs+KMTkFQOjZadslWkDM4nZn2DUpDLXL/+B0T7GrXOyvzOZeqQj9tA1
|
||||
UY5IpAXSMvHvcPsegayBaeUPD2XP19gRjQFDDGAAnXmB+UfwNAsapDQ9d3rHOIJM
|
||||
pzDq72a2Rhws+dbrH0gqsg1lsLDfhhui2FomuBpDZUtHq0Jz/IEvd3X45XvegSH8
|
||||
t8+yL/pFK3+YpDVtj/IzMSwL+izvnXFALvZOO+8CABeyKuSjLh/6LbAzrvoftql5
|
||||
gQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
Reference in New Issue
Block a user