首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 自製 BigInteger 實作 RSA 加解密:支援公鑰/私鑰雙向操作

     編輯:關於C#

背景與動機

.NET 內建 RSACryptoServiceProvider 僅支援「公鑰加密、私鑰解密」(數位信封) 與「私鑰簽名、公鑰驗簽」。若需「私鑰加密、公鑰解密」(如授權檔產生、客戶端驗證授權),需自行實作 RSA 原始運算。

核心數學

  • 金鑰生成:選兩大質數 p, q → n = p*q, φ(n) = (p-1)(q-1) → 選 e (通常 65537) 與 φ(n) 互質 → 計算 d ≡ e⁻¹ (mod φ(n))
  • 加密:c ≡ mᵉ (mod n)
  • 解密:m ≡ cᵈ (mod n)
  • 模冪運算:平方求模法 (Right-to-Left Binary Exponentiation)

BigInteger 精簡實作 (教學級)


public struct BigInteger
{
    private readonly uint[] _data; // little-endian 32-bit limbs
    private readonly int _sign;    // 1, 0, -1

    // 建構子、隱含轉換、ToString(16/10)、位運算、加減乘除、ModPow、ModInverse、GCD...
    // 完整實作約 300-500 行,此處略過,重點在使用層面
}

※ 生產環境請直接使用 .NET Core 2.1+ 內建 System.Numerics.BigInteger,效能經過原生優化並通過 FIPS 驗證。

RSA 封裝類別 (使用內建 BigInteger)


using System;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;

public class CustomRSA
{
    public BigInteger N { get; private set; } // 模數
    public BigInteger E { get; private set; } // 公鑰指數
    public BigInteger D { get; private set; } // 私鑰指數

    // --- 靜態工廠 ---
    public static CustomRSA Generate(int keySize = 2048)
    {
        using var rsa = RSA.Create(keySize);
        var param = rsa.ExportParameters(true);
        return new CustomRSA
        {
            N = new BigInteger(param.Modulus.Reverse().ToArray()), // BigInteger 是 little-endian
            E = new BigInteger(param.Exponent.Reverse().ToArray()),
            D = new BigInteger(param.D.Reverse().ToArray())
        };
    }

    public static CustomRSA FromParameters(BigInteger n, BigInteger e, BigInteger d) => new() { N = n, E = e, D = d };

    // --- 核心運算 ---
    private byte[] ProcessBlock(byte[] block, BigInteger exp)
    {
        var m = new BigInteger(block.Concat(new byte[] { 0 }).ToArray()); // 確保正數
        var c = BigInteger.ModPow(m, exp, N);
        var bytes = c.ToByteArray(true, true); // little-endian, unsigned
        return bytes;
    }

    // --- 公鑰加密 / 私鑰解密 (標準用法) ---
    public byte[] EncryptPublic(string plainText, Encoding encoding = null)
    {
        encoding ??= Encoding.UTF8;
        byte[] data = encoding.GetBytes(plainText);
        return ProcessData(data, E, 245); // 2048-bit key: max 245 bytes per block (PKCS#1 v1.5 padding 需預留 11 bytes)
    }

    public string DecryptPrivate(byte[] cipherText, Encoding encoding = null)
    {
        encoding ??= Encoding.UTF8;
        byte[] data = ProcessData(cipherText, D, 256);
        return encoding.GetString(data);
    }

    // --- 私鑰加密 / 公鑰解密 (簽名/授權檔場景) ---
    public byte[] EncryptPrivate(string plainText, Encoding encoding = null)
    {
        encoding ??= Encoding.UTF8;
        byte[] data = encoding.GetBytes(plainText);
        return ProcessData(data, D, 245);
    }

    public string DecryptPublic(byte[] cipherText, Encoding encoding = null)
    {
        encoding ??= Encoding.UTF8;
        byte[] data = ProcessData(cipherText, E, 256);
        return encoding.GetString(data);
    }

    // --- 分塊處理 (無 Padding 教學版,生產必須加 OAEP/PKCS#1 v1.5) ---
    private byte[] ProcessData(byte[] data, BigInteger exp, int blockSize)
    {
        using var ms = new MemoryStream();
        for (int i = 0; i < data.Length; i += blockSize)
        {
            int len = Math.Min(blockSize, data.Length - i);
            byte[] block = new byte[len];
            Buffer.BlockCopy(data, i, block, 0, len);
            byte[] processed = ProcessBlock(block, exp);
            // 固定輸出長度 (256 bytes for 2048-bit)
            if (processed.Length < 256) Array.Resize(ref processed, 256);
            ms.Write(processed, 0, 256);
        }
        return ms.ToArray();
    }
}

使用範例


// 產生金鑰對
var rsa = CustomRSA.Generate(2048);
Console.WriteLine($"N: {rsa.N.ToString("X")}");
Console.WriteLine($"E: {rsa.E.ToString("X")}");
Console.WriteLine($"D: {rsa.D.ToString("X")}");

// 標準加解密
string secret = "機密資料";
byte[] enc = rsa.EncryptPublic(secret);
string dec = rsa.DecryptPrivate(enc);
Console.WriteLine($"解密: {dec}"); // 機密資料

// 私鑰加密、公鑰解密 (授權檔)
string license = "USER=John;EXP=2025-12-31";
byte[] licEnc = rsa.EncryptPrivate(license);
string licDec = rsa.DecryptPublic(licEnc);
Console.WriteLine($"授權驗證: {licDec}");

安全性警示 (必讀)

風險說明對策
無 Padding教學碼直接對明文模冪,極不安全 (可被選定明文攻擊、同態性攻擊)生產必須使用 OAEP Padding (加密) / PSS Padding (簽名)
時序攻擊ModPow 執行時間隨私鑰位元而異使用常數時間實作或 .NET 內建 RSA 類別
金鑰長度1024-bit 已不安全最小 2048-bit,建議 3072/4096-bit
私鑰儲存明文儲存 D 參數極危險使用 RSA.ExportEncryptedPkcs8PrivateKey、HSM、Azure Key Vault、DPAPI

總結

理解 RSA 數學原理與 BigInteger.ModPow 核心運算,有助於除錯互通問題、實作跨平台授權驗證、教學示範。**生產系統嚴禁使用無 Padding 的教學級實作**,請直接呼叫 .NET 內建 RSA / ECDsa 或成熟函式庫 (BouncyCastle, libsodium.net)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved