You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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);
    }
}

关键改进说明

  1. 新增独立消息加密密钥:仅加密一次原始消息,避免重复加密的性能损耗与冗余
  2. 修复CBC模式安全漏洞:补充随机初始化向量(IV),避免相同明文+密钥生成重复密文的风险
  3. 多接收方专属密钥处理:为每个接收方生成独立共享密钥加密MEK,确保只有对应接收方能解密出MEK
  4. 高扩展性:只需添加新接收方公钥到列表,即可无缝支持更多用户,无需修改核心加密逻辑

内容的提问来源于stack exchange,提问作者Toxic Tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 23:54:23