Skip to content

Commit 5343c14

Browse files
authored
Merge pull request #53 from onixbyte/feature/rsa-key-loader
feat: add functionality to load RSA key pairs from text
2 parents 6fbf624 + 31dd63e commit 5343c14

File tree

37 files changed

+1987
-227
lines changed

37 files changed

+1987
-227
lines changed

devkit-core/build.gradle.kts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,10 @@ dependencies {
5656
val logbackVersion: String by project
5757
val junitVersion: String by project
5858

59-
compileOnly("org.slf4j:slf4j-api:$slf4jVersion")
60-
implementation("ch.qos.logback:logback-classic:$logbackVersion")
59+
compileOnly(libs.slf4j)
60+
implementation(libs.logback)
6161

62-
testCompileOnly("org.slf4j:slf4j-api:$slf4jVersion")
63-
testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
62+
testImplementation(libs.junit)
6463
}
6564

6665
tasks.test {

devkit-utils/build.gradle.kts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,10 @@ tasks.withType<Jar> {
5252
}
5353

5454
dependencies {
55-
val slf4jVersion: String by project
56-
val logbackVersion: String by project
57-
val junitVersion: String by project
58-
59-
compileOnly("org.slf4j:slf4j-api:$slf4jVersion")
60-
implementation("ch.qos.logback:logback-classic:$logbackVersion")
61-
implementation(project(":devkit-core"))
62-
63-
testCompileOnly("org.slf4j:slf4j-api:$slf4jVersion")
64-
testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
55+
compileOnly(libs.slf4j)
56+
implementation(libs.logback)
57+
api(project(":devkit-core"))
58+
testImplementation(libs.junit)
6559
}
6660

6761
tasks.test {

gradle.properties

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,4 @@ artefactVersion=2.1.0
1919
projectUrl=https://onixbyte.com/JDevKit
2020
projectGithubUrl=https://github.com/OnixByte/JDevKit
2121
licenseName=The Apache License, Version 2.0
22-
licenseUrl=https://www.apache.org/licenses/LICENSE-2.0.txt
23-
24-
jacksonVersion=2.18.2
25-
javaJwtVersion=4.4.0
26-
junitVersion=5.11.4
27-
logbackVersion=1.5.16
28-
slf4jVersion=2.0.16
29-
springVersion=6.2.2
30-
springBootVersion=3.4.2
22+
licenseUrl=https://www.apache.org/licenses/LICENSE-2.0.txt

gradle/libs.versions.toml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (C) 2024-2025 OnixByte.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
#
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
[versions]
17+
slf4j = "2.0.17"
18+
logback = "1.5.18"
19+
jackson = "2.18.3"
20+
jwt = "4.5.0"
21+
spring = "6.2.6"
22+
springBoot = "3.4.4"
23+
junit = "5.12.2"
24+
25+
[libraries]
26+
slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
27+
logback = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
28+
jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-core", version.ref = "jackson" }
29+
jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" }
30+
jwt = { group = "com.auth0", name = "java-jwt", version.ref = "jwt"}
31+
spring-boot-autoconfigure = { group = "org.springframework.boot", name = "spring-boot-autoconfigure", version.ref = "springBoot" }
32+
spring-boot-starter-logging = { group = "org.springframework.boot", name = "spring-boot-starter-logging", version.ref = "springBoot" }
33+
spring-boot-configuration-processor = { group = "org.springframework.boot", name = "spring-boot-configuration-processor", version.ref = "springBoot" }
34+
spring-boot-starter-redis = { group = "org.springframework.boot", name = "spring-boot-starter-data-redis", version.ref = "springBoot" }
35+
spring-boot-starter-test = { group = "org.springframework.boot", name = "spring-boot-starter-test", version.ref = "springBoot" }
36+
junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" }

guid/build.gradle.kts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,10 @@ tasks.withType<Jar> {
5252
}
5353

5454
dependencies {
55-
val slf4jVersion: String by project
56-
val logbackVersion: String by project
57-
val junitVersion: String by project
58-
59-
compileOnly("org.slf4j:slf4j-api:$slf4jVersion")
60-
implementation("ch.qos.logback:logback-classic:$logbackVersion")
61-
implementation(project(":devkit-core"))
62-
63-
testCompileOnly("org.slf4j:slf4j-api:$slf4jVersion")
64-
testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
55+
compileOnly(libs.slf4j)
56+
implementation(libs.logback)
57+
api(project(":devkit-core"))
58+
testImplementation(libs.junit)
6559
}
6660

6761
tasks.test {

key-pair-loader/README.md

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,71 @@ ZyYNcH60ONRWjMqlQXozWMb2i7WphKxf8kopp42nzCflWQod+JQY+hM/EQ==
4343
-----END PUBLIC KEY-----
4444
```
4545

46-
#### Convert private key to EC formats which could be acceptable by Java
46+
## RSA-based algorithm
4747

48-
Java's `PKCS8EncodedKeySpec` requires the private key to be in PKCS#8 format, while OpenSSL by
49-
default generates private keys in traditional PEM format. To convert the private key, run the
50-
following command:
48+
### Generate key pair
49+
50+
#### Generate private key
51+
52+
Generate a private key by `genpkey` command provided by OpenSSL:
5153

5254
```shell
53-
openssl pkcs8 -topk8 -inform PEM -outform PEM -in ec_private_key.pem -out ec_private_key_pkcs8.pem -nocrypt
55+
openssl genpkey -algorithm RSA -out rsa_private_key.pem -pkeyopt rsa_keygen_bits:2048
5456
```
5557

56-
The converted private key will look like this:
58+
The output of this command is a file called `rsa_private_key.pem` and its content looks like the
59+
following:
5760

5861
```text
5962
-----BEGIN PRIVATE KEY-----
60-
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgs79JlARgXEf6EDV7
61-
+PHQCTHEMtqIoHOy1GZ1+ynQJ6yhRANCAARkA7GRY2i4gg8qx0XViAXUP9cPw9pn
62-
Jg1wfrQ41FaMyqVBejNYxvaLtamErF/ySimnjafMJ+VZCh34lBj6Ez8R
63+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD4VIFYJFMAs15j
64+
J3V3IicHd7sI2TIFqTZME40zlOlVAlPKLZmTQvZFLNgaUAAsvPi5i1DR2ywwK6Al
65+
BfnwVnzvmDXC5mKHOz4oxOQVA6Nlp2yVaQMzidmfYNSkMtcv/4HRPsatc7K/M5l6
66+
pCP20DVRjkikBdIy8e9w+x6BrIFp5Q8PZc/X2BGNAUMMYACdeYH5R/A0CxqkND13
67+
esc4gkynMOrvZrZGHCz51usfSCqyDWWwsN+GG6LYWia4GkNlS0erQnP8gS93dfjl
68+
e96BIfy3z7Iv+kUrf5ikNW2P8jMxLAv6LO+dcUAu9k477wIAF7Iq5KMuH/otsDOu
69+
+h+2qXmBAgMBAAECggEAdRqcmC0g+y6arxV3fkObthjPGYAa57KBCWUa7B0n30+m
70+
pavVRS2Jpttb2SSqwG4ouI6rARti/iBEd9EWqTCP4AieKZetFOpqCJ24lPRPRGus
71+
d9S6jr5N4qut+vSCp37NABijZj4uJ540nTH0R7qtuhTnynl4Q0/1wwiYvTvVF1Lg
72+
dn+I/8aRbshwDhdAOWOUe6GL7/eaCYgN8/UmlKIpp8tg0w2iWxbaFiR7gZiM41LA
73+
M6SXXfcCas+ZVXsGbzQ3SNiVurCGuuRNcCScXS3/WoEDIb3cNtp49iOmQS+nmEoo
74+
wh4uiEd+0+BrzxngS4o5+mKnHJnwgY0+veGVYLMR5QKBgQD9WKQmevMDU5c+NPq9
75+
8jaR457Fuxq1gwzeFNJdWfOc/K2LEWh+nFNFCb++EboEj6FdxWaWNMxbrmJps5gs
76+
EoBUYy/Tl7UycDqDfiYLmDdTsf2pVjjh9jaIADiLcJ8S6wwJMZKub7Tp8UVkenAl
77+
535MqShLUC11Y7VxLb3Tsll4XwKBgQD67mm6iCmshr/eszPfNE3ylZ+PiNa7nat7
78+
N7lQzBIiRJflT1kmVidC5gE+jASqH728ChkZZKxbHsjxpmWdAhLOITdXoTB4sDsd
79+
wtV1lxkXxK9FnrpFvO3y1wZ/QsD3Z2KXxHYZqawkUETO9F3nqAXW0b2GDar5Qiyo
80+
J3Tx/43aHwKBgDC0NMJtCoDONhowZy/S+6iqQKC0qprQec3L5PErVMkOTnKYwyTr
81+
+pogGKt6ju9HiXcUdvdTaSIK8UJu00dNuzv94XjlBmGO78DNpJTAC4rcge5m9AKE
82+
qdEVcclkukARzbuKuy8rrHT4/CUn4J141m/4aRWpcUPLCluato6XD9ozAoGBANvf
83+
JhOFFgcPd3YazfvpZ9eE1XA+tfFlYYmxNRcgCU+vjO0oDvSxjutmgHae18N91pG6
84+
w21lskSRf/+GDwl5dKLbphOJsOA/gz07qDDGOf2CoRW+1Hcg6drcINxH0K+4DkLv
85+
qZApBSY4k2JH6zR+HMeztn6M4WBRZLHfCPC3PUN/AoGAA3AoHbLTZvqMIKSDkP4Y
86+
U/tTsSFDY4aYo7LG/jk8af3oPU3KyGh4ZFBd6aMmXbS8f8FjvmrM+/e+y9OOGAlq
87+
iOl0hYrs5cJSMLW6i4KnJYuYbMkgmk3bN2t9apu64xKR94gbPrI6AGnPZp+iIzp0
88+
hXKe4HcuhQ3G0a2hjayiQ84=
6389
-----END PRIVATE KEY-----
90+
```
91+
92+
#### Generate public key by private key
93+
94+
Export public key from private key by OpenSSL:
95+
96+
```shell
97+
openssl pkey -in rsa_private_key.pem -pubout -out rsa_public_key.pem
98+
```
99+
100+
The output of this command is a file called `rsa_public_key.pem` and its content looks like the
101+
following:
102+
103+
```text
104+
-----BEGIN PUBLIC KEY-----
105+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+FSBWCRTALNeYyd1dyIn
106+
B3e7CNkyBak2TBONM5TpVQJTyi2Zk0L2RSzYGlAALLz4uYtQ0dssMCugJQX58FZ8
107+
75g1wuZihzs+KMTkFQOjZadslWkDM4nZn2DUpDLXL/+B0T7GrXOyvzOZeqQj9tA1
108+
UY5IpAXSMvHvcPsegayBaeUPD2XP19gRjQFDDGAAnXmB+UfwNAsapDQ9d3rHOIJM
109+
pzDq72a2Rhws+dbrH0gqsg1lsLDfhhui2FomuBpDZUtHq0Jz/IEvd3X45XvegSH8
110+
t8+yL/pFK3+YpDVtj/IzMSwL+izvnXFALvZOO+8CABeyKuSjLh/6LbAzrvoftql5
111+
gQIDAQAB
112+
-----END PUBLIC KEY-----
64113
```

key-pair-loader/build.gradle.kts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2024-2024 OnixByte.
2+
* Copyright (C) 2024-2025 OnixByte.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,16 +52,10 @@ tasks.withType<Jar> {
5252
}
5353

5454
dependencies {
55-
val slf4jVersion: String by project
56-
val logbackVersion: String by project
57-
val junitVersion: String by project
58-
59-
compileOnly("org.slf4j:slf4j-api:$slf4jVersion")
60-
implementation("ch.qos.logback:logback-classic:$logbackVersion")
61-
implementation(project(":devkit-core"))
62-
63-
testCompileOnly("org.slf4j:slf4j-api:$slf4jVersion")
64-
testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
55+
compileOnly(libs.slf4j)
56+
implementation(libs.logback)
57+
api(project(":devkit-core"))
58+
testImplementation(libs.junit)
6559
}
6660

6761
tasks.test {

key-pair-loader/src/main/java/com/onixbyte/security/KeyLoader.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,29 @@ public interface KeyLoader {
4949
*/
5050
PublicKey loadPublicKey(String pemKeyText);
5151

52+
/**
53+
* Retrieves the raw content of a PEM formatted key by removing unnecessary headers, footers,
54+
* and new line characters.
55+
*
56+
* <p>
57+
* This method processes the provided PEM key text to return a cleaned string that contains
58+
* only the key content. The method strips away the
59+
* {@code "-----BEGIN (EC )?(PRIVATE|PUBLIC) KEY-----"} and
60+
* {@code "-----END (EC )?(PRIVATE|PUBLIC) KEY-----"} lines, as well as any new line characters,
61+
* resulting in a continuous string representation of the key, which can be used for further
62+
* cryptographic operations.
63+
*
64+
* @param pemKeyText the PEM formatted key as a string, which may include headers, footers and
65+
* line breaks
66+
* @return a string containing the raw key content devoid of any unnecessary formatting
67+
* or whitespace
68+
*/
69+
default String getRawContent(String pemKeyText) {
70+
// remove all unnecessary parts of the pem key text
71+
return pemKeyText
72+
.replaceAll("-----BEGIN (EC )?(PRIVATE|PUBLIC) KEY-----", "")
73+
.replaceAll("-----END (EC )?(PRIVATE|PUBLIC) KEY-----", "")
74+
.replaceAll("\n", "");
75+
}
76+
5277
}

key-pair-loader/src/main/java/com/onixbyte/security/impl/EcKeyLoader.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,7 @@ public EcKeyLoader() {
8282
@Override
8383
public ECPrivateKey loadPrivateKey(String pemKeyText) {
8484
try {
85-
// remove all unnecessary parts of the pem key text
86-
pemKeyText = pemKeyText
87-
.replaceAll("-----BEGIN (EC )?PRIVATE KEY-----", "")
88-
.replaceAll("-----END (EC )?PRIVATE KEY-----", "")
89-
.replaceAll("\n", "");
85+
pemKeyText = getRawContent(pemKeyText);
9086
var decodedKeyString = decoder.decode(pemKeyText);
9187
var keySpec = new PKCS8EncodedKeySpec(decodedKeyString);
9288

@@ -112,11 +108,7 @@ public ECPrivateKey loadPrivateKey(String pemKeyText) {
112108
@Override
113109
public ECPublicKey loadPublicKey(String pemKeyText) {
114110
try {
115-
// remove all unnecessary parts of the pem key text
116-
pemKeyText = pemKeyText
117-
.replaceAll("-----BEGIN (EC )?PUBLIC KEY-----", "")
118-
.replaceAll("-----END (EC )?PUBLIC KEY-----", "")
119-
.replaceAll("\n", "");
111+
pemKeyText = getRawContent(pemKeyText);
120112
var keyBytes = decoder.decode(pemKeyText);
121113
var spec = new X509EncodedKeySpec(keyBytes);
122114
var key = keyFactory.generatePublic(spec);

0 commit comments

Comments
 (0)