Skip to content

Commit feff0e8

Browse files
authored
feat(sdk): Get the algorithm from the KASInfo and not the config (#272)
Instead of taking what's in the config use what's in the key since what we use to actually do the cryptography. Also some refactoring to simplify how we get key metadata.
1 parent 14288d5 commit feff0e8

File tree

15 files changed

+216
-202
lines changed

15 files changed

+216
-202
lines changed

sdk/src/main/java/io/opentdf/platform/sdk/ECCMode.java

Lines changed: 7 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.opentdf.platform.sdk;
22

3+
import javax.annotation.Nonnull;
4+
35
public class ECCMode {
46
private ECCModeStruct data;
57

@@ -13,7 +15,7 @@ public ECCMode() {
1315
public ECCMode(byte value) {
1416
data = new ECCModeStruct();
1517
int curveMode = value & 0x07; // first 3 bits
16-
setEllipticCurve(NanoTDFType.ECCurve.values()[curveMode]);
18+
setEllipticCurve(NanoTDFType.ECCurve.fromCurveMode(curveMode));
1719
int useECDSABinding = (value >> 7) & 0x01; // most significant bit
1820
data.useECDSABinding = useECDSABinding;
1921
}
@@ -44,75 +46,24 @@ public void setEllipticCurve(NanoTDFType.ECCurve curve) {
4446
}
4547
}
4648

47-
public NanoTDFType.ECCurve getEllipticCurveType() {
48-
return NanoTDFType.ECCurve.values()[data.curveMode];
49-
}
50-
5149
public boolean isECDSABindingEnabled() {
5250
return data.useECDSABinding == 1;
5351
}
5452

55-
public String getCurveName() {
56-
return getEllipticCurveName(NanoTDFType.ECCurve.values()[data.curveMode]);
57-
}
58-
5953
public byte getECCModeAsByte() {
6054
int value = (data.useECDSABinding << 7) | data.curveMode;
6155
return (byte) value;
6256
}
6357

64-
public static String getEllipticCurveName(NanoTDFType.ECCurve curve) {
65-
switch (curve) {
66-
case SECP256R1:
67-
return "secp256r1";
68-
case SECP384R1:
69-
return "secp384r1";
70-
case SECP521R1:
71-
return "secp521r1";
72-
case SECP256K1:
73-
throw new RuntimeException("SDK doesn't support 'secp256k1' curve");
74-
default:
75-
throw new RuntimeException("Unsupported ECC algorithm.");
76-
}
77-
}
78-
79-
public static int getECKeySize(NanoTDFType.ECCurve curve) {
80-
switch (curve) {
81-
case SECP256K1:
82-
throw new RuntimeException("SDK doesn't support 'secp256k1' curve");
83-
case SECP256R1:
84-
return 32;
85-
case SECP384R1:
86-
return 48;
87-
case SECP521R1:
88-
return 66;
89-
default:
90-
throw new RuntimeException("Unsupported ECC algorithm.");
91-
}
92-
}
93-
9458
public static int getECDSASignatureStructSize(NanoTDFType.ECCurve curve) {
95-
int keySize = getECKeySize(curve);
59+
int keySize = curve.getKeySize();
9660
return (1 + keySize + 1 + keySize);
9761
}
9862

99-
public static int getECKeySize(String curveName) {
100-
return ECKeyPair.getECKeySize(curveName);
101-
}
10263

103-
public static int getECCompressedPubKeySize(NanoTDFType.ECCurve curve) {
104-
switch (curve) {
105-
case SECP256K1:
106-
throw new RuntimeException("SDK doesn't support 'secp256k1' curve");
107-
case SECP256R1:
108-
return 33;
109-
case SECP384R1:
110-
return 49;
111-
case SECP521R1:
112-
return 67;
113-
default:
114-
throw new RuntimeException("Unsupported ECC algorithm.");
115-
}
64+
@Nonnull
65+
public NanoTDFType.ECCurve getCurve() {
66+
return NanoTDFType.ECCurve.fromCurveMode(data.curveMode);
11667
}
11768

11869
private class ECCModeStruct {

sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java

Lines changed: 9 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.io.*;
2525
import java.security.*;
2626
import java.security.spec.*;
27+
import java.util.Objects;
2728
// https://www.bouncycastle.org/latest_releases.html
2829

2930
public class ECKeyPair {
@@ -32,45 +33,23 @@ public class ECKeyPair {
3233
Security.addProvider(new BouncyCastleProvider());
3334
}
3435

36+
private final NanoTDFType.ECCurve curve;
37+
3538
public enum ECAlgorithm {
3639
ECDH,
3740
ECDSA
3841
}
3942

4043
private static final BouncyCastleProvider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();
4144

42-
public enum NanoTDFECCurve {
43-
SECP256R1("secp256r1", KeyType.EC256Key),
44-
PRIME256V1("prime256v1", KeyType.EC256Key),
45-
SECP384R1("secp384r1", KeyType.EC384Key),
46-
SECP521R1("secp521r1", KeyType.EC521Key);
47-
48-
private String name;
49-
private KeyType keyType;
50-
51-
NanoTDFECCurve(String curveName, KeyType keyType) {
52-
this.name = curveName;
53-
this.keyType = keyType;
54-
}
55-
56-
@Override
57-
public String toString() {
58-
return name;
59-
}
60-
61-
public KeyType getKeyType() {
62-
return keyType;
63-
}
64-
}
65-
6645
private KeyPair keyPair;
67-
private String curveName;
6846

6947
public ECKeyPair() {
70-
this("secp256r1", ECAlgorithm.ECDH);
48+
this(NanoTDFType.ECCurve.SECP256R1, ECAlgorithm.ECDH);
7149
}
7250

73-
public ECKeyPair(String curveName, ECAlgorithm algorithm) {
51+
public ECKeyPair(NanoTDFType.ECCurve curve, ECAlgorithm algorithm) {
52+
this.curve = Objects.requireNonNull(curve);
7453
KeyPairGenerator generator;
7554

7655
try {
@@ -85,19 +64,13 @@ public ECKeyPair(String curveName, ECAlgorithm algorithm) {
8564
throw new RuntimeException(e);
8665
}
8766

88-
ECGenParameterSpec spec = new ECGenParameterSpec(curveName);
67+
ECGenParameterSpec spec = new ECGenParameterSpec(this.curve.getCurveName());
8968
try {
9069
generator.initialize(spec);
9170
} catch (InvalidAlgorithmParameterException e) {
9271
throw new RuntimeException(e);
9372
}
9473
this.keyPair = generator.generateKeyPair();
95-
this.curveName = curveName;
96-
}
97-
98-
public ECKeyPair(ECPublicKey publicKey, ECPrivateKey privateKey, String curveName) {
99-
this.keyPair = new KeyPair(publicKey, privateKey);
100-
this.curveName = curveName;
10174
}
10275

10376
public ECPublicKey getPublicKey() {
@@ -108,17 +81,8 @@ public ECPrivateKey getPrivateKey() {
10881
return (ECPrivateKey) this.keyPair.getPrivate();
10982
}
11083

111-
public static int getECKeySize(String curveName) {
112-
if (curveName.equalsIgnoreCase(NanoTDFECCurve.SECP256R1.toString()) ||
113-
curveName.equalsIgnoreCase(NanoTDFECCurve.PRIME256V1.toString())) {
114-
return 32;
115-
} else if (curveName.equalsIgnoreCase(NanoTDFECCurve.SECP384R1.toString())) {
116-
return 48;
117-
} else if (curveName.equalsIgnoreCase(NanoTDFECCurve.SECP521R1.toString())) {
118-
return 66;
119-
} else {
120-
throw new IllegalArgumentException("Unsupported ECC algorithm.");
121-
}
84+
NanoTDFType.ECCurve getCurve() {
85+
return this.curve;
12286
}
12387

12488
public String publicKeyInPEMFormat() {
@@ -155,10 +119,6 @@ public int keySize() {
155119
return this.keyPair.getPrivate().getEncoded().length * 8;
156120
}
157121

158-
public String curveName() {
159-
return this.curveName;
160-
}
161-
162122
public byte[] compressECPublickey() {
163123
return ((ECPublicKey) this.keyPair.getPublic()).getQ().getEncoded(true);
164124
}

sdk/src/main/java/io/opentdf/platform/sdk/Header.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public Header(ByteBuffer buffer) {
2626
this.payloadConfig = new SymmetricAndPayloadConfig(buffer.get());
2727
this.policyInfo = new PolicyInfo(buffer, this.eccMode);
2828

29-
int compressedPubKeySize = ECCMode.getECCompressedPubKeySize(this.eccMode.getEllipticCurveType());
29+
int compressedPubKeySize = this.eccMode.getCurve().getCompressedPubKeySize();
3030
this.ephemeralKey = new byte[compressedPubKeySize];
3131
buffer.get(this.ephemeralKey);
3232
}
@@ -79,10 +79,10 @@ public PolicyInfo getPolicyInfo() {
7979
}
8080

8181
public void setEphemeralKey(byte[] bytes) {
82-
if (bytes.length < eccMode.getECCompressedPubKeySize(eccMode.getEllipticCurveType())) {
82+
if (bytes.length < eccMode.getCurve().getCompressedPubKeySize()) {
8383
throw new IllegalArgumentException("Failed to read ephemeral key - invalid buffer size.");
8484
}
85-
ephemeralKey = Arrays.copyOf(bytes, eccMode.getECCompressedPubKeySize(eccMode.getEllipticCurveType()));
85+
ephemeralKey = Arrays.copyOf(bytes, eccMode.getCurve().getCompressedPubKeySize());
8686
}
8787

8888
public byte[] getEphemeralKey() {

sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import io.opentdf.platform.sdk.SDK.KasBadRequestException;
2222

2323
import okhttp3.OkHttpClient;
24+
import org.slf4j.Logger;
25+
import org.slf4j.LoggerFactory;
2426

2527
import java.security.MessageDigest;
2628
import java.security.NoSuchAlgorithmException;
@@ -49,6 +51,8 @@ class KASClient implements SDK.KAS {
4951
private String clientPublicKey;
5052
private KASKeyCache kasKeyCache;
5153

54+
private static final Logger log = LoggerFactory.getLogger(KASClient.class);
55+
5256
/***
5357
* A client that communicates with KAS
5458
*
@@ -69,7 +73,9 @@ class KASClient implements SDK.KAS {
6973

7074
@Override
7175
public KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve) {
72-
var req = PublicKeyRequest.newBuilder().setAlgorithm(format("ec:%s", curve.toString())).build();
76+
log.debug("retrieving public key with kasinfo = [{}]", kasInfo);
77+
78+
var req = PublicKeyRequest.newBuilder().setAlgorithm(curve.getPlatformCurveName()).build();
7379
var r = getStub(kasInfo.URL).publicKeyBlocking(req, Collections.emptyMap()).execute();
7480
PublicKeyResponse res;
7581
try {
@@ -147,10 +153,9 @@ static class NanoTDFRewrapRequestBody {
147153
@Override
148154
public byte[] unwrap(Manifest.KeyAccess keyAccess, String policy, KeyType sessionKeyType) {
149155
ECKeyPair ecKeyPair = null;
150-
151156
if (sessionKeyType.isEc()) {
152-
var curveName = sessionKeyType.getCurveName();
153-
ecKeyPair = new ECKeyPair(curveName, ECKeyPair.ECAlgorithm.ECDH);
157+
var curve = sessionKeyType.getECCurve();
158+
ecKeyPair = new ECKeyPair(curve, ECKeyPair.ECAlgorithm.ECDH);
154159
clientPublicKey = ecKeyPair.publicKeyInPEMFormat();
155160
} else {
156161
// Initialize the RSA key pair only once and reuse it for future unwrap operations
@@ -198,7 +203,7 @@ public byte[] unwrap(Manifest.KeyAccess keyAccess, String policy, KeyType sessi
198203
}
199204

200205
var wrappedKey = response.getEntityWrappedKey().toByteArray();
201-
if (sessionKeyType != KeyType.RSA2048Key) {
206+
if (sessionKeyType.isEc()) {
202207

203208
if (ecKeyPair == null) {
204209
throw new SDKException("ECKeyPair is null. Unable to proceed with the unwrap operation.");
@@ -219,7 +224,7 @@ public byte[] unwrap(Manifest.KeyAccess keyAccess, String policy, KeyType sessi
219224
}
220225

221226
public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kasURL) {
222-
ECKeyPair keyPair = new ECKeyPair(curve.toString(), ECKeyPair.ECAlgorithm.ECDH);
227+
ECKeyPair keyPair = new ECKeyPair(curve, ECKeyPair.ECAlgorithm.ECDH);
223228

224229
NanoTDFKeyAccess keyAccess = new NanoTDFKeyAccess();
225230
keyAccess.header = header;
@@ -228,7 +233,7 @@ public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kas
228233
keyAccess.protocol = "kas";
229234

230235
NanoTDFRewrapRequestBody body = new NanoTDFRewrapRequestBody();
231-
body.algorithm = format("ec:%s", curve.toString());
236+
body.algorithm = format("ec:%s", curve.getCurveName());
232237
body.clientPublicKey = keyPair.publicKeyInPEMFormat();
233238
body.keyAccess = keyAccess;
234239

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,40 @@
11
package io.opentdf.platform.sdk;
22

3+
import javax.annotation.Nonnull;
4+
5+
import static io.opentdf.platform.sdk.NanoTDFType.ECCurve.SECP256R1;
6+
import static io.opentdf.platform.sdk.NanoTDFType.ECCurve.SECP384R1;
7+
import static io.opentdf.platform.sdk.NanoTDFType.ECCurve.SECP521R1;
8+
39
public enum KeyType {
410
RSA2048Key("rsa:2048"),
5-
EC256Key("ec:secp256r1"),
6-
EC384Key("ec:secp384r1"),
7-
EC521Key("ec:secp521r1");
11+
EC256Key("ec:secp256r1", SECP256R1),
12+
EC384Key("ec:secp384r1", SECP384R1),
13+
EC521Key("ec:secp521r1", SECP521R1);
814

915
private final String keyType;
16+
private final NanoTDFType.ECCurve curve;
1017

11-
KeyType(String keyType) {
18+
KeyType(String keyType, NanoTDFType.ECCurve ecCurve) {
1219
this.keyType = keyType;
20+
this.curve = ecCurve;
1321
}
1422

15-
@Override
16-
public String toString() {
17-
return keyType;
23+
KeyType(String keyType) {
24+
this(keyType, null);
1825
}
1926

20-
public String getCurveName() {
21-
switch (this) {
22-
case EC256Key:
23-
return "secp256r1";
24-
case EC384Key:
25-
return "secp384r1";
26-
case EC521Key:
27-
return "secp521r1";
28-
default:
29-
throw new IllegalArgumentException("Unsupported key type: " + this);
27+
@Nonnull
28+
NanoTDFType.ECCurve getECCurve() {
29+
if (!isEc()) {
30+
throw new IllegalStateException("This key type does not have an ECCurve associated with it: " + keyType);
3031
}
32+
return curve;
33+
}
34+
35+
@Override
36+
public String toString() {
37+
return keyType;
3138
}
3239

3340
public static KeyType fromString(String keyType) {
@@ -40,6 +47,6 @@ public static KeyType fromString(String keyType) {
4047
}
4148

4249
public boolean isEc() {
43-
return this != RSA2048Key;
50+
return this.curve != null;
4451
}
4552
}

0 commit comments

Comments
 (0)