Skip to content

Commit a5cd7f0

Browse files
committed
added KDF support to Generate/Extract
1 parent 697a3a0 commit a5cd7f0

File tree

18 files changed

+294
-268
lines changed

18 files changed

+294
-268
lines changed

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLDSA.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ public void configure(ConfigurableProvider provider)
2222
{
2323
provider.addAlgorithm("KeyFactory.ML-DSA", PREFIX + "MLDSAKeyFactorySpi$Pure");
2424
provider.addAlgorithm("KeyPairGenerator.ML-DSA", PREFIX + "MLDSAKeyPairGeneratorSpi$Pure");
25+
provider.addAlgorithm("Alg.Alias.KeyFactory.MLDSA", "ML-DSA");
26+
provider.addAlgorithm("Alg.Alias.KeyPairGenerator.MLDSA", "ML-DSA");
2527
provider.addAlgorithm("KeyFactory.HASH-ML-DSA", PREFIX + "MLDSAKeyFactorySpi$Hash");
2628
provider.addAlgorithm("KeyPairGenerator.HASH-ML-DSA", PREFIX + "MLDSAKeyPairGeneratorSpi$Hash");
29+
provider.addAlgorithm("Alg.Alias.KeyFactory.SHA512WITHMLDSA", "HASH-ML-DSA");
30+
provider.addAlgorithm("Alg.Alias.KeyPairGenerator.SHA512WITHMLDSA", "HASH-ML-DSA");
2731

2832
addKeyFactoryAlgorithm(provider, "ML-DSA-44", PREFIX + "MLDSAKeyFactorySpi$MLDSA44", NISTObjectIdentifiers.id_ml_dsa_44, new MLDSAKeyFactorySpi.MLDSA44());
2933
addKeyFactoryAlgorithm(provider, "ML-DSA-65", PREFIX + "MLDSAKeyFactorySpi$MLDSA65", NISTObjectIdentifiers.id_ml_dsa_65, new MLDSAKeyFactorySpi.MLDSA65());

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLKEM.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ public Mappings()
2121
public void configure(ConfigurableProvider provider)
2222
{
2323
provider.addAlgorithm("KeyFactory.ML-KEM", PREFIX + "MLKEMKeyFactorySpi");
24+
provider.addAlgorithm("Alg.Alias.KeyFactory.MLKEM", "ML-KEM");
2425

2526
addKeyFactoryAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMKeyFactorySpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512, new MLKEMKeyFactorySpi.MLKEM512());
2627
addKeyFactoryAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMKeyFactorySpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768, new MLKEMKeyFactorySpi.MLKEM768());
2728
addKeyFactoryAlgorithm(provider, "ML-KEM-1024", PREFIX + "MLKEMKeyFactorySpi$MLKEM1024", NISTObjectIdentifiers.id_alg_ml_kem_1024, new MLKEMKeyFactorySpi.MLKEM1024());
2829

29-
3030
provider.addAlgorithm("KeyPairGenerator.ML-KEM", PREFIX + "MLKEMKeyPairGeneratorSpi");
31+
provider.addAlgorithm("Alg.Alias.KeyPairGenerator.MLKEM", "ML-KEM");
3132

3233
addKeyPairGeneratorAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMKeyPairGeneratorSpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512);
3334
addKeyPairGeneratorAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMKeyPairGeneratorSpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768);
@@ -42,7 +43,7 @@ public void configure(ConfigurableProvider provider)
4243
AsymmetricKeyInfoConverter keyFact = new MLKEMKeyFactorySpi();
4344

4445
provider.addAlgorithm("Cipher.ML-KEM", PREFIX + "MLKEMCipherSpi$Base");
45-
provider.addAlgorithm("Alg.Alias.Cipher." + (ASN1ObjectIdentifier) null, "ML-KEM");
46+
provider.addAlgorithm("Alg.Alias.Cipher.MLKEM", "ML-KEM");
4647

4748
addCipherAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMCipherSpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512);
4849
addCipherAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMCipherSpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768);

prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.bouncycastle.pqc.crypto.mlkem.MLKEMExtractor;
1818
import org.bouncycastle.pqc.crypto.mlkem.MLKEMGenerator;
1919
import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters;
20+
import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil;
2021
import org.bouncycastle.util.Arrays;
2122

2223
public class MLKEMKeyGeneratorSpi
@@ -93,7 +94,8 @@ protected SecretKey engineGenerateKey()
9394
SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(pubKey.getKeyParams());
9495

9596
byte[] sharedSecret = secEnc.getSecret();
96-
byte[] secret = Arrays.copyOfRange(sharedSecret, 0, (genSpec.getKeySize() + 7) / 8);
97+
98+
byte[] secret = KdfUtil.makeKeyBytes(genSpec, sharedSecret);
9799

98100
Arrays.clear(sharedSecret);
99101

@@ -117,7 +119,7 @@ protected SecretKey engineGenerateKey()
117119

118120
byte[] encapsulation = extSpec.getEncapsulation();
119121
byte[] sharedSecret = kemExt.extractSecret(encapsulation);
120-
byte[] secret = Arrays.copyOfRange(sharedSecret, 0, (extSpec.getKeySize() + 7) / 8);
122+
byte[] secret = KdfUtil.makeKeyBytes(extSpec, sharedSecret);
121123

122124
Arrays.clear(sharedSecret);
123125

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
11
package org.bouncycastle.jcajce.spec;
22

33
import java.security.PrivateKey;
4+
import java.security.PublicKey;
45
import java.security.spec.AlgorithmParameterSpec;
56

7+
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
8+
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
9+
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
610
import org.bouncycastle.util.Arrays;
711

812
public class KEMExtractSpec
13+
extends KEMKDFSpec
914
implements AlgorithmParameterSpec
1015
{
16+
private static final byte[] EMPTY_OTHER_INFO = new byte[0];
17+
private static AlgorithmIdentifier DefKdf = new AlgorithmIdentifier(X9ObjectIdentifiers.id_kdf_kdf3, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256));
18+
1119
private final PrivateKey privateKey;
1220
private final byte[] encapsulation;
13-
private final String keyAlgorithmName;
14-
private final int keySizeInBits;
21+
22+
private KEMExtractSpec(PrivateKey privateKey, byte[] encapsulation, String keyAlgorithmName, int keySizeInBits, AlgorithmIdentifier kdfAlgorithm, byte[] otherInfo)
23+
{
24+
super(kdfAlgorithm, otherInfo, keyAlgorithmName, keySizeInBits);
25+
26+
this.privateKey = privateKey;
27+
this.encapsulation = Arrays.clone(encapsulation);
28+
}
1529

1630
public KEMExtractSpec(PrivateKey privateKey, byte[] encapsulation, String keyAlgorithmName)
1731
{
@@ -20,10 +34,7 @@ public KEMExtractSpec(PrivateKey privateKey, byte[] encapsulation, String keyAlg
2034

2135
public KEMExtractSpec(PrivateKey privateKey, byte[] encapsulation, String keyAlgorithmName, int keySizeInBits)
2236
{
23-
this.privateKey = privateKey;
24-
this.encapsulation = Arrays.clone(encapsulation);
25-
this.keyAlgorithmName = keyAlgorithmName;
26-
this.keySizeInBits = keySizeInBits;
37+
this(privateKey, encapsulation, keyAlgorithmName, keySizeInBits, DefKdf, EMPTY_OTHER_INFO);
2738
}
2839

2940
public byte[] getEncapsulation()
@@ -35,14 +46,4 @@ public PrivateKey getPrivateKey()
3546
{
3647
return privateKey;
3748
}
38-
39-
public String getKeyAlgorithmName()
40-
{
41-
return keyAlgorithmName;
42-
}
43-
44-
public int getKeySize()
45-
{
46-
return keySizeInBits;
47-
}
4849
}

prov/src/main/java/org/bouncycastle/jcajce/spec/KEMGenerateSpec.java

Lines changed: 94 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,117 @@
33
import java.security.PublicKey;
44
import java.security.spec.AlgorithmParameterSpec;
55

6+
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
7+
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
8+
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
9+
import org.bouncycastle.util.Arrays;
10+
611
public class KEMGenerateSpec
12+
extends KEMKDFSpec
713
implements AlgorithmParameterSpec
814
{
9-
private final PublicKey publicKey;
10-
private final String keyAlgorithmName;
11-
private final int keySizeInBits;
15+
private static final byte[] EMPTY_OTHER_INFO = new byte[0];
16+
private static AlgorithmIdentifier DefKdf = new AlgorithmIdentifier(X9ObjectIdentifiers.id_kdf_kdf3, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256));
1217

13-
public KEMGenerateSpec(PublicKey publicKey, String keyAlgorithmName)
18+
/**
19+
* Builder class for creating a KTSParameterSpec.
20+
*/
21+
public static final class Builder
1422
{
15-
this(publicKey, keyAlgorithmName, 256);
23+
private final PublicKey publicKey;
24+
private final String algorithmName;
25+
private final int keySizeInBits;
26+
27+
private AlgorithmIdentifier kdfAlgorithm;
28+
private byte[] otherInfo;
29+
30+
/**
31+
* Basic builder.
32+
*
33+
* @param publicKey the public key to use for encapsulation/secret generation.
34+
* @param keyAlgorithmName the algorithm name for the secret key we want to generate.
35+
* @param keySizeInBits the size of the wrapping key we want to produce in bits.
36+
*/
37+
public Builder(PublicKey publicKey, String keyAlgorithmName, int keySizeInBits)
38+
{
39+
this.publicKey = publicKey;
40+
this.algorithmName = keyAlgorithmName;
41+
this.keySizeInBits = keySizeInBits;
42+
this.kdfAlgorithm = new AlgorithmIdentifier(X9ObjectIdentifiers.id_kdf_kdf3, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256));
43+
this.otherInfo = EMPTY_OTHER_INFO;
44+
}
45+
46+
/**
47+
* Use the shared secret directly for key wrap generation.
48+
*
49+
* @return the current Builder instance.
50+
*/
51+
public Builder withNoKdf()
52+
{
53+
this.kdfAlgorithm = null;
54+
55+
return this;
56+
}
57+
58+
/**
59+
* Set the KDF algorithm and digest algorithm for wrap key generation. The default KDF is X9.44 KDF-3, also
60+
* known as the NIST concatenation KDF.
61+
*
62+
* @param kdfAlgorithm the KDF algorithm to apply.
63+
* @return the current Builder instance.
64+
*/
65+
public Builder withKdfAlgorithm(AlgorithmIdentifier kdfAlgorithm)
66+
{
67+
this.kdfAlgorithm = kdfAlgorithm;
68+
69+
return this;
70+
}
71+
72+
/**
73+
* Set the OtherInfo to use with the KDF. The default OtherInfo is a zero length byte[].
74+
*
75+
* @param otherInfo the other info to use.
76+
* @return the current Builder instance.
77+
*/
78+
public Builder withOtherInfo(byte[] otherInfo)
79+
{
80+
this.otherInfo = (otherInfo == null) ? EMPTY_OTHER_INFO : Arrays.clone(otherInfo);
81+
82+
return this;
83+
}
84+
85+
/**
86+
* Build the new parameter spec.
87+
*
88+
* @return a new parameter spec configured according to the builder state.
89+
*/
90+
public KEMGenerateSpec build()
91+
{
92+
return new KEMGenerateSpec(publicKey, algorithmName, keySizeInBits, kdfAlgorithm, otherInfo);
93+
}
1694
}
1795

18-
public KEMGenerateSpec(PublicKey publicKey, String keyAlgorithmName, int keySizeInBits)
96+
private final PublicKey publicKey;
97+
98+
private KEMGenerateSpec(PublicKey publicKey, String keyAlgorithmName, int keySizeInBits, AlgorithmIdentifier kdfAlgorithm, byte[] otherInfo)
1999
{
100+
super(kdfAlgorithm, otherInfo, keyAlgorithmName, keySizeInBits);
101+
20102
this.publicKey = publicKey;
21-
this.keyAlgorithmName = keyAlgorithmName;
22-
this.keySizeInBits = keySizeInBits;
23103
}
24104

25-
public PublicKey getPublicKey()
105+
public KEMGenerateSpec(PublicKey publicKey, String keyAlgorithmName)
26106
{
27-
return publicKey;
107+
this(publicKey, keyAlgorithmName, 256, DefKdf, EMPTY_OTHER_INFO);
28108
}
29109

30-
public String getKeyAlgorithmName()
110+
public KEMGenerateSpec(PublicKey publicKey, String keyAlgorithmName, int keySizeInBits)
31111
{
32-
return keyAlgorithmName;
112+
this(publicKey, keyAlgorithmName, keySizeInBits, DefKdf, EMPTY_OTHER_INFO);
33113
}
34114

35-
public int getKeySize()
115+
public PublicKey getPublicKey()
36116
{
37-
return keySizeInBits;
117+
return publicKey;
38118
}
39119
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.bouncycastle.jcajce.spec;
2+
3+
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
4+
import org.bouncycastle.util.Arrays;
5+
6+
public class KEMKDFSpec
7+
{
8+
private final String keyAlgorithmName;
9+
private final int keySizeInBits;
10+
private final AlgorithmIdentifier kdfAlgorithm;
11+
private final byte[] otherInfo;
12+
13+
protected KEMKDFSpec(AlgorithmIdentifier kdfAlgorithm, byte[] otherInfo, String keyAlgorithmName, int keySizeInBits)
14+
{
15+
this.keyAlgorithmName = keyAlgorithmName;
16+
this.keySizeInBits = keySizeInBits;
17+
this.kdfAlgorithm = kdfAlgorithm;
18+
this.otherInfo = otherInfo;
19+
}
20+
21+
public String getKeyAlgorithmName()
22+
{
23+
return keyAlgorithmName;
24+
}
25+
26+
public int getKeySize()
27+
{
28+
return keySizeInBits;
29+
}
30+
31+
public AlgorithmIdentifier getKdfAlgorithm()
32+
{
33+
return kdfAlgorithm;
34+
}
35+
36+
public byte[] getOtherInfo()
37+
{
38+
return Arrays.clone(otherInfo);
39+
}
40+
}

prov/src/main/java/org/bouncycastle/jcajce/spec/KTSParameterSpec.java

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,10 @@
1111
* Parameter spec for doing KTS based wrapping via the Cipher API.
1212
*/
1313
public class KTSParameterSpec
14+
extends KEMKDFSpec
1415
implements AlgorithmParameterSpec
1516
{
16-
private final String wrappingKeyAlgorithm;
17-
private final int keySizeInBits;
1817
private final AlgorithmParameterSpec parameterSpec;
19-
private final AlgorithmIdentifier kdfAlgorithm;
20-
private byte[] otherInfo;
2118

2219
/**
2320
* Builder class for creating a KTSParameterSpec.
@@ -111,31 +108,9 @@ protected KTSParameterSpec(
111108
String wrappingKeyAlgorithm, int keySizeInBits,
112109
AlgorithmParameterSpec parameterSpec, AlgorithmIdentifier kdfAlgorithm, byte[] otherInfo)
113110
{
114-
this.wrappingKeyAlgorithm = wrappingKeyAlgorithm;
115-
this.keySizeInBits = keySizeInBits;
116-
this.parameterSpec = parameterSpec;
117-
this.kdfAlgorithm = kdfAlgorithm;
118-
this.otherInfo = otherInfo;
119-
}
111+
super(kdfAlgorithm, otherInfo, wrappingKeyAlgorithm, keySizeInBits);
120112

121-
/**
122-
* Return the name of the algorithm for the wrapping key this key spec should use.
123-
*
124-
* @return the key algorithm.
125-
*/
126-
public String getKeyAlgorithmName()
127-
{
128-
return wrappingKeyAlgorithm;
129-
}
130-
131-
/**
132-
* Return the size of the key (in bits) for the wrapping key this key spec should use.
133-
*
134-
* @return length in bits of the key to be calculated.
135-
*/
136-
public int getKeySize()
137-
{
138-
return keySizeInBits;
113+
this.parameterSpec = parameterSpec;
139114
}
140115

141116
/**
@@ -147,24 +122,4 @@ public AlgorithmParameterSpec getParameterSpec()
147122
{
148123
return parameterSpec;
149124
}
150-
151-
/**
152-
* Return the AlgorithmIdentifier for the KDF to do key derivation after extracting the secret.
153-
*
154-
* @return the AlgorithmIdentifier for the SecretKeyFactory's KDF.
155-
*/
156-
public AlgorithmIdentifier getKdfAlgorithm()
157-
{
158-
return kdfAlgorithm;
159-
}
160-
161-
/**
162-
* Return the otherInfo data for initialising the KDF.
163-
*
164-
* @return the otherInfo data.
165-
*/
166-
public byte[] getOtherInfo()
167-
{
168-
return Arrays.clone(otherInfo);
169-
}
170125
}

0 commit comments

Comments
 (0)