user25753955
user25753955

Reputation: 1

How to use ML-KEM/Kyber for encrypting data using PublicKey and decrypting data using PrivateKey

I am learning how to use Post quantum cryptography with Java. The vendor implementation is provided by BouncyCastle version 1.78.1. In short, I'm using a BouncyCastlePQCProvider to obtain a Key Pair of specification Kyber1024.

static
    {
        Security.addProvider(new BouncyCastleProvider());
        Security.addProvider(new BouncyCastlePQCProvider());
    }
    
    public static KeyPair generateKeyPair() {
        try {
            KeyPairGenerator kpg=KeyPairGenerator.getInstance("Kyber","BCPQC");
            kpg.initialize(KyberParameterSpec.kyber1024);
            return kpg.generateKeyPair();
        } catch (Throwable t) {
            t.printStackTrace();
            throw new RuntimeException(t.getMessage(), t);
        }
    }
    
    public static byte[] encryptData(byte[] data, PublicKey publicKey)
    {
        Cipher cipher=null;
        try
        {
            cipher=Cipher.getInstance("Kyber", "BCPQC");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return cipher.doFinal(data);
        } catch (Throwable t) {
            t.printStackTrace();
            throw new RuntimeException(t.getMessage(), t);
        }
    }
    
    public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey)
    {
        Cipher cipher=null;
        try
        {
            cipher=Cipher.getInstance("Kyber", "BCPQC");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return cipher.doFinal(encryptedData);
        } catch (Throwable t) {
            t.printStackTrace();
            throw new RuntimeException(t.getMessage(), t);
        }
    }
    
    public static void main(String[] args) {
        KeyPair keyPair=generateKeyPair();
        byte[] publicKeyData=keyPair.getPublic().getEncoded();
        byte[] privateKeyData=keyPair.getPrivate().getEncoded();
        String publicKeyHex=Hex.toHexString(publicKeyData);
        String privateKeyHex=Hex.toHexString(privateKeyData);
        System.out.println("Public key length " + keyPair.getPublic().getEncoded().length + " format " + keyPair.getPublic().getFormat() + " algorithm " + keyPair.getPublic().getAlgorithm());
        System.out.println("Public Key ");
        System.out.println(publicKeyHex);
        System.out.println("Private key length " + keyPair.getPrivate().getEncoded().length + " format " + keyPair.getPrivate().getFormat() + " algorithm " + keyPair.getPrivate().getAlgorithm());
        System.out.println("Private Key ");
        System.out.println(privateKeyHex);
        String message="Hello World!";
        byte[] encryptedData=encryptData(message.getBytes(), keyPair.getPublic());
        String encryptedDataStr=DatatypeConverter.printBase64Binary(encryptedData);
        System.out.println("encrypted:" + encryptedDataStr);
        byte[] decryptedData=decryptData(encryptedData, keyPair.getPrivate());
        String decrtyptedDataStr=new String(decryptedData);
        System.out.println("decrypted:" + decrtyptedDataStr);
    }

However when running this code, getting some exceptions during encryption, getting Cipher only valid for wrapping/unwrapping exception

java.security.InvalidParameterException: Cipher only valid for wrapping/unwrapping

What am I doing wrong?

Upvotes: 0

Views: 495

Answers (1)

Myungkyu Jung
Myungkyu Jung

Reputation: 1

ML-KEM using encapsulation/decapsulation instead of encrypt/decrypt. (refer https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf)

and I used bouncycastle v1.79

static {
    Security.addProvider(new BouncyCastleProvider());
}

@Test
public void MLKEM_PKCS_Test(){
    try{
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ML-KEM-512", "BC");
        KeyPair keyPair = keyGen.generateKeyPair();

        PrivateKey privateKey = keyPair.getPrivate();
        System.out.println("Private Key: " + DatatypeConverter.printHexBinary(privateKey.getEncoded()));
        MLKEMPrivateKeyParameters priKey = (MLKEMPrivateKeyParameters) PrivateKeyFactory.createKey(privateKey.getEncoded());
        System.out.println("dk: " + DatatypeConverter.printHexBinary(priKey.getEncoded()));

        PublicKey publicKey = keyPair.getPublic();
        System.out.println("Public Key: " + DatatypeConverter.printHexBinary(publicKey.getEncoded()));
        MLKEMPublicKeyParameters pubKey = (MLKEMPublicKeyParameters)PublicKeyFactory.createKey(publicKey.getEncoded());
        System.out.println("ek: " + DatatypeConverter.printHexBinary(pubKey.getEncoded()));

        MLKEMGenerator mlkemGenerator = new MLKEMGenerator(new SecureRandom());
        SecretWithEncapsulation encaps = mlkemGenerator.generateEncapsulated(pubKey);
        System.out.println("Cipher: "+DatatypeConverter.printHexBinary(encaps.getEncapsulation()));
        System.out.println("secret(encap): " + DatatypeConverter.printHexBinary(encaps.getSecret()));

        MLKEMExtractor mlkemExtractor = new MLKEMExtractor(priKey);
        byte[] secret = mlkemExtractor.extractSecret(encaps.getEncapsulation());
        System.out.println("secret(decap): " + DatatypeConverter.printHexBinary(secret));


    } catch (Exception e) {
        e.printStackTrace();
    }
}

Upvotes: 0

Related Questions