19 package org.turro.push.security;
22 import java.io.FileReader;
23 import java.io.FileWriter;
24 import java.io.IOException;
25 import java.math.BigInteger;
26 import java.security.InvalidAlgorithmParameterException;
27 import java.security.KeyFactory;
28 import java.security.KeyPair;
29 import java.security.KeyPairGenerator;
30 import java.security.NoSuchAlgorithmException;
31 import java.security.NoSuchProviderException;
32 import java.security.PrivateKey;
33 import java.security.PublicKey;
34 import java.security.Security;
35 import java.security.spec.InvalidKeySpecException;
36 import java.util.Properties;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
39 import org.apache.commons.codec.binary.Base64;
40 import org.bouncycastle.jce.ECNamedCurveTable;
41 import org.bouncycastle.jce.interfaces.ECPrivateKey;
42 import org.bouncycastle.jce.interfaces.ECPublicKey;
43 import org.bouncycastle.jce.provider.BouncyCastleProvider;
44 import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
45 import org.bouncycastle.jce.spec.ECParameterSpec;
46 import org.bouncycastle.jce.spec.ECPrivateKeySpec;
47 import org.bouncycastle.jce.spec.ECPublicKeySpec;
48 import org.bouncycastle.math.ec.ECCurve;
49 import org.bouncycastle.math.ec.ECPoint;
50 import org.bouncycastle.util.BigIntegers;
51 import org.turro.elephant.context.ElephantContext;
52 import org.turro.lock.Initializer;
61 return instance().getProperty(
"pk");
65 return instance().getProperty(
"sk");
70 private static final Initializer<Properties> PUSH_KEYS =
new Initializer<>();
72 private static Properties instance() {
73 return PUSH_KEYS.instance(() -> {
74 Security.addProvider(
new BouncyCastleProvider());
75 File keyPair = pushKeyPairFile();
76 if(!keyPair.exists()) generateKeyPair();
77 if(keyPair.exists()) {
78 try(FileReader reader =
new FileReader(keyPair)) {
79 Properties properties =
new Properties();
80 properties.load(reader);
82 }
catch (IOException ex) {
83 Logger.getLogger(
ServerKeys.class.getName()).log(Level.SEVERE,
null, ex);
90 private static final String PUSH_KEYPAIR =
"/WEB-INF/elephant/security/push.cipher";
92 private static void generateKeyPair() {
94 ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(
CURVE);
95 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
96 keyPairGenerator.initialize(parameterSpec);
97 saveKeyPair(keyPairGenerator.generateKeyPair());
98 }
catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException ex) {
99 Logger.getLogger(ServerKeys.class.getName()).log(Level.SEVERE,
null, ex);
103 private static void saveKeyPair(KeyPair serverKey) {
105 ECPublicKey
publicKey = (ECPublicKey) serverKey.getPublic();
106 ECPrivateKey
privateKey = (ECPrivateKey) serverKey.getPrivate();
109 String publicKeyBase64 = Base64.encodeBase64URLSafeString(encodedPublicKey);
110 String privateKeyBase64 = Base64.encodeBase64URLSafeString(encodedPrivateKey);
112 Properties keypair =
new Properties();
113 keypair.put(
"sk", privateKeyBase64);
114 keypair.put(
"pk", publicKeyBase64);
115 try(FileWriter writer =
new FileWriter(pushKeyPairFile())) {
116 keypair.store(writer,
"Elephant Push");
117 }
catch (IOException ex) {
118 Logger.getLogger(ServerKeys.class.getName()).log(Level.SEVERE,
null, ex);
121 }
catch (NoSuchProviderException | NoSuchAlgorithmException | InvalidKeySpecException ex) {
122 Logger.getLogger(ServerKeys.class.getName()).log(Level.SEVERE,
null, ex);
126 private static File pushKeyPairFile() {
127 return new File(ElephantContext.getRealPath(PUSH_KEYPAIR));
130 public static final String
CURVE =
"prime256v1";
134 return publicKey.getQ().getEncoded(
false);
142 ECNamedCurveParameterSpec curveParameters = ECNamedCurveTable.getParameterSpec(
CURVE);
143 ECPoint g = curveParameters.getG();
144 ECPoint sG = g.multiply(((java.security.interfaces.ECPrivateKey)
privateKey).getS());
146 return sG.equals(((ECPublicKey)
publicKey).getQ());
149 public static PrivateKey
loadPrivateKey(String encodedPrivateKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
150 byte[] decodedPrivateKey = Base64.decodeBase64(encodedPrivateKey);
154 public static PrivateKey
loadPrivateKey(
byte[] decodedPrivateKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
155 BigInteger s = BigIntegers.fromUnsignedByteArray(decodedPrivateKey);
156 ECParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(
CURVE);
157 ECPrivateKeySpec privateKeySpec =
new ECPrivateKeySpec(s, parameterSpec);
158 KeyFactory keyFactory = KeyFactory.getInstance(
ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
160 return keyFactory.generatePrivate(privateKeySpec);
163 public static PublicKey
loadPublicKey(String encodedPublicKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
164 byte[] decodedPublicKey = Base64.decodeBase64(encodedPublicKey);
168 public static PublicKey
loadPublicKey(
byte[] decodedPublicKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
169 KeyFactory keyFactory = KeyFactory.getInstance(
ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
170 ECParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(
CURVE);
171 ECCurve curve = parameterSpec.getCurve();
172 ECPoint point = curve.decodePoint(decodedPublicKey);
173 ECPublicKeySpec pubSpec =
new ECPublicKeySpec(point, parameterSpec);
175 return keyFactory.generatePublic(pubSpec);
static final String CURVE
static PrivateKey loadPrivateKey(String encodedPrivateKey)
static final String ALGORITHM
static PublicKey loadPublicKey(String encodedPublicKey)
static byte[] encode(ECPrivateKey privateKey)
static byte[] encode(ECPublicKey publicKey)
static PrivateKey loadPrivateKey(byte[] decodedPrivateKey)
static String publicKey()
static boolean verifyKeyPair(PrivateKey privateKey, PublicKey publicKey)
static PublicKey loadPublicKey(byte[] decodedPublicKey)
static String privateKey()