Skip to content

Commit b26e96e

Browse files
committed
NTRU: Add missing mappings, fix OID mappings
- unify NTRU mappings using SpiUtil
1 parent 590eb54 commit b26e96e

File tree

8 files changed

+160
-153
lines changed

8 files changed

+160
-153
lines changed

core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMExtractor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,6 @@ private void cmov(byte[] r, byte[] x, byte b)
8181

8282
public int getEncapsulationLength()
8383
{
84-
return ntruPrivateKey.getParameters().getParameterSet().ntruCiphertextBytes();
84+
return ntruPrivateKey.getParameters().getEncapsulationLength();
8585
}
8686
}

core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ private NTRUParameters(String name, NTRUParameterSet parameterSet)
5252
this.parameterSet = parameterSet;
5353
}
5454

55+
public int getEncapsulationLength()
56+
{
57+
return getParameterSet().ntruCiphertextBytes();
58+
}
59+
5560
public String getName()
5661
{
5762
return name;

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

Lines changed: 14 additions & 2 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.ntru.NTRUKeyFactorySpi;
89

910
public class NTRU
@@ -27,22 +28,33 @@ public void configure(ConfigurableProvider provider)
2728
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps2048509, "NTRU");
2829
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps2048677, "NTRU");
2930
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps4096821, "NTRU");
31+
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps40961229, "NTRU");
3032
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhrss701, "NTRU");
33+
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhrss1373, "NTRU");
3134

3235
AsymmetricKeyInfoConverter keyFact = new NTRUKeyFactorySpi();
3336

34-
provider.addAlgorithm("Cipher.NTRU", PREFIX + "NTRUCipherSpi$Base");
35-
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_ntru, "NTRU");
37+
addCipherAlgorithm(provider, "NTRU", PREFIX + "NTRUCipherSpi$Base", BCObjectIdentifiers.pqc_kem_ntru);
3638
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps2048509, "NTRU");
3739
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps2048677, "NTRU");
3840
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps4096821, "NTRU");
41+
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps40961229, "NTRU");
3942
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhrss701, "NTRU");
43+
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhrss1373, "NTRU");
4044

4145
registerOid(provider, BCObjectIdentifiers.pqc_kem_ntru, "NTRU", keyFact);
4246
registerOid(provider, BCObjectIdentifiers.ntruhps2048509, "NTRU", keyFact);
4347
registerOid(provider, BCObjectIdentifiers.ntruhps2048677, "NTRU", keyFact);
4448
registerOid(provider, BCObjectIdentifiers.ntruhps4096821, "NTRU", keyFact);
49+
registerOid(provider, BCObjectIdentifiers.ntruhps40961229, "NTRU", keyFact);
4550
registerOid(provider, BCObjectIdentifiers.ntruhrss701, "NTRU", keyFact);
51+
registerOid(provider, BCObjectIdentifiers.ntruhrss1373, "NTRU", keyFact);
52+
53+
if (SpiUtil.hasKEM())
54+
{
55+
// TODO Per-parameter-set SPI classes?
56+
addKEMAlgorithm(provider, "NTRU", PREFIX + "NTRUKEMSpi$NTRU", BCObjectIdentifiers.pqc_kem_ntru);
57+
}
4658
}
4759
}
4860
}

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

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

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

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

3-
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
4-
5-
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
6-
import org.bouncycastle.pqc.crypto.ntru.NTRUKEMExtractor;
7-
import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil;
3+
import java.util.Objects;
84

95
import javax.crypto.DecapsulateException;
106
import javax.crypto.KEMSpi;
117
import javax.crypto.SecretKey;
128
import javax.crypto.spec.SecretKeySpec;
13-
import java.security.InvalidKeyException;
14-
import java.util.Arrays;
15-
import java.util.Objects;
169

10+
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
11+
import org.bouncycastle.pqc.crypto.ntru.NTRUKEMExtractor;
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+
*/
1720
public class NTRUDecapsulatorSpi
1821
implements KEMSpi.DecapsulatorSpi
1922
{
20-
BCNTRUPrivateKey privateKey;
21-
KTSParameterSpec parameterSpec;
22-
NTRUKEMExtractor kemExt;
23+
// private final BCNTRUPrivateKey privateKey;
24+
private final KTSParameterSpec parameterSpec;
25+
private final NTRUKEMExtractor kemExt;
2326

24-
public NTRUDecapsulatorSpi(BCNTRUPrivateKey privateKey, KTSParameterSpec parameterSpec)
27+
NTRUDecapsulatorSpi(BCNTRUPrivateKey privateKey, KTSParameterSpec parameterSpec)
2528
{
26-
this.privateKey = privateKey;
29+
// this.privateKey = privateKey;
2730
this.parameterSpec = parameterSpec;
28-
2931
this.kemExt = new NTRUKEMExtractor(privateKey.getKeyParams());
3032
}
3133

3234
@Override
33-
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
3437
{
3538
Objects.checkFromToIndex(from, to, engineSecretSize());
3639
Objects.requireNonNull(algorithm, "null algorithm");
@@ -41,28 +44,32 @@ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, Strin
4144
throw new DecapsulateException("incorrect encapsulation size");
4245
}
4346

44-
// if algorithm is Generic then use parameterSpec to wrap key
45-
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
46-
algorithm.equals("Generic"))
47+
String keyAlgName = parameterSpec.getKeyAlgorithmName();
48+
if (!"Generic".equals(keyAlgName))
4749
{
48-
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+
}
4960
}
5061

51-
// check spec algorithm mismatch provided algorithm
52-
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
53-
!parameterSpec.getKeyAlgorithmName().equals(algorithm))
62+
byte[] kemSecret = kemExt.extractSecret(encapsulation);
63+
byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret);
64+
65+
try
5466
{
55-
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);
5672
}
57-
58-
// Only use KDF when ktsParameterSpec is provided
59-
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
60-
boolean useKDF = parameterSpec.getKdfAlgorithm() != null;
61-
62-
byte[] secret = kemExt.extractSecret(encapsulation);
63-
byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to);
64-
65-
return new SecretKeySpec(secretKey, algorithm);
6673
}
6774

6875
@Override
Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
11
package org.bouncycastle.pqc.jcajce.provider.ntru;
22

3-
import org.bouncycastle.crypto.SecretWithEncapsulation;
4-
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
5-
import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator;
6-
import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil;
3+
import java.security.SecureRandom;
4+
import java.util.Objects;
75

86
import javax.crypto.KEM;
97
import javax.crypto.KEMSpi;
8+
import javax.crypto.SecretKey;
109
import javax.crypto.spec.SecretKeySpec;
11-
import java.security.InvalidKeyException;
12-
import java.security.SecureRandom;
13-
import java.util.Arrays;
14-
import java.util.Objects;
1510

11+
import org.bouncycastle.crypto.SecretWithEncapsulation;
12+
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
13+
import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator;
14+
import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil;
15+
import org.bouncycastle.util.Arrays;
16+
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
public class NTRUEncapsulatorSpi
1723
implements KEMSpi.EncapsulatorSpi
1824
{
1925
private final BCNTRUPublicKey publicKey;
2026
private final KTSParameterSpec parameterSpec;
2127
private final NTRUKEMGenerator kemGen;
2228

23-
public NTRUEncapsulatorSpi(BCNTRUPublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random)
29+
NTRUEncapsulatorSpi(BCNTRUPublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random)
2430
{
2531
this.publicKey = publicKey;
2632
this.parameterSpec = parameterSpec;
27-
2833
this.kemGen = new NTRUKEMGenerator(random);
2934
}
3035

@@ -34,31 +39,37 @@ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
3439
Objects.checkFromToIndex(from, to, engineSecretSize());
3540
Objects.requireNonNull(algorithm, "null algorithm");
3641

37-
// if algorithm is Generic then use parameterSpec to wrap key
38-
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
39-
algorithm.equals("Generic"))
40-
{
41-
algorithm = parameterSpec.getKeyAlgorithmName();
42-
}
43-
44-
// check spec algorithm mismatch provided algorithm
45-
if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
46-
!parameterSpec.getKeyAlgorithmName().equals(algorithm))
42+
String keyAlgName = parameterSpec.getKeyAlgorithmName();
43+
if (!"Generic".equals(keyAlgName))
4744
{
48-
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+
}
4955
}
5056

51-
// Only use KDF when ktsParameterSpec is provided
52-
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
53-
boolean useKDF = parameterSpec.getKdfAlgorithm() != null;
54-
5557
SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams());
5658

5759
byte[] encapsulation = secEnc.getEncapsulation();
58-
byte[] secret = secEnc.getSecret();
59-
byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to);
6060

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);
63+
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+
}
6273
}
6374

6475
@Override
@@ -70,23 +81,6 @@ public int engineSecretSize()
7081
@Override
7182
public int engineEncapsulationSize()
7283
{
73-
//TODO: Maybe make parameterSet public or add getEncapsulationSize() in NTRUKEMGenerator.java
74-
switch (publicKey.getKeyParams().getParameters().getName())
75-
{
76-
case "ntruhps2048509":
77-
return 699;
78-
case "ntruhps2048677":
79-
return 930;
80-
case "ntruhps4096821":
81-
return 1230;
82-
case "ntruhps40961229":
83-
return 1843;
84-
case "ntruhrss701":
85-
return 1138;
86-
case "ntruhrss1373":
87-
return 2401;
88-
default:
89-
return -1;
90-
}
84+
return publicKey.getKeyParams().getParameters().getEncapsulationLength();
9185
}
9286
}

0 commit comments

Comments
 (0)