Skip to content

Commit 590eb54

Browse files
committed
HQC: Add missing mappings, fix OID mappings
- unify HQC mappings using SpiUtil - restrict keys by parameter set where appropriate
1 parent a544ec1 commit 590eb54

File tree

10 files changed

+194
-178
lines changed

10 files changed

+194
-178
lines changed

core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCEngine.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ class HQCEngine
3030
private final int pkSize;
3131
private final GF2PolynomialCalculator gf;
3232
private final long rejectionThreshold;
33+
private final int cipherTextBytes;
3334

34-
public HQCEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr,
35-
int fft, int nmu, int pkSize, int[] generatorPoly)
35+
HQCEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr, int fft, int nmu, int pkSize,
36+
int[] generatorPoly)
3637
{
3738
this.n = n;
3839
this.k = k;
@@ -54,6 +55,12 @@ public HQCEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr,
5455
long RED_MASK = ((1L << (n & 63)) - 1);
5556
this.gf = new GF2PolynomialCalculator(N_BYTE_64, n, RED_MASK);
5657
this.rejectionThreshold = ((1L << 24) / n) * n;
58+
this.cipherTextBytes = N_BYTE + N1N2_BYTE + 16;
59+
}
60+
61+
int getCipherTextBytes()
62+
{
63+
return cipherTextBytes;
5764
}
5865

5966
/**

core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,32 @@
66
public class HQCKEMExtractor
77
implements EncapsulatedSecretExtractor
88
{
9-
private HQCEngine engine;
9+
private final HQCPrivateKeyParameters privateKey;
10+
private final HQCEngine engine;
1011

11-
private final HQCKeyParameters key;
12-
13-
public HQCKEMExtractor(HQCPrivateKeyParameters privParams)
12+
public HQCKEMExtractor(HQCPrivateKeyParameters privateKey)
1413
{
15-
this.key = privParams;
16-
initCipher(key.getParameters());
17-
}
14+
if (privateKey == null)
15+
{
16+
throw new NullPointerException("'privateKey' cannot be null");
17+
}
1818

19-
private void initCipher(HQCParameters param)
20-
{
21-
engine = param.getEngine();
19+
this.privateKey = privateKey;
20+
this.engine = privateKey.getParameters().getEngine();
2221
}
2322

2423
public byte[] extractSecret(byte[] encapsulation)
2524
{
2625
byte[] session_key = new byte[64];
27-
HQCPrivateKeyParameters secretKey = (HQCPrivateKeyParameters)key;
28-
byte[] sk = secretKey.getPrivateKey();
26+
byte[] sk = privateKey.getPrivateKey();
2927

3028
engine.decaps(session_key, encapsulation, sk);
3129

3230
return Arrays.copyOfRange(session_key, 0, 32);
3331
}
3432

3533
public int getEncapsulationLength()
36-
{ // Hash + salt
37-
return key.getParameters().getN_BYTES() + key.getParameters().getN1N2_BYTES() + 16;
34+
{
35+
return engine.getCipherTextBytes();
3836
}
3937
}

core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,18 @@ public class HQCParameters
3131
final static int PARAM_M = 8;
3232
final static int GF_MUL_ORDER = 255;
3333

34-
private final HQCEngine hqcEngine;
34+
private final HQCEngine engine;
3535

36-
private HQCParameters(String name, int n, int n1, int n2, int k, int g, int delta, int w, int wr,
37-
int fft, int nMu, int pkSize, int skSize, int[] generatorPoly)
36+
private HQCParameters(String name, int n, int n1, int n2, int k, int g, int delta, int w, int wr, int fft, int nMu,
37+
int pkSize, int skSize, int[] generatorPoly)
3838
{
3939
this.name = name;
4040
this.n = n;
4141
this.n1 = n1;
4242
this.n2 = n2;
4343
this.publicKeyBytes = pkSize;
4444
this.secretKeyBytes = skSize;
45-
hqcEngine = new HQCEngine(n, n1, n2, k, g, delta, w, wr, fft, nMu, pkSize, generatorPoly);
45+
this.engine = new HQCEngine(n, n1, n2, k, g, delta, w, wr, fft, nMu, pkSize, generatorPoly);
4646
}
4747

4848
int getSHA512_BYTES()
@@ -67,7 +67,12 @@ int getN1N2_BYTES()
6767

6868
HQCEngine getEngine()
6969
{
70-
return hqcEngine;
70+
return engine;
71+
}
72+
73+
public int getEncapsulationLength()
74+
{
75+
return engine.getCipherTextBytes();
7176
}
7277

7378
public int getSessionKeySize()

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

Lines changed: 11 additions & 5 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.hqc.HQCKeyFactorySpi;
89

910
public class HQC
@@ -38,10 +39,7 @@ public void configure(ConfigurableProvider provider)
3839

3940
AsymmetricKeyInfoConverter keyFact = new HQCKeyFactorySpi();
4041

41-
provider.addAlgorithm("Cipher.HQC", PREFIX + "HQCCipherSpi$Base");
42-
provider.addAlgorithm("Alg.Alias.Cipher.HQC", "HQC");
43-
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_hqc, "HQC");
44-
42+
addCipherAlgorithm(provider, "HQC", PREFIX + "HQCCipherSpi$Base", BCObjectIdentifiers.pqc_kem_hqc);
4543
addCipherAlgorithm(provider, "HQC128", PREFIX + "HQCCipherSpi$HQC128", BCObjectIdentifiers.hqc128);
4644
addCipherAlgorithm(provider, "HQC192", PREFIX + "HQCCipherSpi$HQC192", BCObjectIdentifiers.hqc192);
4745
addCipherAlgorithm(provider, "HQC256", PREFIX + "HQCCipherSpi$HQC256", BCObjectIdentifiers.hqc256);
@@ -50,7 +48,15 @@ public void configure(ConfigurableProvider provider)
5048
provider.addKeyInfoConverter(BCObjectIdentifiers.hqc128, keyFact);
5149
provider.addKeyInfoConverter(BCObjectIdentifiers.hqc192, keyFact);
5250
provider.addKeyInfoConverter(BCObjectIdentifiers.hqc256, keyFact);
51+
52+
if (SpiUtil.hasKEM())
53+
{
54+
provider.addAlgorithm("KEM.HQC", PREFIX + "HQCKEMSpi$HQC");
55+
56+
addKEMAlgorithm(provider, "HQC-128", PREFIX + "HQCKEMSpi$HQC128", BCObjectIdentifiers.hqc128);
57+
addKEMAlgorithm(provider, "HQC-192", PREFIX + "HQCKEMSpi$HQC192", BCObjectIdentifiers.hqc192);
58+
addKEMAlgorithm(provider, "HQC-256", PREFIX + "HQCKEMSpi$HQC256", BCObjectIdentifiers.hqc256);
59+
}
5360
}
5461
}
5562
}
56-

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

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
11
package org.bouncycastle.pqc.jcajce.provider.hqc;
22

3-
import org.bouncycastle.pqc.jcajce.provider.hqc.BCHQCPrivateKey;
4-
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
5-
6-
import org.bouncycastle.pqc.crypto.hqc.HQCKEMExtractor;
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;
139

14-
import java.util.Arrays;
15-
import java.util.Objects;
10+
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
11+
import org.bouncycastle.pqc.crypto.hqc.HQCKEMExtractor;
12+
import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil;
13+
import org.bouncycastle.util.Arrays;
1614

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 HQCDecapsulatorSpi
1821
implements KEMSpi.DecapsulatorSpi
1922
{
20-
BCHQCPrivateKey privateKey;
21-
KTSParameterSpec parameterSpec;
22-
HQCKEMExtractor kemExt;
23+
// private final BCHQCPrivateKey privateKey;
24+
private final KTSParameterSpec parameterSpec;
25+
private final HQCKEMExtractor kemExt;
2326

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

@@ -42,28 +44,32 @@ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, Strin
4244
throw new DecapsulateException("incorrect encapsulation size");
4345
}
4446

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

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

6975
@Override
@@ -77,4 +83,4 @@ public int engineEncapsulationSize()
7783
{
7884
return kemExt.getEncapsulationLength();
7985
}
80-
}
86+
}

0 commit comments

Comments
 (0)