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

C# 實現 PDF 文件完整性驗證:基於 MD5 的簡易數字水印

     編輯:關於C語言

需求背景

用戶掃描發票生成 PDF 上傳,服務端需驗證文件未被篡改。傳統數字簽名/水印方案較重,本文實現輕量級「尾部追加 MD5」方案。

核心原理

  1. 客戶端:計算 PDF 字節流 MD5 → 追加至文件末尾 → 保存。
  2. 服務端:讀取文件,排除末尾 32 字節(MD5 長度)重新計算 MD5 → 與尾部存儲值比對 → 一致則通過。
  3. 關鍵點:不修改原有字節,僅尾部追加,保證 PDF 結構完整,不觸發「文件修復」提示。

完整代碼實現


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

public static class PdfIntegrity
{
    // 客戶端:簽名並追加
    public static string Sign(string filePath, string secretKey)
    {
        byte[] pdfBytes = File.ReadAllBytes(filePath);
        string md5 = ComputeMd5(pdfBytes, 0, pdfBytes.Length);
        md5 = ComputeMd5(Encoding.ASCII.GetBytes(md5 + secretKey)); // 加鹽

        byte[] md5Bytes = Encoding.ASCII.GetBytes(md5);
        File.WriteAllBytes(filePath, pdfBytes.Concat(md5Bytes).ToArray());
        return md5;
    }

    // 服務端:驗證
    public static bool Verify(string filePath, string secretKey)
    {
        try
        {
            byte[] allBytes = File.ReadAllBytes(filePath);
            if (allBytes.Length < 32) return false;

            byte[] pdfBytes = new byte[allBytes.Length - 32];
            Array.Copy(allBytes, pdfBytes, pdfBytes.Length);
            byte[] storedMd5Bytes = new byte[32];
            Array.Copy(allBytes, pdfBytes.Length, storedMd5Bytes, 0, 32);

            string calcMd5 = ComputeMd5(pdfBytes, 0, pdfBytes.Length);
            calcMd5 = ComputeMd5(Encoding.ASCII.GetBytes(calcMd5 + secretKey));
            string storedMd5 = Encoding.ASCII.GetString(storedMd5Bytes);

            return calcMd5 == storedMd5;
        }
        catch { return false; }
    }

    private static string ComputeMd5(byte[] buffer, int offset, int count)
    {
        using (MD5 md5 = MD5.Create())
        {
            byte[] hash = md5.ComputeHash(buffer, offset, count);
            return BitConverter.ToString(hash).Replace("-", "").ToLower();
        }
    }

    private static string ComputeMd5(byte[] buffer) => ComputeMd5(buffer, 0, buffer.Length);
}

關鍵細節

  • 加鹽:secretKey 防止第三方偽造 MD5,即使知道算法也無法生成正確簽名。
  • 流式處理:大文件建議用 FileStream 分塊計算 MD5,避免一次性載入內存。
  • 通用性:同樣適用於圖片、Office 文檔等任意二進制格式,只需確保尾部追加不破壞格式解析。

安全性評估

生產環境建議

  • 升級至 SHA256 + HMAC(HMACSHA256)。
  • 引入時間戳、Nonce、版本號等元數據,構建完整簽名結構。
  • 考慮使用 PDF 標準數字簽名(PKCS#7),獲得法律效力與通用驗證工具支持。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
威脅防護程度說明
內容篡改高任何字節變動導致 MD5 不匹配
截斷/追加攻擊中攻擊者若不知 secretKey 無法重新計算尾部 MD5
碰撞攻擊低MD5 已知碰撞漏洞,高安全場景建議升級 SHA-256
重放攻擊無未包含時間戳/隨機數,同一文件可重複上傳