Skip to content
This repository has been archived by the owner on Feb 25, 2024. It is now read-only.

Commit

Permalink
initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
stefan-zobel committed Jul 12, 2020
1 parent 2a6f5e8 commit 1af4e08
Show file tree
Hide file tree
Showing 18 changed files with 1,021 additions and 0 deletions.
Binary file added build/mercurius-ssl-0.9.0-javadoc.jar
Binary file not shown.
Binary file added build/mercurius-ssl-0.9.0-sources.jar
Binary file not shown.
Binary file added build/mercurius-ssl-0.9.0.jar
Binary file not shown.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
<!-- this grants access to the restricted API -->
<compilerArgument>-XDignore.symbol.file</compilerArgument>
</configuration>
</plugin>
<plugin>
Expand All @@ -30,6 +33,9 @@
<goals>
<goal>jar</goal>
</goals>
<configuration>
<doclint>none</doclint>
</configuration>
</execution>
</executions>
</plugin>
Expand Down
Empty file removed src/main/java/empty.txt
Empty file.
129 changes: 129 additions & 0 deletions src/main/java/net/mercurius/ks/CertGen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright 2020 Stefan Zobel
*
* 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 net.mercurius.ks;

import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;

import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.CertificateExtensions;
import sun.security.x509.KeyIdentifier;
import sun.security.x509.SubjectKeyIdentifierExtension;
import sun.security.x509.X500Name;

public final class CertGen {

private static final int RSA_KEY_BITS_DEFAULT = 5120;
private static final int ECDSA_KEY_BITS_DEFAULT = 521;
// 15 years validity
private static final long VALIDITY = 15L * 365L * 24L * 60L * 60L;
private static final String DUMMY_DN = "CN=GeoTrust Primary Certification Authority - G2, OU=(c) 2007 GeoTrust Inc. - For authorized use only, O=GeoTrust Inc., C=US";
private static final String DEFAULT_ALIAS = "localhost";

public static void main(String[] args) {
String password = (args != null && args.length > 0) ? args[0] : "";
String ksFileName = (args != null && args.length > 1) ? args[1] : "ks.p12";
String dn = (args != null && args.length > 2) ? args[2] : DUMMY_DN;
String alias = (args != null && args.length > 3) ? args[3] : DEFAULT_ALIAS;
char[] passwd = PBKDF2.getKey(password);
System.out.println(passwd);
System.out.println(passwd.length);

long start = System.currentTimeMillis();

Date startDate = new Date();
KeyStore ks = generateKeyStore(dn, alias, passwd, startDate);

long end = System.currentTimeMillis();
System.out.println("took: " + (end - start) + " ms");

try (FileOutputStream fos = new FileOutputStream(ksFileName)) {
ks.store(fos, passwd);
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
throw new RuntimeException(e);
}
}

private static KeyStore generateKeyStore(String certificateDN, String keyEntryAlias, char[] passwd,
Date startDate) {
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null, new char[] {});

generateECDSACertificate(keyStore, certificateDN, keyEntryAlias, passwd, startDate);
generateRSACertificate(keyStore, certificateDN, keyEntryAlias + "2", passwd, startDate);

return keyStore;
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
throw new RuntimeException(e);
}
}

private static void generateECDSACertificate(KeyStore keyStore, String certificateDN, String keyEntryAlias,
char[] passwd, Date startDate) {
try {
CertAndKeyGen certGen = new CertAndKeyGen("EC", "SHA512withECDSA", null);
certGen.generate(ECDSA_KEY_BITS_DEFAULT);

storeCertificate(keyStore, certificateDN, keyEntryAlias, passwd, startDate, certGen);

} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException(e);
}
}

private static void generateRSACertificate(KeyStore keyStore, String certificateDN, String keyEntryAlias,
char[] passwd, Date startDate) {
try {
CertAndKeyGen certGen = new CertAndKeyGen("RSA", "SHA512withRSA", null);
certGen.generate(RSA_KEY_BITS_DEFAULT);

storeCertificate(keyStore, certificateDN, keyEntryAlias, passwd, startDate, certGen);

} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException(e);
}
}

private static void storeCertificate(KeyStore keyStore, String certificateDN, String keyEntryAlias, char[] passwd,
Date startDate, CertAndKeyGen certGen) {
try {
CertificateExtensions ext = new CertificateExtensions();
ext.set(SubjectKeyIdentifierExtension.NAME,
new SubjectKeyIdentifierExtension(new KeyIdentifier(certGen.getPublicKeyAnyway()).getIdentifier()));

X509Certificate cert = certGen.getSelfCertificate(new X500Name(certificateDN), startDate, VALIDITY, ext);

keyStore.setKeyEntry(keyEntryAlias, certGen.getPrivateKey(), passwd, new X509Certificate[] { cert });
} catch (InvalidKeyException | CertificateException | SignatureException | NoSuchAlgorithmException
| NoSuchProviderException | KeyStoreException | IOException e) {
throw new RuntimeException(e);
}
}

private CertGen() {
throw new AssertionError();
}
}
75 changes: 75 additions & 0 deletions src/main/java/net/mercurius/ks/KSLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2020 Stefan Zobel
*
* 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 net.mercurius.ks;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

public final class KSLoader {

private static final String KS_NAME = "ks.p12";

/**
* Test mode. Do not use in production!
*/
public static KeyStore loadKeyStore() {
try (InputStream is = KSLoader.class.getResourceAsStream(KS_NAME)) {
if (is == null) {
throw new IllegalStateException("KeyStore " + KS_NAME + " not found!");
}
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(is, passPhrase());
return ks;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

public static KeyStore loadKeyStore(String password, Path file) {
//@formatter:off
try (InputStream is = Files.newInputStream(file);
BufferedInputStream bis = new BufferedInputStream(is, 1 << 14)
)
{
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(bis, passPhrase(password));
return ks;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
//@formatter:on
}

public static char[] passPhrase() {
return "VpAovsDbxZdX+k3qed8hqEOeSqknJGT1uYanS69gZ2CBJ6oQuZSCGYky7n4WZGpWNWwR".toCharArray();
}

public static char[] passPhrase(String password) {
return PBKDF2.getKey(password);
}
}
63 changes: 63 additions & 0 deletions src/main/java/net/mercurius/ks/PBKDF2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2013 Stefan Zobel
*
* 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 net.mercurius.ks;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public final class PBKDF2 {

private static final String PRIV_1 = "@GSr:p\"[dZR6RU;B:s&;4P<3XHPl@\"|r9*Az w#:";
private static final String PRIV_2 = ",k~m:@HXE-a%%7 c](8J|Yu{d\"`./DK_f'z }^'S";

// 16384 (= 2^14) iterations
private static final int ITERS = 1 << 14;

private static final byte[] SALT_64 = { 59, -76, -110, 53, -98, 81, 100, 67, -90, 113, -119, -32, -5, -61, 44, -9,
8, -108, 107, -86, 118, -125, -70, -94, 59, -106, -121, -18, 15, 12, 12, -77, 108, 70, 125, 23, -79, 66, 18,
-51, 67, 55, 53, -28, -35, -92, -54, 37, -101, 57, 100, -128, 41, 24, 107, -25, -106, 73, -108, -110, -34,
-102, -55, 74 };

private static final int KEY_LENGTH = 51;

public static char[] getKey(String password) {
String pwd = password;
if (pwd == null || "".equals(pwd)) {
pwd = PRIV_1;
}
pwd += PRIV_2;
try {
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
KeySpec spec = new PBEKeySpec(pwd.toCharArray(), SALT_64, ITERS, KEY_LENGTH * 8);
byte[] encoded = skf.generateSecret(spec).getEncoded();
char[] ksPwd = Base64.getEncoder().encodeToString(encoded).toCharArray();
Arrays.fill(encoded, (byte) 0);
return ksPwd;
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}

private PBKDF2() {
throw new AssertionError();
}
}
45 changes: 45 additions & 0 deletions src/main/java/net/mercurius/ssl/Protocol.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2020 Stefan Zobel
*
* 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 net.mercurius.ssl;

public enum Protocol {

//@formatter:off
TLS_12("TLSv1.2"),
TLS_13("TLSv1.3");
//@formatter:on

private final String name;

private Protocol(String prot) {
name = prot;
}

public String toString() {
return name;
}

public static Protocol of(String protocolName) {
switch (protocolName) {
case "TLSv1.2":
return TLS_12;
case "TLSv1.3":
return TLS_13;
default:
return null;
}
}
}
Loading

0 comments on commit 1af4e08

Please sign in to comment.