Skip to content

Commit baf0b02

Browse files
committed
remove bouncycastle
1 parent 9991b07 commit baf0b02

6 files changed

Lines changed: 138 additions & 221 deletions

File tree

sdk/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,12 @@
164164
<dependency>
165165
<groupId>org.bouncycastle</groupId>
166166
<artifactId>bcpkix-jdk18on</artifactId>
167+
<scope>test</scope>
167168
</dependency>
168169
<dependency>
169170
<groupId>org.bouncycastle</groupId>
170171
<artifactId>bcprov-jdk18on</artifactId>
172+
<scope>test</scope>
171173
</dependency>
172174
<!-- Testing Dependencies -->
173175
<dependency>
Lines changed: 83 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,28 @@
11
package io.opentdf.platform.sdk;
22

3-
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
4-
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
5-
import org.bouncycastle.cert.X509CertificateHolder;
6-
import org.bouncycastle.crypto.digests.SHA256Digest;
7-
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
8-
import org.bouncycastle.crypto.params.HKDFParameters;
9-
import org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi;
10-
import org.bouncycastle.jce.ECNamedCurveTable;
11-
import org.bouncycastle.jce.interfaces.ECPrivateKey;
12-
import org.bouncycastle.jce.interfaces.ECPublicKey;
13-
import org.bouncycastle.jce.provider.BouncyCastleProvider;
14-
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
15-
import org.bouncycastle.math.ec.ECPoint;
16-
import org.bouncycastle.openssl.PEMException;
17-
import org.bouncycastle.openssl.PEMParser;
18-
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
19-
import org.bouncycastle.util.io.pem.*;
20-
import org.bouncycastle.util.io.pem.PemReader;
21-
import org.bouncycastle.jce.spec.ECPublicKeySpec;
22-
233
import javax.crypto.KeyAgreement;
24-
import java.io.*;
25-
import java.security.*;
26-
import java.security.spec.*;
4+
import javax.crypto.Mac;
5+
import javax.crypto.spec.SecretKeySpec;
6+
import java.math.BigInteger;
7+
import java.security.InvalidAlgorithmParameterException;
8+
import java.security.InvalidKeyException;
9+
import java.security.KeyPair;
10+
import java.security.KeyPairGenerator;
11+
import java.security.NoSuchAlgorithmException;
12+
import java.security.Signature;
13+
import java.security.SignatureException;
14+
import java.security.interfaces.ECPrivateKey;
15+
import java.security.interfaces.ECPublicKey;
16+
import java.security.spec.ECGenParameterSpec;
17+
import java.security.spec.ECParameterSpec;
18+
import java.security.spec.ECPoint;
19+
import java.util.Base64;
2720
import java.util.Objects;
28-
// https://www.bouncycastle.org/latest_releases.html
2921

3022
public class ECKeyPair {
3123

3224
private static final int SHA256_BYTES = 32;
33-
34-
static {
35-
Security.addProvider(new BouncyCastleProvider());
36-
}
25+
private static final String EC_ALGORITHM = "EC";
3726

3827
private final ECCurve curve;
3928

@@ -42,8 +31,6 @@ public enum ECAlgorithm {
4231
ECDSA
4332
}
4433

45-
private static final BouncyCastleProvider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();
46-
4734
private KeyPair keyPair;
4835

4936
public ECKeyPair() {
@@ -52,27 +39,14 @@ public ECKeyPair() {
5239

5340
public ECKeyPair(ECCurve curve, ECAlgorithm algorithm) {
5441
this.curve = Objects.requireNonNull(curve);
55-
KeyPairGenerator generator;
56-
42+
Objects.requireNonNull(algorithm);
5743
try {
58-
// Should this just use the algorithm vs use ECDH only for ECDH and ECDSA for
59-
// everything else.
60-
if (algorithm == ECAlgorithm.ECDH) {
61-
generator = KeyPairGeneratorSpi.getInstance(ECAlgorithm.ECDH.name(), BOUNCY_CASTLE_PROVIDER);
62-
} else {
63-
generator = KeyPairGeneratorSpi.getInstance(ECAlgorithm.ECDSA.name(), BOUNCY_CASTLE_PROVIDER);
64-
}
65-
} catch (NoSuchAlgorithmException e) {
44+
KeyPairGenerator generator = KeyPairGenerator.getInstance(EC_ALGORITHM);
45+
generator.initialize(new ECGenParameterSpec(this.curve.getCurveName()));
46+
this.keyPair = generator.generateKeyPair();
47+
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
6648
throw new RuntimeException(e);
6749
}
68-
69-
ECGenParameterSpec spec = new ECGenParameterSpec(this.curve.getCurveName());
70-
try {
71-
generator.initialize(spec);
72-
} catch (InvalidAlgorithmParameterException e) {
73-
throw new RuntimeException(e);
74-
}
75-
this.keyPair = generator.generateKeyPair();
7650
}
7751

7852
public ECPublicKey getPublicKey() {
@@ -88,148 +62,28 @@ ECCurve getCurve() {
8862
}
8963

9064
public String publicKeyInPEMFormat() {
91-
StringWriter writer = new StringWriter();
92-
PemWriter pemWriter = new PemWriter(writer);
93-
94-
try {
95-
pemWriter.writeObject(new PemObject("PUBLIC KEY", this.keyPair.getPublic().getEncoded()));
96-
pemWriter.flush();
97-
pemWriter.close();
98-
} catch (IOException e) {
99-
throw new RuntimeException(e);
100-
}
101-
102-
return writer.toString();
65+
return toPem("PUBLIC KEY", this.keyPair.getPublic().getEncoded());
10366
}
10467

10568
public String privateKeyInPEMFormat() {
106-
StringWriter writer = new StringWriter();
107-
PemWriter pemWriter = new PemWriter(writer);
108-
109-
try {
110-
pemWriter.writeObject(new PemObject("PRIVATE KEY", this.keyPair.getPrivate().getEncoded()));
111-
pemWriter.flush();
112-
pemWriter.close();
113-
} catch (IOException e) {
114-
throw new RuntimeException(e);
115-
}
116-
117-
return writer.toString();
69+
return toPem("PRIVATE KEY", this.keyPair.getPrivate().getEncoded());
11870
}
11971

12072
public int keySize() {
12173
return this.keyPair.getPrivate().getEncoded().length * 8;
12274
}
12375

12476
public byte[] compressECPublickey() {
125-
return ((ECPublicKey) this.keyPair.getPublic()).getQ().getEncoded(true);
126-
}
127-
128-
public static String getPEMPublicKeyFromX509Cert(String pemInX509Format) {
129-
try {
130-
PEMParser parser = new PEMParser(new StringReader(pemInX509Format));
131-
X509CertificateHolder x509CertificateHolder = (X509CertificateHolder) parser.readObject();
132-
parser.close();
133-
SubjectPublicKeyInfo publicKeyInfo = x509CertificateHolder.getSubjectPublicKeyInfo();
134-
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BOUNCY_CASTLE_PROVIDER);
135-
ECPublicKey publicKey = null;
136-
try {
137-
publicKey = (ECPublicKey) converter.getPublicKey(publicKeyInfo);
138-
} catch (PEMException e) {
139-
throw new RuntimeException(e);
140-
}
141-
142-
// EC public key to pem formated.
143-
StringWriter writer = new StringWriter();
144-
PemWriter pemWriter = new PemWriter(writer);
145-
146-
pemWriter.writeObject(new PemObject("PUBLIC KEY", publicKey.getEncoded()));
147-
pemWriter.flush();
148-
pemWriter.close();
149-
return writer.toString();
150-
} catch (IOException e) {
151-
throw new RuntimeException(e);
152-
}
153-
}
154-
155-
public static byte[] compressECPublickey(String pemECPubKey) {
156-
try {
157-
KeyFactory ecKeyFac = KeyFactory.getInstance("EC", "BC");
158-
PemReader pemReader = new PemReader(new StringReader(pemECPubKey));
159-
PemObject pemObject = pemReader.readPemObject();
160-
PublicKey pubKey = ecKeyFac.generatePublic(new X509EncodedKeySpec(pemObject.getContent()));
161-
return ((ECPublicKey) pubKey).getQ().getEncoded(true);
162-
} catch (NoSuchAlgorithmException e) {
163-
throw new RuntimeException(e);
164-
} catch (IOException e) {
165-
throw new RuntimeException(e);
166-
} catch (InvalidKeySpecException e) {
167-
throw new RuntimeException(e);
168-
} catch (NoSuchProviderException e) {
169-
throw new RuntimeException(e);
170-
}
171-
}
172-
173-
public static String publicKeyFromECPoint(byte[] ecPoint, String curveName) {
174-
try {
175-
// Create EC Public key
176-
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(curveName);
177-
ECPoint point = ecSpec.getCurve().decodePoint(ecPoint);
178-
ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(point, ecSpec);
179-
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
180-
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
181-
182-
// EC Public keu to pem format.
183-
StringWriter writer = new StringWriter();
184-
PemWriter pemWriter = new PemWriter(writer);
185-
pemWriter.writeObject(new PemObject("PUBLIC KEY", publicKey.getEncoded()));
186-
pemWriter.flush();
187-
pemWriter.close();
188-
return writer.toString();
189-
} catch (InvalidKeySpecException e) {
190-
throw new RuntimeException(e);
191-
} catch (NoSuchAlgorithmException e) {
192-
throw new RuntimeException(e);
193-
} catch (NoSuchProviderException e) {
194-
throw new RuntimeException(e);
195-
} catch (IOException e) {
196-
throw new RuntimeException(e);
197-
}
198-
}
199-
200-
public static ECPublicKey publicKeyFromPem(String pemEncoding) {
201-
try {
202-
PEMParser parser = new PEMParser(new StringReader(pemEncoding));
203-
SubjectPublicKeyInfo publicKeyInfo = (SubjectPublicKeyInfo) parser.readObject();
204-
parser.close();
205-
206-
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BOUNCY_CASTLE_PROVIDER);
207-
return (ECPublicKey) converter.getPublicKey(publicKeyInfo);
208-
} catch (IOException e) {
209-
throw new RuntimeException(e);
210-
}
211-
}
212-
213-
public static ECPrivateKey privateKeyFromPem(String pemEncoding) {
214-
try {
215-
PEMParser parser = new PEMParser(new StringReader(pemEncoding));
216-
PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) parser.readObject();
217-
parser.close();
218-
219-
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BOUNCY_CASTLE_PROVIDER);
220-
return (ECPrivateKey) converter.getPrivateKey(privateKeyInfo);
221-
} catch (IOException e) {
222-
throw new RuntimeException(e);
223-
}
77+
return encodeCompressedPoint((ECPublicKey) this.keyPair.getPublic());
22478
}
22579

22680
public static byte[] computeECDHKey(ECPublicKey publicKey, ECPrivateKey privateKey) {
22781
try {
228-
KeyAgreement aKeyAgree = KeyAgreement.getInstance("ECDH", "BC");
82+
KeyAgreement aKeyAgree = KeyAgreement.getInstance("ECDH");
22983
aKeyAgree.init(privateKey);
23084
aKeyAgree.doPhase(publicKey, true);
23185
return aKeyAgree.generateSecret();
232-
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException e) {
86+
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
23387
throw new RuntimeException(e);
23488
}
23589
}
@@ -239,46 +93,78 @@ public static byte[] computeECDHKey(ECPublicKey publicKey, ECPrivateKey privateK
23993
* that is 32 bytes (256 bits) long.
24094
*/
24195
public static byte[] calculateHKDF(byte[] salt, byte[] secret) {
242-
byte[] key = new byte[SHA256_BYTES];
243-
HKDFParameters params = new HKDFParameters(secret, salt, null);
244-
245-
HKDFBytesGenerator hkdf = new HKDFBytesGenerator(SHA256Digest.newInstance());
246-
hkdf.init(params);
247-
hkdf.generateBytes(key, 0, key.length);
248-
return key;
96+
try {
97+
// RFC 5869: if salt is absent, substitute a zero-filled buffer of Hash output size.
98+
byte[] effectiveSalt = (salt == null || salt.length == 0) ? new byte[SHA256_BYTES] : salt;
99+
Mac hmac = Mac.getInstance("HmacSHA256");
100+
hmac.init(new SecretKeySpec(effectiveSalt, "HmacSHA256"));
101+
byte[] prk = hmac.doFinal(secret);
102+
103+
// HKDF-Expand with empty info and L = 32 (a single HMAC block).
104+
hmac.init(new SecretKeySpec(prk, "HmacSHA256"));
105+
hmac.update((byte) 0x01);
106+
return hmac.doFinal();
107+
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
108+
throw new RuntimeException(e);
109+
}
249110
}
250111

251112
public static byte[] computeECDSASig(byte[] digest, ECPrivateKey privateKey) {
252113
try {
253-
Signature ecdsaSign = Signature.getInstance("SHA256withECDSA", "BC");
114+
Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
254115
ecdsaSign.initSign(privateKey);
255116
ecdsaSign.update(digest);
256117
return ecdsaSign.sign();
257-
} catch (NoSuchAlgorithmException e) {
258-
throw new RuntimeException(e);
259-
} catch (NoSuchProviderException e) {
260-
throw new RuntimeException(e);
261-
} catch (InvalidKeyException e) {
262-
throw new RuntimeException(e);
263-
} catch (SignatureException e) {
118+
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
264119
throw new RuntimeException(e);
265120
}
266121
}
267122

268123
public static Boolean verifyECDSAig(byte[] digest, byte[] signature, ECPublicKey publicKey) {
269124
try {
270-
Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA", "BC");
125+
Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA");
271126
ecdsaVerify.initVerify(publicKey);
272127
ecdsaVerify.update(digest);
273128
return ecdsaVerify.verify(signature);
274-
} catch (NoSuchAlgorithmException e) {
275-
throw new RuntimeException(e);
276-
} catch (NoSuchProviderException e) {
277-
throw new RuntimeException(e);
278-
} catch (InvalidKeyException e) {
279-
throw new RuntimeException(e);
280-
} catch (SignatureException e) {
129+
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
281130
throw new RuntimeException(e);
282131
}
283132
}
284-
}
133+
134+
private static String toPem(String type, byte[] der) {
135+
String b64 = Base64.getEncoder().encodeToString(der);
136+
StringBuilder sb = new StringBuilder();
137+
sb.append("-----BEGIN ").append(type).append("-----\n");
138+
for (int i = 0; i < b64.length(); i += 64) {
139+
sb.append(b64, i, Math.min(i + 64, b64.length())).append('\n');
140+
}
141+
sb.append("-----END ").append(type).append("-----\n");
142+
return sb.toString();
143+
}
144+
145+
private static byte[] encodeCompressedPoint(ECPublicKey publicKey) {
146+
ECPoint w = publicKey.getW();
147+
ECParameterSpec params = publicKey.getParams();
148+
int size = (params.getCurve().getField().getFieldSize() + 7) / 8;
149+
byte[] x = toFixedLength(w.getAffineX(), size);
150+
byte[] result = new byte[size + 1];
151+
result[0] = (byte) (w.getAffineY().testBit(0) ? 0x03 : 0x02);
152+
System.arraycopy(x, 0, result, 1, size);
153+
return result;
154+
}
155+
156+
private static byte[] toFixedLength(BigInteger value, int length) {
157+
byte[] bytes = value.toByteArray();
158+
if (bytes.length == length) {
159+
return bytes;
160+
}
161+
byte[] result = new byte[length];
162+
if (bytes.length > length) {
163+
// BigInteger.toByteArray() may prepend a zero sign byte; strip it.
164+
System.arraycopy(bytes, bytes.length - length, result, 0, length);
165+
} else {
166+
System.arraycopy(bytes, 0, result, length - bytes.length, bytes.length);
167+
}
168+
return result;
169+
}
170+
}

0 commit comments

Comments
 (0)