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

C# 常用加密演算法實作:MD5、DES/AES 相容性指南

     編輯:關於C語言

前言

跨語言系統整合(ASP/ASP.NET、PHP、Java、Python、Go)常面臨加密演算法相容性問題。本文提供 C# 實作的 MD5(16/32位)、AES(ECB/CBC 模式)標準代碼,確保與其他語言互通。

⚠️ 安全性警示

MD5 已被破解,不可用於密碼儲存、簽名驗證、安全關鍵場景。
僅適用於:非安全檢查和、快取鍵、資料完整性非惡意竄改檢查。

DES 已淘汰(56-bit 金鑰可暴力破解),請改用 AES-256。
本文保留 DES 代碼僅供舊系統相容維護。

MD5 相容性實作


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

public static class Md5Compat
{
    /// 
    /// 相容舊版 ASP/動網/DVBBS 的 16/32 位 MD5
    /// 核心差異:取 hash 陣列的不同區段
    /// 
    public static string Compute(string input, int length = 32)
    {
        if (string.IsNullOrEmpty(input)) return string.Empty;
        
        byte[] bytes = Encoding.ASCII.GetBytes(input); // 關鍵:ASCII 編碼
        byte[] hash = MD5.Create().ComputeHash(bytes);
        
        var sb = new StringBuilder();
        switch (length)
        {
            case 16: // 取中間 8 bytes (索引 4-11) → 16 字元
                for (int i = 4; i < 12; i++)
                    sb.Append(hash[i].ToString("x2"));
                break;
            case 32: // 完整 16 bytes → 32 字元
                for (int i = 0; i < 16; i++)
                    sb.Append(hash[i].ToString("x2"));
                break;
            default: // 標準完整輸出
                for (int i = 0; i < hash.Length; i++)
                    sb.Append(hash[i].ToString("x2"));
                break;
        }
        return sb.ToString();
    }

    // 標準 MD5 (32 位小寫)
    public static string Standard(string input) => Compute(input, 32);
}

跨語言驗證對照表

語言/實作輸入16位輸出32位輸出
C# Md5Compat.Compute("test", 16)test098f6bcd4621d373098f6bcd4621d373cade4e832627b4f6
PHP md5("test")test-098f6bcd4621d373cade4e832627b4f6
Python hashlib.md5(b"test").hexdigest()test-098f6bcd4621d373cade4e832627b4f6
Java MessageDigest.getInstance("MD5")test-098f6bcd4621d373cade4e832627b4f6
ASP 動網 16位test098f6bcd4621d373-

AES 加密 (取代 DES) - 現代標準


using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class AesEncryption
{
    // 金鑰必須 16/24/32 bytes (AES-128/192/256)
    // IV 必須 16 bytes (AES 區塊大小)
    private static readonly byte[] DefaultKey = Encoding.UTF8.GetBytes("0123456789abcdef0123456789abcdef"); // 32 bytes = AES-256
    private static readonly byte[] DefaultIV = Encoding.UTF8.GetBytes("abcdef0123456789"); // 16 bytes

    /// 
    /// AES-CBC 加密 (推薦模式),輸出 Base64
    /// 
    public static string Encrypt(string plainText, byte[] key = null, byte[] iv = null)
    {
        key ??= DefaultKey;
        iv ??= DefaultIV;
        
        using (Aes aes = Aes.Create())
        {
            aes.Key = key;
            aes.IV = iv;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7; // 標準填充,跨語言相容
            
            using (MemoryStream ms = new MemoryStream())
            using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
            using (StreamWriter sw = new StreamWriter(cs, Encoding.UTF8))
            {
                sw.Write(plainText);
            }
            return Convert.ToBase64String(ms.ToArray());
        }
    }

    /// 
    /// AES-CBC 解密
    /// 
    public static string Decrypt(string cipherTextBase64, byte[] key = null, byte[] iv = null)
    {
        key ??= DefaultKey;
        iv ??= DefaultIV;
        
        byte[] cipherBytes = Convert.FromBase64String(cipherTextBase64);
        
        using (Aes aes = Aes.Create())
        {
            aes.Key = key;
            aes.IV = iv;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            
            using (MemoryStream ms = new MemoryStream(cipherBytes))
            using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))
            using (StreamReader sr = new StreamReader(cs, Encoding.UTF8))
            {
                return sr.ReadToEnd();
            }
        }
    }
}

舊版 DES 相容代碼 (僅供維護)


public static class DesCompat
{
    // 關鍵:ECB 模式 + ZeroPadding 才能與 Perl/PHP/Java 老版 DES 相容
    private static readonly byte[] DesKey = new byte[] 
    { 
        0x82, 0xBC, 0xA1, 0x6A, 0xF5, 0x87, 0x3B, 0xE6 
    }; // 8 bytes = 64 bits (含 8 位 parity 實際 56 bits)

    public static string Encrypt(string plainText)
    {
        using (var des = DES.Create())
        {
            des.Key = DesKey;
            des.Mode = CipherMode.ECB;        // 關鍵:ECB 模式
            des.Padding = PaddingMode.Zeros;  // 關鍵:ZeroPadding
            
            using (var ms = new MemoryStream())
            using (var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
            {
                byte[] input = Encoding.Unicode.GetBytes(plainText); // 關鍵:Unicode 編碼
                cs.Write(input, 0, input.Length);
                cs.FlushFinalBlock();
                return Convert.ToBase64String(ms.ToArray());
            }
        }
    }

    public static string Decrypt(string cipherText)
    {
        using (var des = DES.Create())
        {
            des.Key = DesKey;
            des.Mode = CipherMode.ECB;
            des.Padding = PaddingMode.Zeros;
            
            byte[] input = Convert.FromBase64String(cipherText);
            using (var ms = new MemoryStream(input))
            using (var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read))
            using (var sr = new StreamReader(cs, Encoding.Unicode))
            {
                return sr.ReadToEnd();
            }
        }
    }
}

跨語言 AES 參數對照表 (CBC + PKCS7 + Base64)

參數C#JavaPythonPHPNode.js
演算法AES/CBC/PKCS7PaddingAES/CBC/PKCS5PaddingAES.MODE_CBCaes-256-cbcaes-256-cbc
金鑰長度32 bytes32 bytes32 bytes32 bytes32 bytes
IV 長度16 bytes16 bytes16 bytes16 bytes16 bytes
編碼UTF-8 → Base64UTF-8 → Base64UTF-8 → Base64UTF-8 → Base64UTF-8 → Base64
填充PKCS7PKCS5 (同 PKCS7)自動自動自動

密碼儲存正確做法:PBKDF2 / Argon2 / Bcrypt


using System.Security.Cryptography;

public static class PasswordHash
{
    // 驗證密碼
    public static bool Verify(string password, string hashBase64)
    {
        byte[] hashBytes = Convert.FromBase64String(hashBase64);
        // 格式: [salt(16)][iterations(4)][hash(32)]
        byte[] salt = hashBytes[0..16];
        int iterations = BitConverter.ToInt32(hashBytes[16..20]);
        byte[] expectedHash = hashBytes[20..52];
        
        using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA256))
        {
            byte[] actualHash = pbkdf2.GetBytes(32);
            return CryptographicOperations.FixedTimeEquals(actualHash, expectedHash);
        }
    }

    // 雜湊密碼
    public static string Hash(string password, int iterations = 100000)
    {
        byte[] salt = RandomNumberGenerator.GetBytes(16);
        using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA256))
        {
            byte[] hash = pbkdf2.GetBytes(32);
            var result = new byte[52];
            Buffer.BlockCopy(salt, 0, result, 0, 16);
            Buffer.BlockCopy(BitConverter.GetBytes(iterations), 0, result, 16, 4);
            Buffer.BlockCopy(hash, 0, result, 20, 32);
            return Convert.ToBase64String(result);
        }
    }
}

總結

  • MD5:僅用於非安全場景相容,16位取 hash[4..11],32位取完整 hash
  • DES:已淘汰,相容需 ECB + ZeroPadding + Unicode 編碼 + Base64
  • AES:現代標準,CBC + PKCS7 + Base64,金鑰 32 bytes,IV 16 bytes
  • 密碼:嚴禁 MD5/SHA 直接雜湊,必須用 PBKDF2/Argon2/Bcrypt + 高迭代 + 隨機鹽
  • 金鑰管理:勿硬編碼,使用 Key Vault、環境變數、HSM
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved