Skip to content

Commit 1d86b12

Browse files
committed
refactor: optimize certificate generation and PEM formatting
Move BouncyCastle provider registration to static initialization to fix redundant allocations and thread contention. Use a secure random 159-bit integer for certificate serial numbers to prevent collisions. Replace the manual wrapping loop with a native MIME encoder configured for strict 64-character lines and LF line endings. Full certificate fingerprint hashing remains intact.
1 parent 59f64b7 commit 1d86b12

1 file changed

Lines changed: 22 additions & 20 deletions

File tree

  • core/src/main/java/pl/skidam/automodpack_core/protocol

core/src/main/java/pl/skidam/automodpack_core/protocol/NetUtils.java

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Calendar;
2323
import java.util.Date;
2424
import java.util.HexFormat;
25+
import java.util.Locale;
2526

2627
public class NetUtils {
2728

@@ -56,13 +57,21 @@ public class NetUtils {
5657
public static final int MIN_CHUNK_SIZE = 8 * 1024; // 8 KB
5758
public static final int MAX_CHUNK_SIZE = 512 * 1024; // 512 KB
5859

60+
private static final Provider BC_PROVIDER = new BouncyCastleProvider();
61+
62+
static {
63+
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
64+
Security.addProvider(BC_PROVIDER);
65+
}
66+
}
67+
5968
public static String getFingerprint(X509Certificate cert) throws CertificateEncodingException {
6069
byte[] certificate = cert.getEncoded();
6170

6271
try {
6372
MessageDigest digest = MessageDigest.getInstance("SHA-256");
6473
byte[] fingerprint = digest.digest(certificate);
65-
return HexFormat.of().formatHex(fingerprint);
74+
return HexFormat.of().formatHex(fingerprint).toLowerCase(Locale.ROOT);
6675
} catch (NoSuchAlgorithmException e) {
6776
throw new RuntimeException(e);
6877
}
@@ -75,31 +84,28 @@ public static KeyPair generateKeyPair() throws Exception {
7584
}
7685

7786
public static X509Certificate selfSign(KeyPair keyPair) throws Exception {
78-
Provider bcProvider = new BouncyCastleProvider();
79-
Security.addProvider(bcProvider);
80-
8187
long now = System.currentTimeMillis();
8288
Date startDate = new Date(now);
8389

8490
X500Name dnName = new X500Name("CN=AutoModpack Self Signed Certificate");
85-
BigInteger certSerialNumber = new BigInteger(Long.toString(now)); // <-- Using the current timestamp as the certificate serial number
91+
BigInteger certSerialNumber = new BigInteger(159, new SecureRandom());
8692

8793
Calendar calendar = Calendar.getInstance();
8894
calendar.setTime(startDate);
89-
calendar.add(Calendar.YEAR, 1); // <-- 1 Yr validity, does not matter, we don't validate it anyway
95+
calendar.add(Calendar.YEAR, 1);
9096
Date endDate = calendar.getTime();
9197

92-
String signatureAlgorithm = "SHA256WithRSA"; // <-- Use appropriate signature algorithm based on your keyPair algorithm.
98+
String signatureAlgorithm = "SHA256WithRSA";
9399
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate());
94100
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, keyPair.getPublic());
95101

96-
return new JcaX509CertificateConverter().setProvider(bcProvider).getCertificate(certBuilder.build(contentSigner));
102+
return new JcaX509CertificateConverter().setProvider(BC_PROVIDER).getCertificate(certBuilder.build(contentSigner));
97103
}
98104

99105
public static void saveCertificate(X509Certificate cert, Path path) throws Exception {
100106
String certPem = "-----BEGIN CERTIFICATE-----\n"
101-
+ formatBase64(Base64.getEncoder().encodeToString(cert.getEncoded()))
102-
+ "-----END CERTIFICATE-----";
107+
+ formatBase64(cert.getEncoded())
108+
+ "-----END CERTIFICATE-----\n";
103109
SmartFileUtils.createParentDirs(path);
104110
Files.writeString(path, certPem);
105111
}
@@ -115,18 +121,14 @@ public static X509Certificate loadCertificate(Path path) throws Exception {
115121
public static void savePrivateKey(PrivateKey key, Path path) throws Exception {
116122
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key.getEncoded());
117123
String keyPem = "-----BEGIN PRIVATE KEY-----\n"
118-
+ formatBase64(Base64.getEncoder().encodeToString(keySpec.getEncoded()))
119-
+ "-----END PRIVATE KEY-----";
124+
+ formatBase64(keySpec.getEncoded())
125+
+ "-----END PRIVATE KEY-----\n";
120126
SmartFileUtils.createParentDirs(path);
121127
Files.writeString(path, keyPem);
122128
}
123129

124-
private static String formatBase64(String base64) {
125-
StringBuilder sb = new StringBuilder();
126-
for (int i = 0; i < base64.length(); i += 64) {
127-
sb.append(base64, i, Math.min(i + 64, base64.length()));
128-
sb.append("\n");
129-
}
130-
return sb.toString();
131-
}
130+
private static String formatBase64(byte[] derEncodedBytes) {
131+
Base64.Encoder encoder = Base64.getMimeEncoder(64, new byte[]{'\n'});
132+
return encoder.encodeToString(derEncodedBytes) + "\n";
133+
}
132134
}

0 commit comments

Comments
 (0)