Skip to content

Commit 6ec81e9

Browse files
committed
NTRUPrime: Add missing mappings, fix OID mappings
- unify NTRUPrime mappings using SpiUtil
1 parent b26e96e commit 6ec81e9

File tree

7 files changed

+155
-151
lines changed

7 files changed

+155
-151
lines changed

core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMExtractor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ public class SNTRUPrimeKEMExtractor
1010

1111
public SNTRUPrimeKEMExtractor(SNTRUPrimePrivateKeyParameters privateKey)
1212
{
13+
if (privateKey == null)
14+
{
15+
throw new NullPointerException("'privateKey' cannot be null");
16+
}
17+
1318
this.privateKey = privateKey;
1419
}
1520

prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
55
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
66
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
7+
import org.bouncycastle.jcajce.util.SpiUtil;
78
import org.bouncycastle.pqc.jcajce.provider.ntruprime.NTRULPRimeKeyFactorySpi;
89
import org.bouncycastle.pqc.jcajce.provider.ntruprime.SNTRUPrimeKeyFactorySpi;
910

@@ -27,32 +28,36 @@ public void configure(ConfigurableProvider provider)
2728

2829
AsymmetricKeyInfoConverter keyFact = new NTRULPRimeKeyFactorySpi();
2930

30-
provider.addAlgorithm("Cipher.NTRULPRIME", PREFIX + "NTRULPRimeCipherSpi$Base");
31-
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_ntrulprime, "NTRU");
32-
31+
addCipherAlgorithm(provider, "NTRULPRIME", PREFIX + "NTRULPRimeCipherSpi$Base", BCObjectIdentifiers.pqc_kem_ntrulprime);
32+
3333
registerOid(provider, BCObjectIdentifiers.ntrulpr653, "NTRULPRIME", keyFact);
3434
registerOid(provider, BCObjectIdentifiers.ntrulpr761, "NTRULPRIME", keyFact);
3535
registerOid(provider, BCObjectIdentifiers.ntrulpr857, "NTRULPRIME", keyFact);
3636
registerOid(provider, BCObjectIdentifiers.ntrulpr953, "NTRULPRIME", keyFact);
3737
registerOid(provider, BCObjectIdentifiers.ntrulpr1013, "NTRULPRIME", keyFact);
3838
registerOid(provider, BCObjectIdentifiers.ntrulpr1277, "NTRULPRIME", keyFact);
39-
39+
4040
provider.addAlgorithm("KeyFactory.SNTRUPRIME", PREFIX + "SNTRUPrimeKeyFactorySpi");
4141
provider.addAlgorithm("KeyPairGenerator.SNTRUPRIME", PREFIX + "SNTRUPrimeKeyPairGeneratorSpi");
4242

4343
provider.addAlgorithm("KeyGenerator.SNTRUPRIME", PREFIX + "SNTRUPrimeKeyGeneratorSpi");
4444

4545
keyFact = new SNTRUPrimeKeyFactorySpi();
4646

47-
provider.addAlgorithm("Cipher.SNTRUPRIME", PREFIX + "SNTRUPrimeCipherSpi$Base");
48-
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_sntruprime, "NTRU");
47+
addCipherAlgorithm(provider, "SNTRUPRIME", PREFIX + "SNTRUPrimeCipherSpi$Base", BCObjectIdentifiers.pqc_kem_sntruprime);
4948

5049
registerOid(provider, BCObjectIdentifiers.sntrup653, "SNTRUPRIME", keyFact);
5150
registerOid(provider, BCObjectIdentifiers.sntrup761, "SNTRUPRIME", keyFact);
5251
registerOid(provider, BCObjectIdentifiers.sntrup857, "SNTRUPRIME", keyFact);
5352
registerOid(provider, BCObjectIdentifiers.sntrup953, "SNTRUPRIME", keyFact);
5453
registerOid(provider, BCObjectIdentifiers.sntrup1013, "SNTRUPRIME", keyFact);
5554
registerOid(provider, BCObjectIdentifiers.sntrup1277, "SNTRUPRIME", keyFact);
55+
56+
if (SpiUtil.hasKEM())
57+
{
58+
// TODO Per-parameter-set SPI classes?
59+
addKEMAlgorithm(provider, "SNTRUPRIME", PREFIX + "SNTRUPrimeKEMSpi$SNTRUPrime", BCObjectIdentifiers.pqc_kem_sntruprime);
60+
}
5661
}
5762
}
5863
}

prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java

Lines changed: 0 additions & 61 deletions
This file was deleted.

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

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
22

3-
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
4-
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMExtractor;
5-
import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil;
6-
import org.bouncycastle.util.Arrays;
3+
import java.util.Objects;
74

85
import javax.crypto.DecapsulateException;
96
import javax.crypto.KEMSpi;
107
import javax.crypto.SecretKey;
118
import javax.crypto.spec.SecretKeySpec;
12-
import java.security.InvalidKeyException;
13-
import java.util.Objects;
149

10+
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
11+
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMExtractor;
12+
import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil;
13+
import org.bouncycastle.util.Arrays;
14+
15+
/*
16+
* NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to
17+
* invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same
18+
* time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message."
19+
*/
1520
class SNTRUPrimeDecapsulatorSpi
1621
implements KEMSpi.DecapsulatorSpi
1722
{
18-
BCSNTRUPrimePrivateKey privateKey;
19-
KTSParameterSpec parameterSpec;
20-
21-
SNTRUPrimeKEMExtractor kemExt;
23+
// private final BCSNTRUPrimePrivateKey privateKey;
24+
private final KTSParameterSpec parameterSpec;
25+
private final SNTRUPrimeKEMExtractor kemExt;
2226

23-
public SNTRUPrimeDecapsulatorSpi(BCSNTRUPrimePrivateKey privateKey, KTSParameterSpec parameterSpec)
27+
SNTRUPrimeDecapsulatorSpi(BCSNTRUPrimePrivateKey privateKey, KTSParameterSpec parameterSpec)
2428
{
25-
this.privateKey = privateKey;
29+
// this.privateKey = privateKey;
2630
this.parameterSpec = parameterSpec;
27-
28-
kemExt = new SNTRUPrimeKEMExtractor(privateKey.getKeyParams());
31+
this.kemExt = new SNTRUPrimeKEMExtractor(privateKey.getKeyParams());
2932
}
3033

3134
@Override
32-
public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) throws DecapsulateException
35+
public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm)
36+
throws DecapsulateException
3337
{
3438
Objects.checkFromToIndex(from, to, engineSecretSize());
3539
Objects.requireNonNull(algorithm, "null algorithm");
@@ -40,27 +44,32 @@ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, Strin
4044
throw new DecapsulateException("incorrect encapsulation size");
4145
}
4246

43-
// if algorithm is Generic then use parameterSpec to wrap key
44-
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
45-
algorithm.equals("Generic"))
47+
String keyAlgName = parameterSpec.getKeyAlgorithmName();
48+
if (!"Generic".equals(keyAlgName))
4649
{
47-
algorithm = parameterSpec.getKeyAlgorithmName();
50+
// if algorithm is Generic then use parameterSpec to wrap key
51+
if ("Generic".equals(algorithm))
52+
{
53+
algorithm = keyAlgName;
54+
}
55+
// check spec algorithm mismatch provided algorithm
56+
else if (!algorithm.equals(keyAlgName))
57+
{
58+
throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm);
59+
}
4860
}
4961

50-
// check spec algorithm mismatch provided algorithm
51-
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
52-
!parameterSpec.getKeyAlgorithmName().equals(algorithm))
62+
byte[] kemSecret = kemExt.extractSecret(encapsulation);
63+
byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret);
64+
65+
try
5366
{
54-
throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm);
67+
return new SecretKeySpec(kdfSecret, from, to - from, algorithm);
68+
}
69+
finally
70+
{
71+
Arrays.clear(kdfSecret);
5572
}
56-
57-
// Only use KDF when ktsParameterSpec is provided
58-
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
59-
byte[] secret = kemExt.extractSecret(encapsulation);
60-
61-
byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to);
62-
63-
return new SecretKeySpec(secretKey, algorithm);
6473
}
6574

6675
@Override

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

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,36 @@
11
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
22

3+
import java.security.SecureRandom;
4+
import java.util.Objects;
5+
6+
import javax.crypto.KEM;
7+
import javax.crypto.KEMSpi;
8+
import javax.crypto.SecretKey;
9+
import javax.crypto.spec.SecretKeySpec;
10+
311
import org.bouncycastle.crypto.SecretWithEncapsulation;
412
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
513
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMGenerator;
614
import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil;
715
import org.bouncycastle.util.Arrays;
816

9-
import javax.crypto.KEM;
10-
import javax.crypto.KEMSpi;
11-
import javax.crypto.spec.SecretKeySpec;
12-
import java.security.InvalidKeyException;
13-
import java.security.SecureRandom;
14-
import java.util.Objects;
15-
17+
/*
18+
* NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to
19+
* invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same
20+
* time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message."
21+
*/
1622
class SNTRUPrimeEncapsulatorSpi
1723
implements KEMSpi.EncapsulatorSpi
1824
{
1925
private final BCSNTRUPrimePublicKey publicKey;
2026
private final KTSParameterSpec parameterSpec;
2127
private final SNTRUPrimeKEMGenerator kemGen;
2228

23-
24-
public SNTRUPrimeEncapsulatorSpi(BCSNTRUPrimePublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random)
29+
SNTRUPrimeEncapsulatorSpi(BCSNTRUPrimePublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random)
2530
{
2631
this.publicKey = publicKey;
2732
this.parameterSpec = parameterSpec;
28-
29-
kemGen = new SNTRUPrimeKEMGenerator(random);
33+
this.kemGen = new SNTRUPrimeKEMGenerator(random);
3034
}
3135

3236
@Override
@@ -35,31 +39,37 @@ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
3539
Objects.checkFromToIndex(from, to, engineSecretSize());
3640
Objects.requireNonNull(algorithm, "null algorithm");
3741

38-
// if algorithm is Generic then use parameterSpec to wrap key
39-
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
40-
algorithm.equals("Generic"))
41-
{
42-
algorithm = parameterSpec.getKeyAlgorithmName();
43-
}
44-
45-
// check spec algorithm mismatch provided algorithm
46-
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
47-
!parameterSpec.getKeyAlgorithmName().equals(algorithm))
42+
String keyAlgName = parameterSpec.getKeyAlgorithmName();
43+
if (!"Generic".equals(keyAlgName))
4844
{
49-
throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm);
45+
// if algorithm is Generic then use parameterSpec to wrap key
46+
if ("Generic".equals(algorithm))
47+
{
48+
algorithm = keyAlgName;
49+
}
50+
// check spec algorithm mismatch provided algorithm
51+
else if (!algorithm.equals(keyAlgName))
52+
{
53+
throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm);
54+
}
5055
}
5156

52-
// Only use KDF when ktsParameterSpec is provided
53-
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
5457
SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams());
5558

5659
byte[] encapsulation = secEnc.getEncapsulation();
57-
byte[] secret = secEnc.getSecret();
5860

59-
byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to);
60-
61-
return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, null); //TODO: DER encoding for params
61+
byte[] kemSecret = secEnc.getSecret();
62+
byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret);
6263

64+
try
65+
{
66+
SecretKey secretKey = new SecretKeySpec(kdfSecret, from, to - from, algorithm);
67+
return new KEM.Encapsulated(secretKey, encapsulation, null);
68+
}
69+
finally
70+
{
71+
Arrays.clear(kdfSecret);
72+
}
6373
}
6474

6575
@Override

0 commit comments

Comments
 (0)