Skip to content

Commit e71cdcd

Browse files
author
royb
committed
Update SNTRUPrime KEMSpi for jdk21 (only tested generic)
1 parent 5c8caa7 commit e71cdcd

File tree

5 files changed

+179
-234
lines changed

5 files changed

+179
-234
lines changed

prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java

-85
This file was deleted.

prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java

+40-19
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
22

3-
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
43
import org.bouncycastle.crypto.InvalidCipherTextException;
54
import org.bouncycastle.crypto.Wrapper;
6-
import org.bouncycastle.crypto.params.KeyParameter;
75
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
86
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMExtractor;
97
import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
@@ -14,11 +12,8 @@
1412
import javax.crypto.SecretKey;
1513
import javax.crypto.spec.SecretKeySpec;
1614
import java.security.InvalidKeyException;
17-
import java.security.NoSuchAlgorithmException;
1815
import java.util.Objects;
1916

20-
import static org.bouncycastle.pqc.jcajce.provider.Util.makeKeyBytes;
21-
2217
class SNTRUPrimeDecapsulatorSpi
2318
implements KEMSpi.DecapsulatorSpi
2419
{
@@ -47,33 +42,59 @@ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, Strin
4742
throw new DecapsulateException("incorrect encapsulation size");
4843
}
4944

50-
KTSParameterSpec.Builder builder = new KTSParameterSpec.Builder(parameterSpec.getKeyAlgorithmName(), parameterSpec.getKeySize());
45+
// if algorithm is Generic then use parameterSpec to wrap key
46+
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
47+
algorithm.equals("Generic"))
48+
{
49+
algorithm = parameterSpec.getKeyAlgorithmName();
50+
}
5151

52-
if (!algorithm.equals("Generic"))
52+
// check spec algorithm mismatch provided algorithm
53+
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
54+
!parameterSpec.getKeyAlgorithmName().equals(algorithm))
5355
{
54-
//TODO:
55-
// builder.withKdfAlgorithm(AlgorithmIdentifier.getInstance(algorithm));
56+
throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm);
5657
}
57-
KTSParameterSpec spec = builder.build();
5858

59-
byte[] secret = kemExt.extractSecret(encapsulation);
59+
// Only use KDF when ktsParameterSpec is provided
60+
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
61+
boolean wrapKey = !(parameterSpec.getKeyAlgorithmName().equals("Generic") && algorithm.equals("Generic"));
6062

61-
byte[] kdfKey = Arrays.copyOfRange(secret, from, to);
63+
byte[] secret = kemExt.extractSecret(encapsulation);
64+
byte[] secretKey = Arrays.copyOfRange(secret, from, to);
6265

63-
try
64-
{
65-
return new SecretKeySpec(makeKeyBytes(spec, kdfKey), algorithm);
66-
}
67-
catch (InvalidKeyException e)
66+
if (wrapKey)
6867
{
69-
throw new RuntimeException(e);
68+
try
69+
{
70+
KTSParameterSpec spec = parameterSpec;
71+
// Generate a new ktsParameterSpec if spec is generic but algorithm is not generic
72+
if (parameterSpec.getKeyAlgorithmName().equals("Generic"))
73+
{
74+
spec = new KTSParameterSpec.Builder(algorithm, secretKey.length * 8).withNoKdf().build();
75+
}
76+
77+
Wrapper kWrap = WrapUtil.getKeyUnwrapper(spec, secretKey);
78+
secretKey = kWrap.unwrap(secretKey, 0, secretKey.length);
79+
80+
}
81+
catch (InvalidCipherTextException e)
82+
{
83+
throw new RuntimeException(e);
84+
}
85+
catch (InvalidKeyException e)
86+
{
87+
throw new RuntimeException(e);
88+
}
89+
7090
}
91+
return new SecretKeySpec(secretKey, algorithm);
7192
}
7293

7394
@Override
7495
public int engineSecretSize()
7596
{
76-
return privateKey.getKeyParams().getParameters().getSessionKeySize() / 8;
97+
return parameterSpec.getKeySize() / 8;
7798
}
7899

79100
@Override

prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java

+38-23
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
22

3-
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
4-
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
53
import org.bouncycastle.crypto.SecretWithEncapsulation;
64
import org.bouncycastle.crypto.Wrapper;
7-
import org.bouncycastle.crypto.params.KeyParameter;
85
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
96
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMGenerator;
107
import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
@@ -13,68 +10,86 @@
1310
import javax.crypto.KEM;
1411
import javax.crypto.KEMSpi;
1512
import javax.crypto.spec.SecretKeySpec;
16-
import java.security.InvalidAlgorithmParameterException;
1713
import java.security.InvalidKeyException;
18-
import java.security.KeyPair;
1914
import java.security.SecureRandom;
2015
import java.util.Objects;
2116

22-
import static org.bouncycastle.pqc.jcajce.provider.Util.makeKeyBytes;
23-
2417
class SNTRUPrimeEncapsulatorSpi
2518
implements KEMSpi.EncapsulatorSpi
2619
{
2720
private final BCSNTRUPrimePublicKey publicKey;
2821
private final KTSParameterSpec parameterSpec;
29-
private final SecureRandom random;
3022
private final SNTRUPrimeKEMGenerator kemGen;
3123

3224

3325
public SNTRUPrimeEncapsulatorSpi(BCSNTRUPrimePublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random)
3426
{
3527
this.publicKey = publicKey;
3628
this.parameterSpec = parameterSpec;
37-
this.random = random;
3829

3930
kemGen = new SNTRUPrimeKEMGenerator(random);
4031
}
4132

4233
@Override
4334
public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
4435
{
45-
Objects.checkFromToIndex(from, to, engineEncapsulationSize());
36+
Objects.checkFromToIndex(from, to, engineSecretSize());
4637
Objects.requireNonNull(algorithm, "null algorithm");
4738

48-
KTSParameterSpec.Builder builder = new KTSParameterSpec.Builder(parameterSpec.getKeyAlgorithmName(), parameterSpec.getKeySize());
39+
// if algorithm is Generic then use parameterSpec to wrap key
40+
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
41+
algorithm.equals("Generic"))
42+
{
43+
algorithm = parameterSpec.getKeyAlgorithmName();
44+
}
4945

50-
if (!algorithm.equals("Generic"))
46+
// check spec algorithm mismatch provided algorithm
47+
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
48+
!parameterSpec.getKeyAlgorithmName().equals(algorithm))
5149
{
52-
//TODO:
53-
// builder.withKdfAlgorithm(AlgorithmIdentifier.getInstance(algorithm));
50+
throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm);
5451
}
55-
KTSParameterSpec spec = builder.build();
52+
53+
// Only use KDF when ktsParameterSpec is provided
54+
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
55+
boolean wrapKey = !(parameterSpec.getKeyAlgorithmName().equals("Generic") && algorithm.equals("Generic"));
5656

5757
SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams());
5858

5959
byte[] encapsulation = secEnc.getEncapsulation();
6060
byte[] secret = secEnc.getSecret();
6161

62-
byte[] kdfKey = Arrays.copyOfRange(secret, from, to);
62+
byte[] secretKey = Arrays.copyOfRange(secret, from, to);
6363

64-
try
64+
if (wrapKey)
6565
{
66-
return new KEM.Encapsulated(new SecretKeySpec(makeKeyBytes(spec, kdfKey), algorithm), encapsulation , null);
67-
}
68-
catch (InvalidKeyException e)
69-
{
70-
throw new RuntimeException(e);
66+
try
67+
{
68+
KTSParameterSpec spec = parameterSpec;
69+
// Generate a new ktsParameterSpec if spec is generic but algorithm is not generic
70+
if (parameterSpec.getKeyAlgorithmName().equals("Generic"))
71+
{
72+
spec = new KTSParameterSpec.Builder(algorithm, secretKey.length * 8).withNoKdf().build();
73+
}
74+
75+
Wrapper kWrap = WrapUtil.getKeyWrapper(spec, secret);
76+
secretKey = kWrap.wrap(secretKey, 0, secretKey.length);
77+
// secretKey = Arrays.concatenate(encapsulation, kWrap.wrap(secretKey, 0, secretKey.length));
78+
}
79+
catch (InvalidKeyException e)
80+
{
81+
throw new RuntimeException(e);
82+
}
7183
}
84+
85+
return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, parameterSpec.getOtherInfo());
86+
7287
}
7388

7489
@Override
7590
public int engineSecretSize()
7691
{
77-
return publicKey.getKeyParams().getParameters().getSessionKeySize() / 8;
92+
return parameterSpec.getKeySize() / 8;
7893
}
7994

8095
@Override

prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java

+4-14
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
11
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
22

3-
import org.bouncycastle.crypto.CryptoServicesRegistrar;
4-
import org.bouncycastle.crypto.SecretWithEncapsulation;
5-
import org.bouncycastle.crypto.Wrapper;
6-
import org.bouncycastle.crypto.params.KeyParameter;
73
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
8-
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMGenerator;
9-
import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
10-
import org.bouncycastle.util.Arrays;
114

12-
import javax.crypto.IllegalBlockSizeException;
135
import javax.crypto.KEMSpi;
14-
import javax.security.auth.DestroyFailedException;
15-
import java.security.AlgorithmParameters;
166
import java.security.InvalidAlgorithmParameterException;
177
import java.security.InvalidKeyException;
188
import java.security.PrivateKey;
@@ -33,8 +23,8 @@ public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParam
3323
}
3424
if (spec == null)
3525
{
36-
// TODO: default should probably use shake.
37-
spec = new KTSParameterSpec.Builder("AES-KWP", 256).build();
26+
// Do not wrap key, no KDF
27+
spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build();
3828
}
3929
if (!(spec instanceof KTSParameterSpec))
4030
{
@@ -56,8 +46,8 @@ public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmPar
5646
}
5747
if (spec == null)
5848
{
59-
// TODO: default should probably use shake.
60-
spec = new KTSParameterSpec.Builder("AES-KWP", 256).build();
49+
// Do not unwrap key, no KDF
50+
spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build();
6151
}
6252
if (!(spec instanceof KTSParameterSpec))
6353
{

0 commit comments

Comments
 (0)