[Wikipedia] Key encapsulation mechanisms (KEMs) are a class of encryption techniques designed to secure symmetric cryptographic key material for transmission using asymmetric (public-key) algorithms. In practice, public key systems are clumsy to use in transmitting long messages. Instead they are often used to exchange symmetric keys, which are relatively short. The symmetric key is then used to encrypt the longer message. The traditional approach to sending a symmetric key with public key systems is to first generate a random symmetric key and then encrypt it using the chosen public key algorithm. The recipient then decrypts the public key message to recover the symmetric key. As the symmetric key is generally short, padding is required for full security and proofs of security for padding schemes are often less than complete. KEMs simplify the process by generating a random element in the finite group underlying the public key system and deriving the symmetric key by hashing that element, eliminating the need for padding.
Arcanum provides a support class called KEMCipher which simplifies the integration of a KEM and a Cipher. The following is an example of how to use the class.
1 package it.unisa.dia.gas.crypto.kem; 2 3 import it.unisa.dia.gas.crypto.circuit.Circuit; 4 import it.unisa.dia.gas.crypto.circuit.DefaultCircuit; 5 import it.unisa.dia.gas.crypto.arcanum.fe.abe.gghsw13.engines.GGHSW13KEMEngine; 6 import it.unisa.dia.gas.crypto.arcanum.fe.abe.gghsw13.generators.GGHSW13KeyPairGenerator; 7 import it.unisa.dia.gas.crypto.arcanum.fe.abe.gghsw13.generators.GGHSW13ParametersGenerator; 8 import it.unisa.dia.gas.crypto.arcanum.fe.abe.gghsw13.generators.GGHSW13SecretKeyGenerator; 9 import it.unisa.dia.gas.crypto.arcanum.fe.abe.gghsw13.params.*; 10 import it.unisa.dia.gas.crypto.kem.cipher.engines.KEMCipher; 11 import it.unisa.dia.gas.crypto.kem.cipher.params.KEMCipherDecryptionParameters; 12 import it.unisa.dia.gas.crypto.kem.cipher.params.KEMCipherEncryptionParameters; 13 import PairingFactory; 14 import ExecutorServiceUtils; 15 import org.bouncycastle.crypto.AsymmetricCipherKeyPair; 16 import org.bouncycastle.crypto.CipherParameters; 17 import org.bouncycastle.jce.provider.BouncyCastleProvider; 18 19 import javax.crypto.Cipher; 20 import javax.crypto.spec.IvParameterSpec; 21 import java.security.GeneralSecurityException; 22 import java.security.SecureRandom; 23 import java.security.Security; 24 import java.security.spec.AlgorithmParameterSpec; 25 26 import static it.unisa.dia.gas.crypto.circuit.Circuit.Gate.Type.*; 27 import static org.junit.Assert.assertEquals; 28 29 30 /** 31 * @author Angelo De Caro (arcanumlib@gmail.com) 32 */ 33 public class KEMCipherGGHSW13KEM { 34 protected KEMCipher kemCipher; 35 protected AlgorithmParameterSpec iv; 36 37 protected AsymmetricCipherKeyPair keyPair; 38 39 40 public KEMCipherGGHSW13KEM() throws GeneralSecurityException { 41 this.kemCipher = new KEMCipher( 42 Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"), 43 new GGHSW13KEMEngine() 44 ); 45 46 // build the initialization vector. This example is all zeros, but it 47 // could be any value or generated using a random number generator. 48 iv = new IvParameterSpec(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); 49 } 50 51 52 public AsymmetricCipherKeyPair setup(int n) { 53 GGHSW13KeyPairGenerator setup = new GGHSW13KeyPairGenerator(); 54 setup.init(new GGHSW13KeyPairGenerationParameters( 55 new SecureRandom(), 56 new GGHSW13ParametersGenerator().init( 57 PairingFactory.getPairing("params/mm/ctl13/toy.properties"), 58 n).generateParameters() 59 )); 60 61 return (keyPair = setup.generateKeyPair()); 62 } 63 64 65 public byte[] initEncryption(String assignment) { 66 try { 67 return kemCipher.init( 68 true, 69 new KEMCipherEncryptionParameters( 70 128, 71 new GGHSW13EncryptionParameters( 72 (GGHSW13PublicKeyParameters) keyPair.getPublic(), 73 assignment 74 ) 75 ), 76 iv 77 ); 78 } catch (Exception e) { 79 throw new RuntimeException(e); 80 } 81 } 82 83 public byte[] encrypt(String message) { 84 try { 85 return kemCipher.doFinal(message.getBytes()); 86 } catch (Exception e) { 87 throw new RuntimeException(e); 88 } 89 } 90 91 92 public CipherParameters keyGen(Circuit circuit) { 93 GGHSW13SecretKeyGenerator keyGen = new GGHSW13SecretKeyGenerator(); 94 keyGen.init(new GGHSW13SecretKeyGenerationParameters( 95 (GGHSW13PublicKeyParameters) keyPair.getPublic(), 96 (GGHSW13MasterSecretKeyParameters) keyPair.getPrivate(), 97 circuit 98 )); 99 100 return keyGen.generateKey(); 101 } 102 103 public byte[] decrypt(CipherParameters secretKey, byte[] encapsulation, byte[] ciphertext) { 104 try { 105 kemCipher.init( 106 false, 107 new KEMCipherDecryptionParameters(secretKey, encapsulation, 128), 108 iv 109 ); 110 return kemCipher.doFinal(ciphertext); 111 } catch (Exception e) { 112 throw new RuntimeException(e); 113 } 114 } 115 116 117 118 public static void main(String[] args) { 119 Security.addProvider(new BouncyCastleProvider()); 120 121 try { 122 // Setup 123 int n = 4; 124 KEMCipherGGHSW13KEM engine = new KEMCipherGGHSW13KEM(); 125 engine.setup(n); 126 127 // Encrypt 128 String message = "Hello World!!!"; 129 byte[] encapsulation = engine.initEncryption("1101"); 130 byte[] ciphertext = engine.encrypt(message); 131 132 // Decrypt 133 int q = 3; 134 Circuit circuit = new DefaultCircuit(n, q, 3, new DefaultCircuit.DefaultGate[]{ 135 new DefaultCircuit.DefaultGate(INPUT, 0, 1), 136 new DefaultCircuit.DefaultGate(INPUT, 1, 1), 137 new DefaultCircuit.DefaultGate(INPUT, 2, 1), 138 new DefaultCircuit.DefaultGate(INPUT, 3, 1), 139 140 new DefaultCircuit.DefaultGate(AND, 4, 2, new int[]{0, 1}), 141 new DefaultCircuit.DefaultGate(OR, 5, 2, new int[]{2, 3}), 142 143 new DefaultCircuit.DefaultGate(AND, 6, 3, new int[]{4, 5}), 144 }); 145 byte[] plaintext = engine.decrypt(engine.keyGen(circuit), encapsulation, ciphertext); 146 147 assertEquals(true, message.equals(new String(plaintext))); 148 } catch (Exception e) { 149 e.printStackTrace(); 150 } finally { 151 ExecutorServiceUtils.shutdown(); 152 } 153 } 154 155 }