如何使用BouncyCastle C#实现多收件人数据加密?
多用户加密通信扩展方案
你的一对一加密方案基于X25519密钥协商生成共享密钥,再用DES加密消息。要扩展到多用户场景,核心思路是生成一个独立的消息加密密钥(MEK),然后分别用每个接收方对应的共享密钥加密这个MEK,最终将「加密后的消息 + 各接收方对应的加密MEK」一起发送。每个接收方用自身私钥解密出MEK,再解密消息内容。
具体实现步骤
- 生成随机的消息加密密钥(MEK),用该密钥仅加密一次原始消息
- 对每个接收方,用发送方私钥和接收方公钥生成专属共享密钥,并用此密钥加密MEK
- 接收方用自身私钥和发送方公钥生成共享密钥,解密出MEK后再解密消息
修改后的代码示例
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Agreement; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Paddings; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using System; using System.Collections.Generic; using System.Text; public class MultiUserEncryptionService { private IBlockCipher engine = new DesEngine(); private IAsymmetricCipherKeyPairGenerator keyGen = new X25519KeyPairGenerator(); private AsymmetricKeyParameter senderPrivateKey; private AsymmetricKeyParameter senderPublicKey; private List<AsymmetricKeyParameter> receiverPublicKeys = new List<AsymmetricKeyParameter>(); private Dictionary<string, byte[]> encryptedMekPerReceiver = new Dictionary<string, byte[]>(); private byte[] messageEncryptionKey; public void RunMultiUserExchange() { var plainTextMessage = AsciiStringToBytes("Hello Everyone!"); // 生成发送方密钥对 (senderPrivateKey, senderPublicKey) = GenerateKeyPair(); // 生成两个接收方密钥对 var (receiver1Private, receiver1Public) = GenerateKeyPair(); var (receiver2Private, receiver2Public) = GenerateKeyPair(); receiverPublicKeys.Add(receiver1Public); receiverPublicKeys.Add(receiver2Public); // 1. 生成随机消息加密密钥(MEK) messageEncryptionKey = GenerateRandomKey(engine.GetBlockSize()); Console.WriteLine($"消息加密密钥(MEK): {Hex.ToHexString(messageEncryptionKey)}"); // 2. 用MEK加密原始消息(仅加密一次) var encryptedMessage = Encrypt(messageEncryptionKey, plainTextMessage); Console.WriteLine($"加密后的消息: {Hex.ToHexString(encryptedMessage)}"); // 3. 为每个接收方加密MEK EncryptMekForEachReceiver(); // --- 接收方1解密流程 --- Console.WriteLine("\n=== 接收方1解密过程 ==="); var receiver1SharedSecret = GetSharedSecret(receiver1Private, senderPublicKey); var receiver1DecryptedMek = Decrypt(receiver1SharedSecret, encryptedMekPerReceiver["Receiver1"]); var receiver1DecryptedMessage = Decrypt(receiver1DecryptedMek, encryptedMessage); Console.WriteLine($"接收方1解密后的消息: {BytesToAsciiString(receiver1DecryptedMessage)}"); // --- 接收方2解密流程 --- Console.WriteLine("\n=== 接收方2解密过程 ==="); var receiver2SharedSecret = GetSharedSecret(receiver2Private, senderPublicKey); var receiver2DecryptedMek = Decrypt(receiver2SharedSecret, encryptedMekPerReceiver["Receiver2"]); var receiver2DecryptedMessage = Decrypt(receiver2DecryptedMek, encryptedMessage); Console.WriteLine($"接收方2解密后的消息: {BytesToAsciiString(receiver2DecryptedMessage)}"); } private void EncryptMekForEachReceiver() { for (int i = 0; i < receiverPublicKeys.Count; i++) { var receiverPublicKey = receiverPublicKeys[i]; var receiverId = $"Receiver{i+1}"; // 生成发送方与当前接收方的专属共享密钥 var sharedSecret = GetSharedSecret(senderPrivateKey, receiverPublicKey); // 用共享密钥加密MEK var encryptedMek = Encrypt(sharedSecret, messageEncryptionKey); encryptedMekPerReceiver.Add(receiverId, encryptedMek); Console.WriteLine($"{receiverId}对应的加密MEK: {Hex.ToHexString(encryptedMek)}"); } } private byte[] GenerateRandomKey(int keySize) { var secureRandom = new SecureRandom(); byte[] key = new byte[keySize]; secureRandom.NextBytes(key); return key; } private byte[] GetSharedSecret(AsymmetricKeyParameter privateKey, AsymmetricKeyParameter publicKey) { var keyAgreement = new X25519Agreement(); keyAgreement.Init(privateKey); byte[] sharedSecret = new byte[keyAgreement.AgreementSize]; keyAgreement.CalculateAgreement(publicKey, sharedSecret, 0); Console.WriteLine($"共享密钥: {Hex.ToHexString(sharedSecret)}"); return sharedSecret; } private (AsymmetricKeyParameter privateKey, AsymmetricKeyParameter publicKey) GenerateKeyPair() { keyGen.Init(new KeyGenerationParameters(new SecureRandom(), 256)); var pair = keyGen.GenerateKeyPair(); return (pair.Private, pair.Public); } private byte[] Encrypt(byte[] key, byte[] plainTextBytes) { // 补充CBC模式必需的随机IV,修复原代码安全隐患 var secureRandom = new SecureRandom(); byte[] iv = new byte[engine.GetBlockSize()]; secureRandom.NextBytes(iv); BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine)); cipher.Init(true, new ParametersWithIV(new KeyParameter(key), iv)); byte[] encryptedBytes = new byte[cipher.GetOutputSize(plainTextBytes.Length)]; int processed = cipher.ProcessBytes(plainTextBytes, 0, plainTextBytes.Length, encryptedBytes, 0); processed += cipher.DoFinal(encryptedBytes, processed); // 将IV与加密内容拼接,解密时需要先提取IV byte[] result = new byte[iv.Length + processed]; Array.Copy(iv, 0, result, 0, iv.Length); Array.Copy(encryptedBytes, 0, result, iv.Length, processed); return result; } private byte[] Decrypt(byte[] key, byte[] cipherText) { // 提取IV(前blockSize字节) int blockSize = engine.GetBlockSize(); byte[] iv = new byte[blockSize]; Array.Copy(cipherText, 0, iv, 0, blockSize); byte[] encryptedBytes = new byte[cipherText.Length - blockSize]; Array.Copy(cipherText, blockSize, encryptedBytes, 0, encryptedBytes.Length); BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine)); cipher.Init(false, new ParametersWithIV(new KeyParameter(key), iv)); byte[] decryptedBytes = new byte[cipher.GetOutputSize(encryptedBytes.Length)]; int processed = cipher.ProcessBytes(encryptedBytes, 0, encryptedBytes.Length, decryptedBytes, 0); processed += cipher.DoFinal(decryptedBytes, processed); // 去除填充,返回有效明文 byte[] result = new byte[processed]; Array.Copy(decryptedBytes, 0, result, 0, processed); return result; } private static byte[] AsciiStringToBytes(string text) { return Encoding.ASCII.GetBytes(text); } private static string BytesToAsciiString(byte[] bytes) { return Encoding.ASCII.GetString(bytes); } }
关键改进说明
- 新增独立消息加密密钥:仅加密一次原始消息,避免重复加密的性能损耗与冗余
- 修复CBC模式安全漏洞:补充随机初始化向量(IV),避免相同明文+密钥生成重复密文的风险
- 多接收方专属密钥处理:为每个接收方生成独立共享密钥加密MEK,确保只有对应接收方能解密出MEK
- 高扩展性:只需添加新接收方公钥到列表,即可无缝支持更多用户,无需修改核心加密逻辑
内容的提问来源于stack exchange,提问作者Toxic Tom
相关产品推荐
相关产品推荐

