Skip to content

Commit

Permalink
github #1664 - Abstract KEM functionality out of DHKEM
Browse files Browse the repository at this point in the history
  • Loading branch information
royb committed Jul 17, 2024
1 parent 4abf695 commit 8de3703
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 33 deletions.
13 changes: 12 additions & 1 deletion core/src/main/java/org/bouncycastle/crypto/hpke/DHKEM.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@


class DHKEM
extends KEM
{
private AsymmetricCipherKeyPairGenerator kpGen;

Expand All @@ -48,6 +49,7 @@ class DHKEM
private byte bitmask;
private int Nsk;
private int Nsecret;
private int Nenc;

ECDomainParameters domainParams;

Expand All @@ -74,7 +76,7 @@ protected DHKEM(short kemid)
bitmask = (byte)0xff;
Nsk = 32;
Nsecret = 32;

Nenc = 65;
this.kpGen = new ECKeyPairGenerator();
this.kpGen.init(new ECKeyGenerationParameters(domainParams, new SecureRandom()));

Expand All @@ -96,6 +98,7 @@ protected DHKEM(short kemid)
bitmask = (byte)0xff;
Nsk = 48;
Nsecret = 48;
Nenc = 97;

this.kpGen = new ECKeyPairGenerator();
this.kpGen.init(new ECKeyGenerationParameters(domainParams, new SecureRandom()));
Expand All @@ -119,6 +122,7 @@ protected DHKEM(short kemid)
bitmask = 0x01;
Nsk = 66;
Nsecret = 64;
Nenc = 133;

this.kpGen = new ECKeyPairGenerator();
this.kpGen.init(new ECKeyGenerationParameters(domainParams, new SecureRandom()));
Expand All @@ -129,6 +133,7 @@ protected DHKEM(short kemid)
this.agreement = new XDHBasicAgreement();
Nsecret = 32;
Nsk = 32;
Nenc = 32;
this.kpGen = new X25519KeyPairGenerator();
this.kpGen.init(new X25519KeyGenerationParameters(new SecureRandom()));

Expand All @@ -138,6 +143,7 @@ protected DHKEM(short kemid)
this.agreement = new XDHBasicAgreement();
Nsecret = 64;
Nsk = 56;
Nenc = 56;

this.kpGen = new X448KeyPairGenerator();
this.kpGen.init(new X448KeyGenerationParameters(new SecureRandom()));
Expand Down Expand Up @@ -242,6 +248,11 @@ public AsymmetricCipherKeyPair DeserializePrivateKey(byte[] skEncoded, byte[] pk
}
}

int getEncryptionSize()
{
return Nenc;
}

private boolean ValidateSk(BigInteger d)
{
BigInteger n = domainParams.getN();
Expand Down
51 changes: 19 additions & 32 deletions core/src/main/java/org/bouncycastle/crypto/hpke/HPKE.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class HPKE
private final short kemId;
private final short kdfId;
private final short aeadId;
private final DHKEM dhkem;
private final KEM kem;
private final HKDF hkdf;

short Nk;
Expand All @@ -58,7 +58,7 @@ public HPKE(byte mode, short kemId, short kdfId, short aeadId)
this.kdfId = kdfId;
this.aeadId = aeadId;
this.hkdf = new HKDF(kdfId);
this.dhkem = new DHKEM(kemId);
this.kem = new DHKEM(kemId);
if (aeadId == aead_AES_GCM128)
{
Nk = 16;
Expand All @@ -67,25 +67,12 @@ public HPKE(byte mode, short kemId, short kdfId, short aeadId)
{
Nk = 32;
}

}

public int getEncSize()
{
switch (kemId)
{
case HPKE.kem_P256_SHA256:
return 65;
case HPKE.kem_P384_SHA348:
return 97;
case HPKE.kem_P521_SHA512:
return 133;
case HPKE.kem_X25519_SHA256:
return 32;
case HPKE.kem_X448_SHA512:
return 56;
default:
throw new IllegalArgumentException("invalid kem id");
}
return kem.getEncryptionSize();
}
public short getAeadId()
{
Expand Down Expand Up @@ -139,32 +126,32 @@ private HPKEContext keySchedule(byte mode, byte[] sharedSecret, byte[] info, byt

public AsymmetricCipherKeyPair generatePrivateKey()
{
return dhkem.GeneratePrivateKey();
return kem.GeneratePrivateKey();
}


public byte[] serializePublicKey(AsymmetricKeyParameter pk)
{
return dhkem.SerializePublicKey(pk);
return kem.SerializePublicKey(pk);
}

public byte[] serializePrivateKey(AsymmetricKeyParameter sk)
{
return dhkem.SerializePrivateKey(sk);
return kem.SerializePrivateKey(sk);
}
public AsymmetricKeyParameter deserializePublicKey(byte[] pkEncoded)
{
return dhkem.DeserializePublicKey(pkEncoded);
return kem.DeserializePublicKey(pkEncoded);
}

public AsymmetricCipherKeyPair deserializePrivateKey(byte[] skEncoded, byte[] pkEncoded)
{
return dhkem.DeserializePrivateKey(skEncoded, pkEncoded);
return kem.DeserializePrivateKey(skEncoded, pkEncoded);
}

public AsymmetricCipherKeyPair deriveKeyPair(byte[] ikm)
{
return dhkem.DeriveKeyPair(ikm);
return kem.DeriveKeyPair(ikm);
}

public byte[][] sendExport(AsymmetricKeyParameter pkR, byte[] info, byte[] exporterContext, int L,
Expand Down Expand Up @@ -273,7 +260,7 @@ public byte[] open(byte[] enc, AsymmetricCipherKeyPair skR, byte[] info, byte[]

public HPKEContextWithEncapsulation setupBaseS(AsymmetricKeyParameter pkR, byte[] info)
{
byte[][] output = dhkem.Encap(pkR); // sharedSecret, enc
byte[][] output = kem.Encap(pkR); // sharedSecret, enc
HPKEContext ctx = keySchedule(mode_base, output[0], info, default_psk, default_psk_id);

return new HPKEContextWithEncapsulation(ctx, output[1]);
Expand All @@ -283,21 +270,21 @@ public HPKEContextWithEncapsulation setupBaseS(AsymmetricKeyParameter pkR, byte[
// This should only be used to validate test vectors.
public HPKEContextWithEncapsulation setupBaseS(AsymmetricKeyParameter pkR, byte[] info, AsymmetricCipherKeyPair kpE)
{
byte[][] output = dhkem.Encap(pkR, kpE); // sharedSecret, enc
byte[][] output = kem.Encap(pkR, kpE); // sharedSecret, enc
HPKEContext ctx = keySchedule(mode_base, output[0], info, default_psk, default_psk_id);

return new HPKEContextWithEncapsulation(ctx, output[1]);
}

public HPKEContext setupBaseR(byte[] enc, AsymmetricCipherKeyPair skR, byte[] info)
{
byte[] sharedSecret = dhkem.Decap(enc, skR);
byte[] sharedSecret = kem.Decap(enc, skR);
return keySchedule(mode_base, sharedSecret, info, default_psk, default_psk_id);
}

public HPKEContextWithEncapsulation SetupPSKS(AsymmetricKeyParameter pkR, byte[] info, byte[] psk, byte[] psk_id)
{
byte[][] output = dhkem.Encap(pkR); // sharedSecret, enc
byte[][] output = kem.Encap(pkR); // sharedSecret, enc

HPKEContext ctx = keySchedule(mode_psk, output[0], info, psk, psk_id);

Expand All @@ -306,35 +293,35 @@ public HPKEContextWithEncapsulation SetupPSKS(AsymmetricKeyParameter pkR, byte[]

public HPKEContext setupPSKR(byte[] enc, AsymmetricCipherKeyPair skR, byte[] info, byte[] psk, byte[] psk_id)
{
byte[] sharedSecret = dhkem.Decap(enc, skR);
byte[] sharedSecret = kem.Decap(enc, skR);
return keySchedule(mode_psk, sharedSecret, info, psk, psk_id);
}

public HPKEContextWithEncapsulation setupAuthS(AsymmetricKeyParameter pkR, byte[] info, AsymmetricCipherKeyPair skS)
{
byte[][] output = dhkem.AuthEncap(pkR, skS);
byte[][] output = kem.AuthEncap(pkR, skS);
HPKEContext ctx = keySchedule(mode_auth, output[0], info, default_psk, default_psk_id);

return new HPKEContextWithEncapsulation(ctx, output[1]);
}

public HPKEContext setupAuthR(byte[] enc, AsymmetricCipherKeyPair skR, byte[] info, AsymmetricKeyParameter pkS)
{
byte[] sharedSecret = dhkem.AuthDecap(enc, skR, pkS);
byte[] sharedSecret = kem.AuthDecap(enc, skR, pkS);
return keySchedule(mode_auth, sharedSecret, info, default_psk, default_psk_id);
}

public HPKEContextWithEncapsulation setupAuthPSKS(AsymmetricKeyParameter pkR, byte[] info, byte[] psk, byte[] psk_id, AsymmetricCipherKeyPair skS)
{
byte[][] output = dhkem.AuthEncap(pkR, skS);
byte[][] output = kem.AuthEncap(pkR, skS);
HPKEContext ctx = keySchedule(mode_auth_psk, output[0], info, psk, psk_id);

return new HPKEContextWithEncapsulation(ctx, output[1]);
}

public HPKEContext setupAuthPSKR(byte[] enc, AsymmetricCipherKeyPair skR, byte[] info, byte[] psk, byte[] psk_id, AsymmetricKeyParameter pkS)
{
byte[] sharedSecret = dhkem.AuthDecap(enc, skR, pkS);
byte[] sharedSecret = kem.AuthDecap(enc, skR, pkS);
return keySchedule(mode_auth_psk, sharedSecret, info, psk, psk_id);
}
}
35 changes: 35 additions & 0 deletions core/src/main/java/org/bouncycastle/crypto/hpke/KEM.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.bouncycastle.crypto.hpke;

import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;


/**
* base class for HPKE KEM
*/
public abstract class KEM {

// Key Generation
abstract AsymmetricCipherKeyPair GeneratePrivateKey();
abstract AsymmetricCipherKeyPair DeriveKeyPair(byte[] ikm);

// Encapsulates a shared secret for a given public key and returns the encapsulated key and shared secret.
abstract byte[][] Encap(AsymmetricKeyParameter recipientPublicKey);
abstract byte[][] Encap(AsymmetricKeyParameter pkR, AsymmetricCipherKeyPair kpE);
abstract byte[][] AuthEncap(AsymmetricKeyParameter pkR, AsymmetricCipherKeyPair kpS);

// Decapsulates the given encapsulated key using the recipient's key pair and returns the shared secret.
abstract byte[] Decap(byte[] encapsulatedKey, AsymmetricCipherKeyPair recipientKeyPair);
abstract byte[] AuthDecap(byte[] enc, AsymmetricCipherKeyPair kpR, AsymmetricKeyParameter pkS);

// Serialization
abstract byte[] SerializePublicKey(AsymmetricKeyParameter publicKey);
abstract byte[] SerializePrivateKey(AsymmetricKeyParameter key);

// Deserialization
abstract AsymmetricKeyParameter DeserializePublicKey(byte[] encodedPublicKey);
abstract AsymmetricCipherKeyPair DeserializePrivateKey(byte[] skEncoded, byte[] pkEncoded);

abstract int getEncryptionSize();

}

0 comments on commit 8de3703

Please sign in to comment.