Skip to content

Commit bd6e70c

Browse files
author
royb
committed
Fixed SNTRUPrime KEMSpi for jdk21, added more tests
1 parent e71cdcd commit bd6e70c

File tree

4 files changed

+204
-136
lines changed

4 files changed

+204
-136
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package org.bouncycastle.pqc.jcajce.provider;
2+
3+
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
4+
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
5+
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
6+
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
7+
import org.bouncycastle.crypto.DerivationFunction;
8+
import org.bouncycastle.crypto.Digest;
9+
import org.bouncycastle.crypto.Xof;
10+
import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
11+
import org.bouncycastle.crypto.digests.SHA256Digest;
12+
import org.bouncycastle.crypto.digests.SHA512Digest;
13+
import org.bouncycastle.crypto.digests.SHAKEDigest;
14+
import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
15+
import org.bouncycastle.crypto.params.KDFParameters;
16+
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
17+
18+
import java.security.InvalidKeyException;
19+
20+
public class Util
21+
{
22+
public static byte[] makeKeyBytes(KTSParameterSpec ktsSpec, byte[] secret)
23+
throws InvalidKeyException
24+
{
25+
AlgorithmIdentifier kdfAlgorithm = ktsSpec.getKdfAlgorithm();
26+
byte[] otherInfo = ktsSpec.getOtherInfo();
27+
byte[] keyBytes = new byte[(ktsSpec.getKeySize() + 7) / 8];
28+
29+
if (X9ObjectIdentifiers.id_kdf_kdf2.equals(kdfAlgorithm.getAlgorithm()))
30+
{
31+
AlgorithmIdentifier digAlg = AlgorithmIdentifier.getInstance(kdfAlgorithm.getParameters());
32+
DerivationFunction kdf = new KDF2BytesGenerator(getDigest(digAlg.getAlgorithm()));
33+
34+
kdf.init(new KDFParameters(secret, otherInfo));
35+
36+
kdf.generateBytes(keyBytes, 0, keyBytes.length);
37+
}
38+
else if (X9ObjectIdentifiers.id_kdf_kdf3.equals(kdfAlgorithm.getAlgorithm()))
39+
{
40+
AlgorithmIdentifier digAlg = AlgorithmIdentifier.getInstance(kdfAlgorithm.getParameters());
41+
DerivationFunction kdf = new ConcatenationKDFGenerator(getDigest(digAlg.getAlgorithm()));
42+
43+
kdf.init(new KDFParameters(secret, otherInfo));
44+
45+
kdf.generateBytes(keyBytes, 0, keyBytes.length);
46+
}
47+
else if (NISTObjectIdentifiers.id_shake256.equals(kdfAlgorithm.getAlgorithm()))
48+
{
49+
Xof xof = new SHAKEDigest(256);
50+
51+
xof.update(secret, 0, secret.length);
52+
xof.update(otherInfo, 0, otherInfo.length);
53+
54+
xof.doFinal(keyBytes, 0, keyBytes.length);
55+
}
56+
else
57+
{
58+
throw new InvalidKeyException("Unrecognized KDF: " + kdfAlgorithm.getAlgorithm());
59+
}
60+
61+
return keyBytes;
62+
}
63+
64+
static Digest getDigest(ASN1ObjectIdentifier oid)
65+
{
66+
if (oid.equals(NISTObjectIdentifiers.id_sha256))
67+
{
68+
return new SHA256Digest();
69+
}
70+
if (oid.equals(NISTObjectIdentifiers.id_sha512))
71+
{
72+
return new SHA512Digest();
73+
}
74+
if (oid.equals(NISTObjectIdentifiers.id_shake128))
75+
{
76+
return new SHAKEDigest(128);
77+
}
78+
if (oid.equals(NISTObjectIdentifiers.id_shake256))
79+
{
80+
return new SHAKEDigest(256);
81+
}
82+
83+
throw new IllegalArgumentException("unrecognized digest OID: " + oid);
84+
}
85+
}

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

+6-21
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
22

3-
import org.bouncycastle.crypto.InvalidCipherTextException;
4-
import org.bouncycastle.crypto.Wrapper;
53
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
64
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMExtractor;
7-
import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
5+
import org.bouncycastle.pqc.jcajce.provider.Util;
86
import org.bouncycastle.util.Arrays;
97

108
import javax.crypto.DecapsulateException;
@@ -58,36 +56,23 @@ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, Strin
5856

5957
// Only use KDF when ktsParameterSpec is provided
6058
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
61-
boolean wrapKey = !(parameterSpec.getKeyAlgorithmName().equals("Generic") && algorithm.equals("Generic"));
59+
boolean useKDF = parameterSpec.getKdfAlgorithm() != null;
6260

6361
byte[] secret = kemExt.extractSecret(encapsulation);
64-
byte[] secretKey = Arrays.copyOfRange(secret, from, to);
6562

66-
if (wrapKey)
63+
if (useKDF)
6764
{
6865
try
6966
{
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);
67+
secret = Util.makeKeyBytes(parameterSpec, secret);
8468
}
8569
catch (InvalidKeyException e)
8670
{
8771
throw new RuntimeException(e);
8872
}
89-
9073
}
74+
byte[] secretKey = Arrays.copyOfRange(secret, from, to);
75+
9176
return new SecretKeySpec(secretKey, algorithm);
9277
}
9378

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

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

33
import org.bouncycastle.crypto.SecretWithEncapsulation;
4-
import org.bouncycastle.crypto.Wrapper;
54
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
65
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMGenerator;
7-
import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
6+
import org.bouncycastle.pqc.jcajce.provider.Util;
87
import org.bouncycastle.util.Arrays;
98

109
import javax.crypto.KEM;
@@ -52,36 +51,29 @@ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
5251

5352
// Only use KDF when ktsParameterSpec is provided
5453
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
55-
boolean wrapKey = !(parameterSpec.getKeyAlgorithmName().equals("Generic") && algorithm.equals("Generic"));
54+
boolean useKDF = parameterSpec.getKdfAlgorithm() != null;
5655

5756
SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams());
5857

5958
byte[] encapsulation = secEnc.getEncapsulation();
6059
byte[] secret = secEnc.getSecret();
6160

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

64-
if (wrapKey)
63+
if (useKDF)
6564
{
6665
try
6766
{
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));
67+
secret = Util.makeKeyBytes(parameterSpec, secret);
7868
}
7969
catch (InvalidKeyException e)
8070
{
8171
throw new RuntimeException(e);
8272
}
8373
}
8474

75+
secretKey = Arrays.copyOfRange(secret, from, to);
76+
8577
return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, parameterSpec.getOtherInfo());
8678

8779
}

0 commit comments

Comments
 (0)