Skip to content

Commit c482eb7

Browse files
committed
New features, tests and some needed refactoring
(cherry picked from commit 9cb8c02)
1 parent bdc5e22 commit c482eb7

File tree

15 files changed

+418
-19
lines changed

15 files changed

+418
-19
lines changed

gamutils/src/main/java/com/genexus/gam/GamUtilsEO.java

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

3-
import com.genexus.gam.utils.*;
3+
import com.genexus.gam.utils.Random;
4+
import com.genexus.gam.utils.cryptography.Encryption;
5+
import com.genexus.gam.utils.cryptography.Hash;
6+
import com.genexus.gam.utils.json.Jwk;
7+
import com.genexus.gam.utils.json.Jwks;
8+
import com.genexus.gam.utils.json.Jwt;
49

510
public class GamUtilsEO {
611

@@ -11,15 +16,24 @@ public static String sha512(String plainText) {
1116
return Hash.sha512(plainText);
1217
}
1318

19+
//**ENCRYPTION**//
20+
21+
public static String AesGcm(String input, String key, String nonce, int macSize, boolean toEncrypt) {
22+
return Encryption.AesGcm(input, key, nonce, macSize, toEncrypt);
23+
}
24+
1425
//**RANDOM**//
1526
public static String randomAlphanumeric(int length) {
16-
return Random.randomAlphanumeric(length);
27+
return Random.alphanumeric(length);
1728
}
1829

1930
public static String randomNumeric(int length) {
20-
return Random.randomNumeric(length);
31+
return Random.numeric(length);
2132
}
2233

34+
public static String randomHexaBits(int bits) {
35+
return Random.hexaBits(bits);
36+
}
2337

2438
//**JWK**//
2539

@@ -50,5 +64,9 @@ public static boolean verifyJWTWithFile(String path, String alias, String passwo
5064
return Jwt.verify(path, alias, password, token);
5165
}
5266

67+
public static String createJWTWithFile(String path, String alias, String password, String payload, String header) {
68+
return Jwt.create(path, alias, password, payload, header);
69+
}
70+
5371
/********EXTERNAL OBJECT PUBLIC METHODS - END ********/
5472
}

gamutils/src/main/java/com/genexus/gam/utils/Random.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ private static SecureRandom instanceRandom() {
1818
}
1919
}
2020

21-
public static String randomAlphanumeric(int length) {
21+
public static String alphanumeric(int length) {
2222
SecureRandom random = instanceRandom();
2323
if (random == null) {
2424
logger.error("randomAlphanumeric SecureRandom is null");
@@ -31,7 +31,7 @@ public static String randomAlphanumeric(int length) {
3131
return sb.toString();
3232
}
3333

34-
public static String randomNumeric(int length) {
34+
public static String numeric(int length) {
3535
SecureRandom random = instanceRandom();
3636
if (random == null) {
3737
logger.error("randomNumeric SecureRandom is null");
@@ -43,4 +43,20 @@ public static String randomNumeric(int length) {
4343
}
4444
return sb.toString();
4545
}
46+
47+
public static String hexaBits(int bits)
48+
{
49+
SecureRandom random = instanceRandom();
50+
if (random == null) {
51+
logger.error("randomNumeric SecureRandom is null");
52+
return "";
53+
}
54+
byte[] values = new byte[bits / 8];
55+
random.nextBytes(values);
56+
StringBuilder sb = new StringBuilder();
57+
for (byte b : values) {
58+
sb.append(String.format("%02x", b));
59+
}
60+
return sb.toString().replaceAll("\\s", "");
61+
}
4662
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.genexus.gam.utils.cryptography;
2+
3+
import org.apache.logging.log4j.LogManager;
4+
import org.apache.logging.log4j.Logger;
5+
import org.bouncycastle.crypto.engines.AESEngine;
6+
import org.bouncycastle.crypto.modes.AEADBlockCipher;
7+
import org.bouncycastle.crypto.modes.GCMBlockCipher;
8+
import org.bouncycastle.crypto.params.AEADParameters;
9+
import org.bouncycastle.crypto.params.KeyParameter;
10+
import org.bouncycastle.util.encoders.Base64;
11+
import org.bouncycastle.util.encoders.Hex;
12+
13+
import java.nio.charset.StandardCharsets;
14+
15+
public class Encryption {
16+
17+
private static Logger logger = LogManager.getLogger(Encryption.class);
18+
19+
public static String AesGcm(String input, String key, String nonce, int macSize, boolean toEncrypt) {
20+
return toEncrypt ? Base64.toBase64String(internal_AesGcm(input.getBytes(StandardCharsets.UTF_8), key, nonce, macSize, toEncrypt)) : new String(internal_AesGcm(Base64.decode(input), key, nonce, macSize, toEncrypt), StandardCharsets.UTF_8);
21+
}
22+
23+
public static byte[] internal_AesGcm(byte[] inputBytes, String key, String nonce, int macSize, boolean toEncrypt) {
24+
logger.debug("internal_AesGcm");
25+
AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
26+
AEADParameters AEADparams = new AEADParameters(new KeyParameter(Hex.decode(key)), macSize, Hex.decode(nonce));
27+
try {
28+
cipher.init(toEncrypt, AEADparams);
29+
byte[] outputBytes = new byte[cipher.getOutputSize(inputBytes.length)];
30+
int length = cipher.processBytes(inputBytes, 0, inputBytes.length, outputBytes, 0);
31+
cipher.doFinal(outputBytes, length);
32+
return outputBytes;
33+
} catch (Exception e) {
34+
logger.error("Aes_gcm", e);
35+
return null;
36+
}
37+
}
38+
}

gamutils/src/main/java/com/genexus/gam/utils/Hash.java renamed to gamutils/src/main/java/com/genexus/gam/utils/cryptography/Hash.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.genexus.gam.utils;
1+
package com.genexus.gam.utils.cryptography;
22

33
import org.apache.logging.log4j.Logger;
44
import org.apache.logging.log4j.LogManager;

gamutils/src/main/java/com/genexus/gam/utils/Jwk.java renamed to gamutils/src/main/java/com/genexus/gam/utils/json/Jwk.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.genexus.gam.utils;
1+
package com.genexus.gam.utils.json;
22

33
import com.nimbusds.jose.Algorithm;
44
import com.nimbusds.jose.jwk.JWK;

gamutils/src/main/java/com/genexus/gam/utils/Jwks.java renamed to gamutils/src/main/java/com/genexus/gam/utils/json/Jwks.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.genexus.gam.utils;
1+
package com.genexus.gam.utils.json;
22

33
import com.nimbusds.jose.jwk.JWK;
44
import com.nimbusds.jose.jwk.JWKSet;

gamutils/src/main/java/com/genexus/gam/utils/Jwt.java renamed to gamutils/src/main/java/com/genexus/gam/utils/json/Jwt.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
package com.genexus.gam.utils;
1+
package com.genexus.gam.utils.json;
22

3+
import com.genexus.gam.utils.keys.CertificateUtil;
4+
import com.genexus.gam.utils.keys.PrivateKeyUtil;
35
import com.nimbusds.jose.JWSHeader;
46
import com.nimbusds.jose.JWSVerifier;
57
import com.nimbusds.jose.crypto.RSASSASigner;
@@ -44,6 +46,11 @@ public static boolean verify(String path, String alias, String password, String
4446
return verify((RSAPublicKey) CertificateUtil.getCertificate(path, alias, password).getPublicKey(), token);
4547
}
4648

49+
public static String create(String path, String alias, String password, String payload, String header)
50+
{
51+
return create(PrivateKeyUtil.getPrivateKey(path, alias, password), payload, header);
52+
}
53+
4754
/******** EXTERNAL OBJECT PUBLIC METHODS - END ********/
4855

4956

gamutils/src/main/java/com/genexus/gam/utils/CertificateUtil.java renamed to gamutils/src/main/java/com/genexus/gam/utils/keys/CertificateUtil.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
package com.genexus.gam.utils;
1+
package com.genexus.gam.utils.keys;
22

33
import org.apache.logging.log4j.Logger;
44
import org.apache.logging.log4j.LogManager;
55
import org.apache.commons.io.FilenameUtils;
66
import org.bouncycastle.cert.X509CertificateHolder;
77
import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
88
import org.bouncycastle.openssl.PEMParser;
9+
import org.bouncycastle.util.encoders.Base64;
910

1011
import java.io.*;
1112
import java.security.KeyStore;
1213
import java.security.cert.X509Certificate;
1314

1415
public enum CertificateUtil {
1516

16-
crt, cer, pfx, jks, pkcs12, p12, pem, key;
17+
crt, cer, pfx, jks, pkcs12, p12, pem, key, b64;
1718

1819
private static Logger logger = LogManager.getLogger(CertificateUtil.class);
1920

@@ -35,18 +36,17 @@ public static CertificateUtil value(String ext) {
3536
return pem;
3637
case "key":
3738
return key;
39+
case "b64":
40+
return b64;
3841
default:
3942
logger.error("Invalid certificate file extension");
4043
return null;
4144
}
4245
}
4346

4447
public static X509Certificate getCertificate(String path, String alias, String password) {
45-
CertificateUtil ext = CertificateUtil.value(FilenameUtils.getExtension(path));
46-
if (ext == null) {
47-
logger.error("Error reading certificate path");
48-
return null;
49-
}
48+
String extension = FilenameUtils.getExtension(path);
49+
CertificateUtil ext = extension.isEmpty() ? CertificateUtil.value("b64"): CertificateUtil.value(extension);
5050
switch (ext) {
5151
case crt:
5252
case cer:
@@ -59,12 +59,27 @@ public static X509Certificate getCertificate(String path, String alias, String p
5959
case pem:
6060
case key:
6161
return loadFromPkcs8(path);
62+
case b64:
63+
return loadBase64(path);
6264
default:
6365
logger.error("Invalid certificate file extension");
6466
return null;
6567
}
6668
}
6769

70+
private static X509Certificate loadBase64(String base64)
71+
{
72+
logger.debug("loadBase64");
73+
try {
74+
ByteArrayInputStream byteArray = new ByteArrayInputStream(Base64.decode(base64));
75+
CertificateFactory factory = new CertificateFactory();
76+
return (X509Certificate) factory.engineGenerateCertificate(byteArray);
77+
} catch (Exception e) {
78+
logger.error("loadBase64", e);
79+
return null;
80+
}
81+
}
82+
6883
private static X509Certificate loadFromPkcs8(String path) {
6984
try (FileReader privateKeyReader = new FileReader(new File(path))) {
7085
try (PEMParser parser = new PEMParser(privateKeyReader)) {
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.genexus.gam.utils.keys;
2+
3+
import org.apache.commons.io.FilenameUtils;
4+
import org.apache.logging.log4j.LogManager;
5+
import org.apache.logging.log4j.Logger;
6+
import org.bouncycastle.asn1.ASN1InputStream;
7+
import org.bouncycastle.asn1.ASN1Sequence;
8+
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
9+
import org.bouncycastle.openssl.PEMKeyPair;
10+
import org.bouncycastle.openssl.PEMParser;
11+
import org.bouncycastle.util.encoders.Base64;
12+
13+
import java.io.FileReader;
14+
import java.io.InputStream;
15+
import java.nio.file.Files;
16+
import java.nio.file.Paths;
17+
import java.security.KeyFactory;
18+
import java.security.KeyStore;
19+
import java.security.interfaces.RSAPrivateKey;
20+
import java.security.spec.PKCS8EncodedKeySpec;
21+
22+
public enum PrivateKeyUtil {
23+
24+
pfx, jks, pkcs12, p12, pem, key, b64;
25+
26+
private static Logger logger = LogManager.getLogger(PrivateKeyUtil.class);
27+
28+
public static PrivateKeyUtil value(String ext) {
29+
switch (ext.toLowerCase().trim()) {
30+
case "pfx":
31+
return pfx;
32+
case "jks":
33+
return jks;
34+
case "pkcs12":
35+
return pkcs12;
36+
case "p12":
37+
return p12;
38+
case "pem":
39+
return pem;
40+
case "key":
41+
return key;
42+
case "b64":
43+
return b64;
44+
default:
45+
logger.error("Invalid certificate file extension");
46+
return null;
47+
}
48+
}
49+
50+
public static RSAPrivateKey getPrivateKey(String path, String alias, String password) {
51+
String extension = FilenameUtils.getExtension(path);
52+
PrivateKeyUtil ext = extension.isEmpty() ? PrivateKeyUtil.value("b64"): PrivateKeyUtil.value(extension);
53+
switch (ext) {
54+
case pfx:
55+
case jks:
56+
case pkcs12:
57+
case p12:
58+
return loadFromPkcs12(path, alias, password);
59+
case pem:
60+
case key:
61+
return loadFromPkcs8(path);
62+
case b64:
63+
return loadFromBase64(path);
64+
default:
65+
logger.error("Invalid private key file extension");
66+
return null;
67+
}
68+
}
69+
70+
private static RSAPrivateKey loadFromBase64(String base64)
71+
{
72+
logger.debug("loadFromBase64");
73+
try(ASN1InputStream stream = new ASN1InputStream(Base64.decode(base64))) {
74+
ASN1Sequence seq = (ASN1Sequence) stream.readObject();
75+
return castPrivateKeyInfo(PrivateKeyInfo.getInstance(seq));
76+
}catch (Exception e)
77+
{
78+
logger.error("loadFromBase64", e);
79+
return null;
80+
}
81+
}
82+
83+
private static RSAPrivateKey loadFromPkcs8(String path) {
84+
logger.debug("loadFromPkcs8");
85+
try (FileReader privateKeyReader = new FileReader(path)) {
86+
try (PEMParser parser = new PEMParser(privateKeyReader)) {
87+
Object obj;
88+
obj = parser.readObject();
89+
if (obj instanceof PrivateKeyInfo) {
90+
return castPrivateKeyInfo((PrivateKeyInfo) obj);
91+
} else if (obj instanceof PEMKeyPair) {
92+
PEMKeyPair pemKeyPair = (PEMKeyPair) obj;
93+
return castPrivateKeyInfo(pemKeyPair.getPrivateKeyInfo());
94+
} else {
95+
logger.error("loadFromPkcs8: Could not load private key");
96+
return null;
97+
}
98+
}
99+
} catch (Exception e) {
100+
logger.error("loadFromPkcs8", e);
101+
return null;
102+
}
103+
}
104+
105+
private static RSAPrivateKey castPrivateKeyInfo(PrivateKeyInfo privateKeyInfo) {
106+
logger.debug("castPrivateKeyInfo");
107+
try {
108+
KeyFactory kf = KeyFactory.getInstance(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().getId());
109+
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded());
110+
return (RSAPrivateKey) kf.generatePrivate(keySpec);
111+
} catch (Exception e) {
112+
logger.error("castPrivateKeyInfo", e);
113+
return null;
114+
}
115+
}
116+
117+
private static RSAPrivateKey loadFromPkcs12(String path, String alias, String password) {
118+
logger.debug("loadFromPkcs12");
119+
try (InputStream targetStream = Files.newInputStream(Paths.get(path))) {
120+
KeyStore ks = KeyStore.getInstance("PKCS12");
121+
ks.load(targetStream, password.toCharArray());
122+
if (alias.isEmpty()) {
123+
return (RSAPrivateKey) ks.getKey(ks.aliases().nextElement(), password.toCharArray());
124+
} else {
125+
return (RSAPrivateKey) ks.getKey(alias, password.toCharArray());
126+
}
127+
} catch (Exception e) {
128+
logger.error("loadFromPkcs12", e);
129+
return null;
130+
}
131+
}
132+
}

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

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

3-
import com.genexus.gam.utils.CertificateUtil;
3+
import com.genexus.gam.utils.keys.CertificateUtil;
44
import org.junit.Assert;
55
import org.junit.BeforeClass;
66
import org.junit.Test;
@@ -76,4 +76,12 @@ public void testLoadKey() {
7676
X509Certificate cert = CertificateUtil.getCertificate(path_RSA_sha256_2048 + "sha256_cert.key", "", "");
7777
Assert.assertNotNull("testLoadKey", cert);
7878
}
79+
80+
@Test
81+
public void testLoadBase64()
82+
{
83+
String base64 = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh";
84+
X509Certificate cert = CertificateUtil.getCertificate(base64, "", "");
85+
Assert.assertNotNull("testLoadBase64", cert);
86+
}
7987
}

0 commit comments

Comments
 (0)