Skip to content

Commit a56858d

Browse files
committed
WIP: Add a concrete Kyber implementation
1 parent 11e1d5c commit a56858d

9 files changed

+256
-7
lines changed

pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,26 @@
1414
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1515
</properties>
1616

17+
<repositories>
18+
<repository>
19+
<id>jitpack.io</id>
20+
<url>https://jitpack.io</url>
21+
</repository>
22+
</repositories>
23+
1724
<dependencies>
1825
<dependency>
1926
<groupId>com.google.code.findbugs</groupId>
2027
<artifactId>jsr305</artifactId>
2128
<version>3.0.2</version>
2229
</dependency>
2330

31+
<dependency>
32+
<groupId>com.github.fisherstevenk</groupId>
33+
<artifactId>kyberJCE</artifactId>
34+
<version>v3.0.0</version>
35+
</dependency>
36+
2437
<dependency>
2538
<groupId>com.fasterxml.jackson.core</groupId>
2639
<artifactId>jackson-databind</artifactId>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.eatthepath.noise.component;
2+
3+
import com.swiftcryptollc.crypto.interfaces.KyberPublicKey;
4+
import com.swiftcryptollc.crypto.provider.KyberCipherText;
5+
import com.swiftcryptollc.crypto.provider.KyberDecrypted;
6+
import com.swiftcryptollc.crypto.provider.KyberEncrypted;
7+
import com.swiftcryptollc.crypto.provider.KyberKeySize;
8+
import com.swiftcryptollc.crypto.provider.kyber.KyberParams;
9+
import com.swiftcryptollc.crypto.spec.KyberPublicKeySpec;
10+
11+
import javax.crypto.KeyAgreement;
12+
import java.security.*;
13+
import java.security.spec.InvalidKeySpecException;
14+
15+
abstract class AbstractKyberKeyEncapsulationMechanism implements NoiseKeyEncapsulationMechanism {
16+
17+
private final KeyAgreement keyAgreement;
18+
private final KeyPairGenerator keyPairGenerator;
19+
private final KeyFactory keyFactory;
20+
21+
AbstractKyberKeyEncapsulationMechanism(final KeyAgreement keyAgreement,
22+
final KeyPairGenerator keyPairGenerator,
23+
final KeyFactory keyFactory) {
24+
25+
this.keyAgreement = keyAgreement;
26+
this.keyPairGenerator = keyPairGenerator;
27+
this.keyFactory = keyFactory;
28+
}
29+
30+
protected abstract KyberKeySize getKyberKeySize();
31+
32+
@Override
33+
public KeyPair generateKeyPair() {
34+
return keyPairGenerator.generateKeyPair();
35+
}
36+
37+
@Override
38+
public EncapsulatedKey encapsulate(final PrivateKey privateKey, final PublicKey publicKey) {
39+
try {
40+
keyAgreement.init(privateKey);
41+
} catch (final InvalidKeyException e) {
42+
throw new IllegalArgumentException("Invalid private key for encapsulation", e);
43+
}
44+
45+
try {
46+
final KyberEncrypted kyberEncrypted = (KyberEncrypted) keyAgreement.doPhase(publicKey, true);
47+
48+
return new EncapsulatedKey(kyberEncrypted.getSecretKey().getS(), kyberEncrypted.getCipherText().getC());
49+
} catch (final InvalidKeyException e) {
50+
throw new IllegalArgumentException("Invalid public key for encapsulation", e);
51+
}
52+
}
53+
54+
@Override
55+
public byte[] decapsulate(final PrivateKey privateKey, final byte[] encapsulation) {
56+
try {
57+
keyAgreement.init(privateKey);
58+
} catch (final InvalidKeyException e) {
59+
throw new IllegalArgumentException("Invalid private key for decapsulation", e);
60+
}
61+
62+
try {
63+
final KyberCipherText kyberCiphertext =
64+
new KyberCipherText(encapsulation, KyberParams.default_p, KyberParams.default_g);
65+
66+
return ((KyberDecrypted) keyAgreement.doPhase(kyberCiphertext, true)).getSecretKey().getS();
67+
} catch (final InvalidKeyException e) {
68+
throw new IllegalArgumentException("Invalid ciphertext for decapsulation", e);
69+
}
70+
}
71+
72+
@Override
73+
public byte[] serializePublicKey(final PublicKey publicKey) {
74+
if (publicKey instanceof final KyberPublicKey kyberPublicKey) {
75+
return kyberPublicKey.getY();
76+
}
77+
78+
throw new IllegalArgumentException("Illegal public key type: " + publicKey.getClass());
79+
}
80+
81+
@Override
82+
public PublicKey deserializePublicKey(final byte[] publicKeyBytes) {
83+
try {
84+
return keyFactory.generatePublic(
85+
new KyberPublicKeySpec(publicKeyBytes, KyberParams.default_p, KyberParams.default_g, getKyberKeySize()));
86+
} catch (final InvalidKeySpecException e) {
87+
throw new IllegalArgumentException("Could not parse public key bytes as a Kyber public key", e);
88+
}
89+
}
90+
}

src/main/java/com/eatthepath/noise/component/AbstractXECKeyAgreement.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ abstract class AbstractXECKeyAgreement implements NoiseKeyAgreement {
1414
private final KeyFactory keyFactory;
1515

1616
protected AbstractXECKeyAgreement(final KeyAgreement keyAgreement,
17-
final KeyPairGenerator keyPairGenerator,
18-
final KeyFactory keyFactory) {
17+
final KeyPairGenerator keyPairGenerator,
18+
final KeyFactory keyFactory) {
1919

2020
this.keyAgreement = keyAgreement;
2121
this.keyPairGenerator = keyPairGenerator;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
package com.eatthepath.noise.component;
22

3+
import java.security.Key;
4+
35
public record EncapsulatedKey(byte[] sharedSecret, byte[] encapsulation) {
46
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.eatthepath.noise.component;
2+
3+
import com.swiftcryptollc.crypto.provider.KyberKeySize;
4+
import com.swiftcryptollc.crypto.provider.kyber.KyberParams;
5+
6+
import javax.crypto.KeyAgreement;
7+
import java.security.KeyFactory;
8+
import java.security.KeyPairGenerator;
9+
import java.security.NoSuchAlgorithmException;
10+
11+
public class Kyber1024KeyEncapsulationMechanism extends AbstractKyberKeyEncapsulationMechanism {
12+
13+
private static final String ALGORITHM = "Kyber1024";
14+
15+
public Kyber1024KeyEncapsulationMechanism() throws NoSuchAlgorithmException {
16+
super(KeyAgreement.getInstance(ALGORITHM), KeyPairGenerator.getInstance(ALGORITHM), KeyFactory.getInstance(ALGORITHM));
17+
}
18+
19+
@Override
20+
protected KyberKeySize getKyberKeySize() {
21+
return KyberKeySize.KEY_1024;
22+
}
23+
24+
@Override
25+
public String getName() {
26+
return "Kyber1024";
27+
}
28+
29+
@Override
30+
public int getPublicKeyLength() {
31+
return KyberParams.Kyber1024PKBytes;
32+
}
33+
34+
@Override
35+
public int getEncapsulationLength() {
36+
return KyberParams.Kyber1024CTBytes;
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.eatthepath.noise.component;
2+
3+
import com.swiftcryptollc.crypto.provider.KyberKeySize;
4+
import com.swiftcryptollc.crypto.provider.kyber.KyberParams;
5+
6+
import javax.crypto.KeyAgreement;
7+
import java.security.KeyFactory;
8+
import java.security.KeyPairGenerator;
9+
import java.security.NoSuchAlgorithmException;
10+
11+
class Kyber512KeyEncapsulationMechanism extends AbstractKyberKeyEncapsulationMechanism {
12+
13+
private static final String ALGORITHM = "Kyber512";
14+
15+
public Kyber512KeyEncapsulationMechanism() throws NoSuchAlgorithmException {
16+
super(KeyAgreement.getInstance(ALGORITHM), KeyPairGenerator.getInstance(ALGORITHM), KeyFactory.getInstance(ALGORITHM));
17+
}
18+
19+
@Override
20+
protected KyberKeySize getKyberKeySize() {
21+
return KyberKeySize.KEY_512;
22+
}
23+
24+
@Override
25+
public String getName() {
26+
return "Kyber512";
27+
}
28+
29+
@Override
30+
public int getPublicKeyLength() {
31+
return KyberParams.Kyber512PKBytes;
32+
}
33+
34+
@Override
35+
public int getEncapsulationLength() {
36+
return KyberParams.Kyber512CTBytes;
37+
}
38+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.eatthepath.noise.component;
2+
3+
import com.swiftcryptollc.crypto.provider.KyberKeySize;
4+
import com.swiftcryptollc.crypto.provider.kyber.KyberParams;
5+
6+
import javax.crypto.KeyAgreement;
7+
import java.security.KeyFactory;
8+
import java.security.KeyPairGenerator;
9+
import java.security.NoSuchAlgorithmException;
10+
11+
class Kyber768KeyEncapsulationMechanism extends AbstractKyberKeyEncapsulationMechanism {
12+
private static final String ALGORITHM = "Kyber768";
13+
14+
public Kyber768KeyEncapsulationMechanism() throws NoSuchAlgorithmException {
15+
super(KeyAgreement.getInstance(ALGORITHM), KeyPairGenerator.getInstance(ALGORITHM), KeyFactory.getInstance(ALGORITHM));
16+
}
17+
18+
@Override
19+
protected KyberKeySize getKyberKeySize() {
20+
return KyberKeySize.KEY_768;
21+
}
22+
23+
@Override
24+
public String getName() {
25+
return "Kyber768";
26+
}
27+
28+
@Override
29+
public int getPublicKeyLength() {
30+
return KyberParams.Kyber768PKBytes;
31+
}
32+
33+
@Override
34+
public int getEncapsulationLength() {
35+
return KyberParams.Kyber768CTBytes;
36+
}
37+
}

src/main/java/com/eatthepath/noise/component/NoiseKeyEncapsulationMechanism.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.eatthepath.noise.component;
22

3-
import java.security.KeyPair;
4-
import java.security.PrivateKey;
5-
import java.security.PublicKey;
3+
import java.security.*;
64

75
public interface NoiseKeyEncapsulationMechanism {
86

9-
static NoiseKeyEncapsulationMechanism getInstance(final String name) {
10-
throw new IllegalArgumentException("Unrecognized key encapsulation method name: " + name);
7+
static NoiseKeyEncapsulationMechanism getInstance(final String name) throws NoSuchAlgorithmException {
8+
return switch (name) {
9+
case "Kyber512" -> new Kyber512KeyEncapsulationMechanism();
10+
case "Kyber768" -> new Kyber768KeyEncapsulationMechanism();
11+
case "Kyber1024" -> new Kyber1024KeyEncapsulationMechanism();
12+
default -> throw new IllegalArgumentException("Unrecognized key encapsulation method name: " + name);
13+
};
1114
}
1215

1316
String getName();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.eatthepath.noise;
2+
3+
import com.swiftcryptollc.crypto.provider.KyberJCE;
4+
import com.swiftcryptollc.crypto.provider.kyber.KyberParams;
5+
6+
import java.security.KeyPair;
7+
import java.security.KeyPairGenerator;
8+
import java.security.NoSuchAlgorithmException;
9+
import java.security.Security;
10+
import java.util.HexFormat;
11+
12+
public class KyberSandbox {
13+
14+
public static void main(final String... args) throws NoSuchAlgorithmException {
15+
// Security.setProperty("crypto.policy", "unlimited");
16+
Security.addProvider(new KyberJCE());
17+
18+
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("Kyber1024");
19+
KeyPair keyPair = keyGen.generateKeyPair();
20+
21+
System.out.println(keyPair.getPublic().getEncoded().length);
22+
System.out.println(KyberParams.Kyber1024PKBytes);
23+
24+
for (int i = 0; i < 10; i++) {
25+
System.out.println(HexFormat.of().formatHex(keyGen.generateKeyPair().getPublic().getEncoded(), 0, 168));
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)