有效的資料處理:使用Tango庫進行壓縮和加密
目錄
用於記憶體中gzip和lzma壓縮的.NET庫與基於強blakeb的流密碼引擎結合使用。
介紹
該專案為記憶體資料(如byte陣列和MemoryStream)壓縮和加密引入了一個自持的.NET庫(dll)。當然,處理後的輸出可以儲存到硬碟中,但專案集中在有效的記憶體資料處理方方法上。
壓縮
壓縮的明顯選擇是內建的.NET GZip功能和7Zip SDK C#實現提供的LZM演算法,這是迄今為止最有效的壓縮功能。
由於專案的目的是直接記憶體轉換,因此它不提供具有特定頭結構的7Zip檔案。該庫呼叫GZip和LZM壓縮演算法,使用並行程式設計來縮小/擴充記憶體資料,以利用多個CPU核心。
庫可用的壓縮選項來自以下內容
public enum CompressionAlgo {
GZip_All,
GZip1,
GZip2,
GZip4,
GZip8,
LZMA_All,
LZMA1,
LZMA2,
LZMA4,
LZMA8,
None
}
其中1,2,4,8代表壓縮期間要處理的處理器數量,Gzip_All
提供的功能的主要和唯一的目的是記憶體操作。因此儲存到硬碟的單執行緒LZMA1壓縮結果(位元組陣列)形成了可以使用7zip應用程式開啟的正確7z檔案,但多執行緒選項不能提供格式良好的7z檔案。
加密
對於加密部分,該庫引入了基於BlakeB壓縮功能的快速流密碼,由Samuel Neves,Christian Winnerlein和Uli Riehm實現。
BlakeB壓縮功能在生成器的核心工作,該生成器在輸入的鍵、鹽(salt)和分佈值中建立使用者獨有的輸出位元組陣列(pad
生成的pad以下列方式用於加密/解密:
加密:純文字(位元組陣列p)XOR pad =>密文(位元組陣列x)
解密:密文(x)XOR pad =>純文字(p)
由於加密和解密功能都只是使用pad對位元組進行異或,因此密碼引擎包括覆蓋這兩種情況的單個函式Crypt,併為我們提供了流密碼實現。
發生器(程式中的BGen類)和流密碼(程式中的Streamer類)都使用多核處理器以並行模式工作。
例如,如果機器有8個處理器,則生成器將生成8個並行陣列並將它們粘合到單個輸出(pad)中。不用說,這些陣列保證是獨一無二的,不會重複。
類似地,Streamer將輸入流分成8個部分,與填充的8個相應部分進行異或,併產生彙總結果。
讓我們對BlakeB功能進行一些修改。
核心壓縮功能由這些塊組成
v0 = v0 + v4 + m0;
v12 = v12 ^ v0;
v12 = ((v12 >> 32) | (v12 << (32)));
v8 = v8 + v12;
v4 = v4 ^ v8;
v4 = ((v4 >> 24) | (v4 << (40)));
v0 = v0 + v4 + m1;
v12 = v12 ^ v0;
v12 = ((v12 >> 16) | (v12 << (48)));
v8 = v8 + v12;
v4 = v4 ^ v8;
v4 = ((v4 >> 63) | (v4 << (1)));
v1 = v1 + v5 + m2;
v13 = v13 ^ v1;
v13 = ((v13 >> 32) | (v13 << (32)));
v9 = v9 + v13;
v5 = v5 ^ v9;
v5 = ((v5 >> 24) | (v5 << (40)));
v1 = v1 + v5 + m3;
v13 = v13 ^ v1;
v13 = ((v13 >> 16) | (v13 << (48)));
v9 = v9 + v13;
v5 = v5 ^ v9;
v5 = ((v5 >> 63) | (v5 << (1)));
...
具有重複的移位常數32,24,16和63.每個常數在12輪處理中出現96次,總共384次。
為了使對手的生活更有趣,當前的實現最初基於使用者密碼(金鑰),鹽(salt)和分佈輸入生成位元組陣列S [384]。這允許在壓縮函式中有以下模式:
int i = 0;
v0 = v0 + v4 + m0;
v12 = v12 ^ v0;
v12 = RR(v12, S[i++]);
v8 = v8 + v12;
v4 = v4 ^ v8;
v4 = RR(v4, S[i++]);
v0 = v0 + v4 + m1;
v12 = v12 ^ v0;
v12 = RR(v12, S[i++]);
v8 = v8 + v12;
v4 = v4 ^ v8;
v4 = RR(v4, S[i++]);
...
其中RR是右移函式
private ulong RR(ulong x, byte n) {
return (x >> n) | (x << (-n & 63));
}
因此,壓縮函式利用取決於使用者輸入的金鑰,鹽(salt)和分佈的唯一組384個移位數(位元組),從而消除來自計算的任意常數。
生成器中唯一的常量是程式設計師定義的ulongs:
private const ulong IV0 = 9111111111111111111;
private const ulong IV1 = 8222222222222222222;
private const ulong IV2 = 7333333333333333333;
private const ulong IV3 = 6444444444444444444;
private const ulong IV4 = 5555555555555555555;
private const ulong IV5 = 4666666666666666666;
private const ulong IV6 = 3777777777777777777;
private const ulong IV7 = 2888888888888888888;
private const ulong IV8 = 1999999999999999999;
private const ulong IV9 = 1111111111111111111;
private const ulong IV10 = 2222222222222222222;
private const ulong IV11 = 3333333333333333333;
private const ulong IV12 = 4444444444444444444;
private const ulong IV13 = 5555555555555555555;
private const ulong IV14 = 6666666666666666666;
private const ulong IV15 = 7777777777777777777;
private const ulong FNL0 = 123456789;
private const ulong FNL1 = 987654321;
在您的實現中設定唯一常量,並享受可靠靈活的個人流密碼,其中沒有任何外部預定義。
使用者提供的鹽(salt)和分佈輸入會影響生成器的初始狀態,因此會增加結果的分散。
Tango庫
Tango庫的Tang類是一個單一的入口點,具有僅用於壓縮、僅用於加密或同時用於兩者的介面。
這是建構函式用法示例。
壓縮
Tang tang1 = new Tang(CompressionAlgo.GZip1); // use GZip on 1 processor
Tang tang2 = new Tang(CompressionAlgo.LZMA8); // use LZMA on 8 processors
加密
Tang<code> </code>tang3 = new Tang("key", "salt", "distr", 1); // use 1 processor for encryption
Tang tang4 = new Tang(key, salt, distr); // use all processors for encryption. key,salt and distr are byte arrays
使用壓縮加密
Tang tang5<code> </code>= new Tang(CompressionAlgo.GZip8, "key", "salt", "distr", 4); // GZip8 compression, 4 processors for encryption
Tang tang6 = new Tang(CompressionAlgo.LZMA1, "key", "salt", "distr"); // LZMA1 compression, all processors for encryption
在操作中
Tang tang1<code> </code>= new Tang(CompressionAlgo.GZip1);
byte[] plain = ...
byte[] compressed = tang1.Zip(plain);
byte[] uncompressed = tang1.Unzip(compressed);
Tang tang<code>2 </code>= new Tang("key", "salt", "distr");
byte[] encrypted= tang2.Crypt(plain);
// The reset is needed when using the same tang object for the paired encrypt/decrypt and tangle/untangle actions.
tang2.Reset();
byte[] decrypted = tang2.Crypt (encrypted);
Tang tang3<code> </code>= new Tang(CompressionAlgo.LZMA1, "key", "salt", "distr");
byte[] tangled = tang3.Tangle(plain); // Tangle is Crypt(Zip(plain))
tang3.Reset();
byte[] untangled = tang3.Untangle(tangled); // Untangle is Unzip(Crypt(tangled))
還有Tango函式使用MemoryStream輸入引數,而不是位元組陣列作為引數。
不要忘記在un-unzip和Untangle操作中放置try / catch塊。
生成
初始化後,tang物件可以生成給定長度的位元組陣列,該位元組陣列對於提供的金鑰,鹽(salt)和分佈是唯一的:
Tang tang = new Tang("key", "salt", "distr");
byte[] hash = tang.Generate(<code>int </code>length);
測量
PC:i7 2GHz 64位8核
Tangle()
Source 9,653,618 B (fb2 file - allows for high compression)
time compression rate
GZip1 2,463,446 B 1259 ms 25.52%
GZip8 2,472,430 B 303 ms 25.61%
LZMA1 1,777,219 B 30995 ms 18.41%
LZMA8 1,914,649 B 6124 ms 19.83%
僅限壓縮
Source 9653618 B timing compression rate
GZip1 2,463,446 B 1169 ms 3.7% 25.52%
GZip8 2,472,430 B 293 ms 0.9% 25.61%
LZMA1 1,777,219 B 31377 ms 100% 18.41%
LZMA8 1,914,649 B 6131 ms 19.5% 19.83%
預期最有效的壓縮演算法是LZMA1,它具有最高的時間成本。
GZip8比GZip1快4倍,壓縮效果幾乎不差。
僅限加密
Source 9653618 B
time
1 core 903 ms 100%
2 cores 457 ms 50.6%
4 cores 295 ms 32.7%
8 cores 219 ms 24.3%
生成
250毫秒內生成10,000,000個位元組
初始化速度
<code>Tang tang </code>= new <code>Tang </code>(CompressionAlgo.LZMA8, "key", "salt", "distr");
Tang構造時間大約需要0.08 ms,與應用的壓縮演算法無關。
讓您輕鬆與Tango糾纏在一起!
原文地址:https://www.codeproject.com/Articles/1273094/Effective-data-handling-compress-and-encrypt-with