Skip to content

Commit bc24d69

Browse files
committed
Load encrypted private keys + tests
(cherry picked from commit a2c7ae2)
1 parent 99710f8 commit bc24d69

File tree

5 files changed

+84
-8
lines changed

5 files changed

+84
-8
lines changed

gamutils/src/main/java/com/genexus/gam/utils/keys/PrivateKeyUtil.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,22 @@
66
import org.bouncycastle.asn1.ASN1InputStream;
77
import org.bouncycastle.asn1.ASN1Sequence;
88
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
9+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
910
import org.bouncycastle.openssl.PEMKeyPair;
1011
import org.bouncycastle.openssl.PEMParser;
12+
import org.bouncycastle.operator.InputDecryptorProvider;
13+
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
14+
import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder;
1115
import org.bouncycastle.util.encoders.Base64;
1216

17+
import javax.crypto.EncryptedPrivateKeyInfo;
1318
import java.io.FileReader;
1419
import java.io.InputStream;
1520
import java.nio.file.Files;
1621
import java.nio.file.Paths;
1722
import java.security.KeyFactory;
1823
import java.security.KeyStore;
24+
import java.security.Security;
1925
import java.security.interfaces.RSAPrivateKey;
2026
import java.security.spec.PKCS8EncodedKeySpec;
2127

@@ -49,7 +55,7 @@ public static PrivateKeyUtil value(String ext) {
4955

5056
public static RSAPrivateKey getPrivateKey(String path, String alias, String password) {
5157
String extension = FilenameUtils.getExtension(path);
52-
PrivateKeyUtil ext = extension.isEmpty() ? PrivateKeyUtil.value("b64"): PrivateKeyUtil.value(extension);
58+
PrivateKeyUtil ext = extension.isEmpty() ? PrivateKeyUtil.value("b64") : PrivateKeyUtil.value(extension);
5359
switch (ext) {
5460
case pfx:
5561
case jks:
@@ -58,7 +64,7 @@ public static RSAPrivateKey getPrivateKey(String path, String alias, String pass
5864
return loadFromPkcs12(path, alias, password);
5965
case pem:
6066
case key:
61-
return loadFromPkcs8(path);
67+
return loadFromPkcs8(path, password);
6268
case b64:
6369
return loadFromBase64(path);
6470
default:
@@ -67,20 +73,18 @@ public static RSAPrivateKey getPrivateKey(String path, String alias, String pass
6773
}
6874
}
6975

70-
private static RSAPrivateKey loadFromBase64(String base64)
71-
{
76+
private static RSAPrivateKey loadFromBase64(String base64) {
7277
logger.debug("loadFromBase64");
73-
try(ASN1InputStream stream = new ASN1InputStream(Base64.decode(base64))) {
78+
try (ASN1InputStream stream = new ASN1InputStream(Base64.decode(base64))) {
7479
ASN1Sequence seq = (ASN1Sequence) stream.readObject();
7580
return castPrivateKeyInfo(PrivateKeyInfo.getInstance(seq));
76-
}catch (Exception e)
77-
{
81+
} catch (Exception e) {
7882
logger.error("loadFromBase64", e);
7983
return null;
8084
}
8185
}
8286

83-
private static RSAPrivateKey loadFromPkcs8(String path) {
87+
private static RSAPrivateKey loadFromPkcs8(String path, String password) {
8488
logger.debug("loadFromPkcs8");
8589
try (FileReader privateKeyReader = new FileReader(path)) {
8690
try (PEMParser parser = new PEMParser(privateKeyReader)) {
@@ -91,6 +95,13 @@ private static RSAPrivateKey loadFromPkcs8(String path) {
9195
} else if (obj instanceof PEMKeyPair) {
9296
PEMKeyPair pemKeyPair = (PEMKeyPair) obj;
9397
return castPrivateKeyInfo(pemKeyPair.getPrivateKeyInfo());
98+
} else if (obj instanceof EncryptedPrivateKeyInfo || obj instanceof PKCS8EncryptedPrivateKeyInfo) {
99+
logger.debug("loadFromPkcs8 encrypted private key");
100+
Security.addProvider(new BouncyCastleProvider());
101+
PKCS8EncryptedPrivateKeyInfo encPrivKeyInfo = (PKCS8EncryptedPrivateKeyInfo) obj;
102+
InputDecryptorProvider pkcs8Prov = new JcePKCSPBEInputDecryptorProviderBuilder().setProvider("BC")
103+
.build(password.toCharArray());
104+
return castPrivateKeyInfo(encPrivKeyInfo.decryptPrivateKeyInfo(pkcs8Prov));
94105
} else {
95106
logger.error("loadFromPkcs8: Could not load private key");
96107
return null;

gamutils/src/test/java/com/genexus/gam/utils/test/JwtTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ public void testCreatePkcs8()
108108
Assert.assertFalse("testCreatePkcs8", token.isEmpty());
109109
}
110110

111+
@Test
112+
public void testCreateEncryptedPkcs8()
113+
{
114+
String token = GamUtilsEO.createJWTWithFile(path_RSA_sha256_2048 + "sha256_key.pem", "", password, payload, header);
115+
Assert.assertFalse("testCreateEncryptedPkcs8", token.isEmpty());
116+
}
117+
111118
@Test
112119
public void testVerifyDer() {
113120
boolean result = GamUtilsEO.verifyJWTWithFile(path_RSA_sha256_2048 + "sha256_cert.cer", "", "", tokenFile);

gamutils/src/test/java/com/genexus/gam/utils/test/PrivateKeyTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,11 @@ public void testLoadBase64() {
7171
RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(base64, "", "");
7272
Assert.assertNotNull("testLoadBase64", key);
7373
}
74+
75+
@Test
76+
public void testLoadEncryptedPkcs8()
77+
{
78+
RSAPrivateKey key = PrivateKeyUtil.getPrivateKey(path_RSA_sha256_2048 + "sha256_key.pem", "", password);
79+
Assert.assertNotNull("testLoadEncryptedPkcs8", key);
80+
}
7481
}

gamutils/src/test/java/com/genexus/gam/utils/test/RandomTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.genexus.gam.utils.test;
22

33
import com.genexus.gam.GamUtilsEO;
4+
import org.bouncycastle.util.encoders.Hex;
45
import org.junit.Assert;
56
import org.junit.BeforeClass;
67
import org.junit.Test;
@@ -52,4 +53,24 @@ public void testRandomAlphanumeric() {
5253
String l256_string = GamUtilsEO.randomAlphanumeric(l256);
5354
Assert.assertEquals("l256 alphanumeric: ", l256, l256_string.length());
5455
}
56+
57+
@Test
58+
public void testHexaBits() {
59+
int[] lengths = new int[]{32, 64, 128, 256, 512, 1024};
60+
for (int n : lengths) {
61+
String hexa = GamUtilsEO.randomHexaBits(n);
62+
Assert.assertFalse("TestHexaBits", hexa.isEmpty());
63+
try
64+
{
65+
byte[] decoded = Hex.decode(hexa);
66+
if(decoded.length*8 != n)
67+
{
68+
Assert.fail("testHexaBits wrong hexa length");
69+
}
70+
}catch(Exception e)
71+
{
72+
Assert.fail("testHexaBits not hexa characters" + e.getMessage());
73+
}
74+
}
75+
}
5576
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-----BEGIN ENCRYPTED PRIVATE KEY-----
2+
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI5Xxbb/ckzykCAggA
3+
MBQGCCqGSIb3DQMHBAiLR0U2DKvbeQSCBMg5y4x5chPFsx7N081HcFhNVV2xwvIx
4+
vbRcBeBUhiVaJUuJfRSXzwm16oqV7bZj91IkbePXGwkhHPeBoyy0yrNgsfFJ+t05
5+
lQU7vKxSFCiTdijGVbp2nxntOb1yRPkc2pA0iSSED00QNHpjDgcpywAKPDmRJSyM
6+
mWDmrYzQYLTzyFgmcec53B27DXfHoGHBGwq1lfdKGzlphJPDxd+w+2VuAl33Zuq4
7+
oriu69l4CHcg64vJAa/Y9BkW3HiAytKaEBHHAuE8W2mHYfW4DwZlBur+lo+aUiNV
8+
4RFOH1xdej/k4feMXsOnYak93gZIbWyr/8MljbQJLNlE+NkheNzAyTT2a9P04JOv
9+
GUqv45EO9PIdDBemJxCiK4wmeoS/KhJ/zyictOsc1W659lzdCpCIecu0t/1La5b2
10+
/MWIkdDmqvE4CSNEmGNykLejKKjvGwk9hTsnpckoo44eNjSiElcItd6d0nZr8o9Q
11+
h8kK8GF0bRjYYqiXoCO5WCO6h6IcJEVmx58/Y07yQ504Djih5eU5TrbPfVcUNcYy
12+
fWbcai0/X6SSEJXOuvHtx6s+7Y8f3Uo9mh3UI2we4C7zPABvlGTDMRliamcUc4AD
13+
8BCahJZuOTN1mkYae+G1IpFW3E12z7+C9bQ6tuundntPuc+GJvEw/Clss6dZ5b3w
14+
+Gf+5Kc9PlPu/UxGTUFntN5AB2GGheERtw6UFG+Wf34aHg8uYPXnOYXK1ssnhXlI
15+
TxbKSUBiirR/LwoXVapepQdLXfVxirW/QVB42dcH0mjtkgSy5k7teaKZV3eZQhid
16+
Ja9tGq6cMEngzd7BNWA+zzrjn/Jj5DbnnQhYuBr+w82qfiVqc6VYxTCcs2KJK1lU
17+
LuwXfygNcksvw+7w0tLqUWNsY1M1ZtmnSWiAW76G6ARugmTevYa0WXLAo/N74c96
18+
ORW0n8ZSQa7zhROJgefbXsuG4brTRnQMAJc+SzH09BRU8m3xeo8bygUGrN/aDyQy
19+
DZ37pcWwFXlLRRshYoRqCW7v8TDVnCMSM9aujGnlSyK/l/88BCJuiLziHWPiJgvk
20+
1x68JoEN/fxLh7O3qTYpUiyfVN8LHB6tqqJe97p12BAzo1HX5WSoq2a/oYl4Hqa2
21+
VfCwiI11NrUpv1EIKfa2yspRk4JVz38dT+KbxB5mz0MgEL8aq/9cJ4ISersTK2UU
22+
ZJQPgPvJzbnXU4Vh0ON4P7f724eZvTxzGiiJZAIWrqiR7TyEd4J65r3FbBU1xpLU
23+
tTgrvv38EkA9+qoAG9CjukGTn1k0T8jNC3vxkn4f2nIMn1n9YbvsiVsjzq1UKzRt
24+
nxHHzMOfKnt092HsO8dtXwZadrpYcoZk9qVx9xbA1RO9rv9CSqLszWThUOT6xXmG
25+
3F2ff9jXJjHtAog70TCrU2/bXZmZCmuHG78aLtSUSyNSgCc+Lp9CBQmc0QHrqjCS
26+
7qwHXhdriOElj0fDwuFOk9pXUfc4t4YDWQGxY7+YWnS7RXCye9YI90U/8TyhLBOs
27+
JZY2DDlOskC0NoIkqHfb2jyHMtW1BzmQIQ0tfKTxTzyg/dOZKJuIWhvpi9LTHDCI
28+
+Er7OrZ0vf91c5FraxPaXatdw4laiNMak9fgWNsp44jIxYHi0zVQLkjQKDuKVoZo
29+
Vzk=
30+
-----END ENCRYPTED PRIVATE KEY-----

0 commit comments

Comments
 (0)