Skip to content

Commit 776ca78

Browse files
committed
Extract common XEC functionality to a utility class
1 parent dadea56 commit 776ca78

File tree

4 files changed

+71
-44
lines changed

4 files changed

+71
-44
lines changed

src/main/java/com/eatthepath/noise/component/AbstractXECKeyAgreement.java

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,57 +42,22 @@ public byte[] generateSecret(final PrivateKey privateKey, final PublicKey public
4242

4343
@Override
4444
public byte[] serializePublicKey(final PublicKey publicKey) {
45-
// This is a little hacky, but the structure for an X.509 public key defines the order in which its elements appear.
46-
// The first part of the key, which defines the algorithm and its parameters, is always the same for keys of the
47-
// same type, and the last N bytes are the literal key material.
48-
final byte[] serializedPublicKey = new byte[getPublicKeyLength()];
49-
System.arraycopy(publicKey.getEncoded(), getX509Prefix().length, serializedPublicKey, 0, getPublicKeyLength());
50-
51-
return serializedPublicKey;
45+
return XECUtil.serializePublicKey(publicKey, getPublicKeyLength(), getX509Prefix());
5246
}
5347

5448
@Override
5549
public PublicKey deserializePublicKey(final byte[] publicKeyBytes) {
56-
final int publicKeyLength = getPublicKeyLength();
57-
58-
if (publicKeyBytes.length != publicKeyLength) {
59-
throw new IllegalArgumentException("Unexpected serialized public key length");
60-
}
61-
62-
final byte[] x509Prefix = getX509Prefix();
63-
final byte[] x509Bytes = new byte[publicKeyLength + x509Prefix.length];
64-
System.arraycopy(x509Prefix, 0, x509Bytes, 0, x509Prefix.length);
65-
System.arraycopy(publicKeyBytes, 0, x509Bytes, x509Prefix.length, publicKeyLength);
66-
67-
try {
68-
return keyFactory.generatePublic(new X509EncodedKeySpec(x509Bytes, keyFactory.getAlgorithm()));
69-
} catch (final InvalidKeySpecException e) {
70-
throw new IllegalArgumentException("Invalid key", e);
71-
}
50+
return XECUtil.deserializePublicKey(publicKeyBytes, getPublicKeyLength(), getX509Prefix(), keyFactory);
7251
}
7352

7453
@Override
7554
public void checkPublicKey(final PublicKey publicKey) throws InvalidKeyException {
76-
checkKey(publicKey);
55+
XECUtil.checkKey(publicKey, keyAgreement.getAlgorithm());
7756
}
7857

7958
@Override
8059
public void checkKeyPair(final KeyPair keyPair) throws InvalidKeyException {
81-
checkKey(keyPair.getPublic());
82-
checkKey(keyPair.getPrivate());
83-
}
84-
85-
private void checkKey(final Key key) throws InvalidKeyException {
86-
if (key instanceof XECKey xecKey) {
87-
if (xecKey.getParams() instanceof NamedParameterSpec namedParameterSpec) {
88-
if (!keyAgreement.getAlgorithm().equals(namedParameterSpec.getName())) {
89-
throw new InvalidKeyException("Unexpected key algorithm: " + namedParameterSpec.getName());
90-
}
91-
} else {
92-
throw new InvalidKeyException("Unexpected key parameter type: " + xecKey.getParams().getClass());
93-
}
94-
} else {
95-
throw new InvalidKeyException("Unexpected key type: " + key.getClass());
96-
}
60+
XECUtil.checkKey(keyPair.getPublic(), keyAgreement.getAlgorithm());
61+
XECUtil.checkKey(keyPair.getPrivate(), keyAgreement.getAlgorithm());
9762
}
9863
}

src/main/java/com/eatthepath/noise/component/X25519KeyAgreement.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
class X25519KeyAgreement extends AbstractXECKeyAgreement {
88

99
private static final String ALGORITHM = "X25519";
10-
private static final byte[] X509_PREFIX = HexFormat.of().parseHex("302a300506032b656e032100");
1110

1211
public X25519KeyAgreement() throws NoSuchAlgorithmException {
1312
super(KeyAgreement.getInstance(ALGORITHM), KeyPairGenerator.getInstance(ALGORITHM), KeyFactory.getInstance(ALGORITHM));
@@ -25,6 +24,6 @@ public int getPublicKeyLength() {
2524

2625
@Override
2726
protected byte[] getX509Prefix() {
28-
return X509_PREFIX;
27+
return XECUtil.X25519_X509_PREFIX;
2928
}
3029
}

src/main/java/com/eatthepath/noise/component/X448KeyAgreement.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
class X448KeyAgreement extends AbstractXECKeyAgreement {
88

99
private static final String ALGORITHM = "X448";
10-
private static final byte[] X509_PREFIX = HexFormat.of().parseHex("3042300506032b656f033900");
1110

1211
public X448KeyAgreement() throws NoSuchAlgorithmException {
1312
super(KeyAgreement.getInstance(ALGORITHM), KeyPairGenerator.getInstance(ALGORITHM), KeyFactory.getInstance(ALGORITHM));
@@ -25,6 +24,6 @@ public int getPublicKeyLength() {
2524

2625
@Override
2726
protected byte[] getX509Prefix() {
28-
return X509_PREFIX;
27+
return XECUtil.X448_X509_PREFIX;
2928
}
3029
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.eatthepath.noise.component;
2+
3+
import java.security.InvalidKeyException;
4+
import java.security.Key;
5+
import java.security.KeyFactory;
6+
import java.security.PublicKey;
7+
import java.security.interfaces.XECKey;
8+
import java.security.spec.InvalidKeySpecException;
9+
import java.security.spec.NamedParameterSpec;
10+
import java.security.spec.X509EncodedKeySpec;
11+
import java.util.HexFormat;
12+
13+
class XECUtil {
14+
15+
static final byte[] X25519_X509_PREFIX = HexFormat.of().parseHex("302a300506032b656e032100");
16+
static final byte[] X448_X509_PREFIX = HexFormat.of().parseHex("3042300506032b656f033900");
17+
18+
private XECUtil() {
19+
}
20+
21+
static byte[] serializePublicKey(final PublicKey publicKey, final int publicKeyLength, final byte[] x509Prefix) {
22+
// This is a little hacky, but the structure for an X.509 public key defines the order in which its elements appear.
23+
// The first part of the key, which defines the algorithm and its parameters, is always the same for keys of the
24+
// same type, and the last N bytes are the literal key material.
25+
final byte[] serializedPublicKey = new byte[publicKeyLength];
26+
System.arraycopy(publicKey.getEncoded(), x509Prefix.length, serializedPublicKey, 0, publicKeyLength);
27+
28+
return serializedPublicKey;
29+
}
30+
31+
static PublicKey deserializePublicKey(final byte[] publicKeyBytes,
32+
final int publicKeyLength,
33+
final byte[] x509Prefix,
34+
final KeyFactory keyFactory) {
35+
36+
if (publicKeyBytes.length != publicKeyLength) {
37+
throw new IllegalArgumentException("Unexpected serialized public key length");
38+
}
39+
40+
final byte[] x509Bytes = new byte[publicKeyLength + x509Prefix.length];
41+
System.arraycopy(x509Prefix, 0, x509Bytes, 0, x509Prefix.length);
42+
System.arraycopy(publicKeyBytes, 0, x509Bytes, x509Prefix.length, publicKeyLength);
43+
44+
try {
45+
return keyFactory.generatePublic(new X509EncodedKeySpec(x509Bytes, keyFactory.getAlgorithm()));
46+
} catch (final InvalidKeySpecException e) {
47+
throw new IllegalArgumentException("Invalid key", e);
48+
}
49+
}
50+
51+
static void checkKey(final Key key, final String algorithm) throws InvalidKeyException {
52+
if (key instanceof XECKey xecKey) {
53+
if (xecKey.getParams() instanceof NamedParameterSpec namedParameterSpec) {
54+
if (!algorithm.equals(namedParameterSpec.getName())) {
55+
throw new InvalidKeyException("Unexpected key algorithm: " + namedParameterSpec.getName());
56+
}
57+
} else {
58+
throw new InvalidKeyException("Unexpected key parameter type: " + xecKey.getParams().getClass());
59+
}
60+
} else {
61+
throw new InvalidKeyException("Unexpected key type: " + key.getClass());
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)