使用BouncyCastle 1.78.1实现Kyber加密时报错:Cipher仅支持包装/解包
解决Kyber1024加密时抛出"Cipher only valid for wrapping/unwrapping"异常的问题
你遇到的问题根源在于Kyber是密钥交换/封装算法(KEM),不是直接的明文加密算法,而且在BouncyCastle 1.78.1版本中,Kyber对应的Cipher实现仅支持密钥的封装(wrap)和解封装(unwrap)操作,不能直接用来加密明文。
正确的处理方式
应该使用BouncyCastle提供的KeyEncapsulation类来处理Kyber的密钥封装逻辑,生成共享密钥后,再用对称加密算法(比如AES)来加密实际的明文数据。以下是修正后的代码示例:
1. 注册BouncyCastle PQC提供者
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; import java.security.Security; public class KyberExample { static { Security.addProvider(new BouncyCastleProvider()); Security.addProvider(new BouncyCastlePQCProvider()); } }
2. 生成Kyber1024密钥对
import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.SecureRandom; public class KyberExample { // ... 注册提供者代码 ... public static KeyPair generateKyber1024KeyPair() throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("Kyber1024", "BCPQC"); kpg.initialize(1024, new SecureRandom()); return kpg.generateKeyPair(); } }
3. 密钥封装(生成共享密钥并封装)
import org.bouncycastle.pqc.jcajce.provider.kyber.BCKyberPublicKey; import org.bouncycastle.pqc.jcajce.interfaces.KyberKey; import org.bouncycastle.pqc.jcajce.spec.KyberParameterSpec; import javax.crypto.SecretKey; import org.bouncycastle.pqc.jcajce.provider.KeyEncapsulation; public class KyberExample { // ... 其他代码 ... public static byte[] encapsulateKey(BCKyberPublicKey publicKey, SecretKey outSecretKey) throws Exception { KeyEncapsulation kem = KeyEncapsulation.getInstance("Kyber1024", "BCPQC"); kem.init(publicKey, new SecureRandom()); // 生成封装后的密钥(用于传输给私钥持有者),同时生成共享对称密钥 return kem.generateSecret(outSecretKey); } }
4. 密钥解封装(恢复共享密钥)
import org.bouncycastle.pqc.jcajce.provider.kyber.BCKyberPrivateKey; public static SecretKey decapsulateKey(BCKyberPrivateKey privateKey, byte[] encapsulatedKey) throws Exception { KeyEncapsulation kem = KeyEncapsulation.getInstance("Kyber1024", "BCPQC"); kem.init(privateKey); return kem.decryptSecret(encapsulatedKey); }
5. 使用共享密钥加密解密明文
拿到共享密钥后,就可以用标准对称加密算法(比如AES-GCM)处理明文:
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; public static byte[] encryptWithAES(SecretKey secretKey, byte[] plaintext) throws Exception { Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] iv = cipher.getIV(); byte[] ciphertext = cipher.doFinal(plaintext); // 合并IV和密文(解密时需要IV) byte[] result = new byte[iv.length + ciphertext.length]; System.arraycopy(iv, 0, result, 0, iv.length); System.arraycopy(ciphertext, 0, result, iv.length, ciphertext.length); return result; } public static byte[] decryptWithAES(SecretKey secretKey, byte[] encryptedData) throws Exception { int ivLength = 12; // AES-GCM推荐的IV长度 byte[] iv = new byte[ivLength]; byte[] ciphertext = new byte[encryptedData.length - ivLength]; System.arraycopy(encryptedData, 0, iv, 0, ivLength); System.arraycopy(encryptedData, ivLength, ciphertext, 0, ciphertext.length); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC"); GCMParameterSpec spec = new GCMParameterSpec(128, iv); cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); return cipher.doFinal(ciphertext); }
为什么原来的Cipher调用会报错
在BouncyCastle 1.78.1中,Kyber的Cipher实现是为了兼容密钥封装的wrap/unwrap操作设计的,它只能用来封装对称密钥,不能直接处理明文。如果你一定要用Cipher来做密钥封装,代码应该是这样,但依然不能直接加密明文:
// 仅用于封装对称密钥,不能加密明文 Cipher cipher = Cipher.getInstance("Kyber1024", "BCPQC"); cipher.init(Cipher.WRAP_MODE, publicKey); byte[] wrappedKey = cipher.wrap(aesSecretKey); // 封装对称密钥 // 解封装 cipher.init(Cipher.UNWRAP_MODE, privateKey); SecretKey unwrappedKey = (SecretKey) cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
总结:Kyber的核心是生成共享对称密钥,实际明文加密要交给对称算法来做,不要用Kyber的Cipher直接加密明文。
内容的提问来源于stack exchange,提问作者user25753955
相关产品推荐
相关产品推荐

