使用 C# 實現資料不落地加密 ZIP 壓縮
6 |
工作上有愈來愈多需要加密壓縮的場合,過去我慣用的做法是從 C# 呼叫外部程式,借助 7z.exe 完成任務。不方便之處是我必須先將要打包加密的內容依目錄結構寫成暫存檔,再交給 7-Zip 處理,且做完必須刪檔抹去足跡。這裡隱藏一個危機,若程式在寫暫存檔到刪檔前出錯,便可能殘留明文內容,有資訊外流風險。因此,讓加密壓縮過程完全在記憶體裡完成是較完美的做法。
過去我有示範過用 .NET 4.5 的 ZipArchive、ZipFile 實現 byte[] 不落地壓縮 ZIP 檔,可惜它無法支援加密。放心,.NET 開發社群是很強大的,你想得到的需求幾乎都有解決方案。
針對本次的需求,免費的 DotNetZip Library 開源專案是個好選擇,用 NuGet 即可下載:
DotNetZip 的使用方法十分簡便,現場來個簡單範例。我打算用 C# 動態產一個 Secret.zip 檔案提供本日業績資料,其中包含兩個檔案,index.html 與 imgs\chart.png,ZIP 檔需以密碼加密。這個範例涵蓋了輸出 string 到文字檔、輸出 byte[] 到圖檔、區分資料夾結構、使用密碼加密等功能。
程式碼如下:(我還很無聊地用 Graphics 胡亂畫出長條圖 .png 練手感)
using Ionic.Zip;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
using (var zip = new ZipFile())
{
zip.Password = "P@ssW0rd";
zip.AddEntry("imgs\\chart.png", GenChart());
zip.AddEntry("index.html", $@"
<html><body>
<div>{DateTime.Today:yyyy-MM-dd} 業績</div>
<img src='imgs/chart.png' />
</body>");
zip.Save("D:\\Secret.zip");
}
}
static byte[] GenChart()
{
var bmp = new Bitmap(240, 180);
var g = Graphics.FromImage(bmp);
g.FillRectangle(new SolidBrush(Color.LightGray),
0, 0, bmp.Width, bmp.Height);
var p = new Pen(new SolidBrush(Color.Black));
var margin = 6;
g.DrawRectangle(p, margin, margin, 1, bmp.Height - margin * 2);
g.DrawRectangle(p, margin, bmp.Height - margin, bmp.Width - margin * 2, 1);
var colors = new Color[]
{
Color.Green,
Color.Brown,
Color.BlueViolet,
Color.Indigo
};
var barAreaWidth = (bmp.Width - margin * 2) / 4;
var barWidth = 40;
var rnd = new Random();
Enumerable.Range(0, 4).ToList()
.ForEach(i =>
{
var value = rnd.Next(120) + 50;
g.FillRectangle(new SolidBrush(colors[i]),
margin + i * barAreaWidth + (barAreaWidth - barWidth) / 2,
bmp.Height - margin - value,
barWidth,
value);
});
using (var ms = new MemoryStream())
{
bmp.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
}
}
}
如此,我們成功的產生加密 ZIP 檔,具備資料夾結構,過程沒產生任何暫存檔。
網頁內容檢視正常,大成功!
Example of using DotNetZip to compress data in memory to encrypted zip file
Comments
# by Bryan
7-zip 其實有 c# 的 sdk 叫 lzma sdk,請見網址 https://www.7-zip.org/sdk.html
# by Jeffrey
to Bryan,哦哦哦,好物! 感謝分享,有空來研究一下。
# by Leo
我在使用DotNetZip進行加密壓縮時,發現欲加密的檔案為0 byte時,產生的zip沒有被加密,請問黑大有遇過這個問題嗎?
# by Jeffrey
to Leo, 有點不明白,若要壓縮加密的檔案沒有任何內容,應不需要也無法加密,原本預期的結果為何?
# by Leo
to Jeffrey, 假設今日客戶要求每日固定上傳一檔案,名為log.txt,而該檔案必須壓縮加密成zip檔案,但log.txt並不一定會有內容,即使log.txt內無內容,壓縮加密後的檔案log.txt.zip也必須在解壓縮時帶入密碼才能進行解壓縮。 因使用winrar、7zip等軟體都可以達成以上需求,DotNetZip好像沒辦法,後來改用SharpZipLib時解決了這個問題。
# by Jeffrey
to Leo,明白了。ZIP檔內容的檔名跟大小不用密碼便能取得,故理論上不知密碼也能解壓出 0 Byte 檔案。但在你的情境,若沒加密得寫額外邏輯處理無內容情境,會變麻煩。