原文:使用Vernam(維爾南/弗納姆)演算法實現檔案加密解密[C#]
本文介紹如何通過Gilbert Sandford Vernam的演算法實現一個簡潔而又穩定的檔案加密解密類。通過此類加密的資料是絕對無法在沒有密鑰的情況下被破解的。它的基本原理是,需要有一個需要加密的明文和一個隨機產生的解密鑰匙檔案。然後使用這兩個檔案組合起來產生密文:(明文) 組合 (密鑰) = 加密後的密文。
使用Vernam密碼編譯演算法,經其處理的密鑰可以擁有與待加密檔案大小相同的密鑰長度,而且輸出檔案的大小相比待加密檔案無任何改變(精確到位元組)。換言之,密鑰檔案越大,加密強度越高!舉個例子,如果想加密一個5M的檔案,那麼密鑰長度將高達40,000,000位,輸出檔案大小則仍為5M。前面的數字意味著即使是夢幻配置的個人電腦,想要在“有生之年”靠窮取法破解出密碼,也是不可能完成的任務!待加密檔案類型不限,密鑰檔案也可以是任何資料:應用程式、分頁檔,或者音樂檔案,甚至是您寵物的靚照,等等...
Vernam密碼演算法:
1、 現代密碼體制的萌芽是Vernam加密方法。
2、Vernam密碼是美國電話電報公司的Gilbert Vernam在1917年為電報通訊設計的一種非常方便的密碼,它在近代電腦和通訊系統設計中得到了廣泛應用。
3、Vernam密碼的明文、密鑰和密文均用二元數字序列表示。這是一種使用異或方法進行加密解密的方法。
4、要編製Vernam密碼,只需先把明文和密鑰表示成二元序列,再把它們按位模2相加,就可得到密文。
5、而解密只需把密文和密鑰的二元序列按位模2相加便可得到明文。
6、開始時使用一個定長的密鑰序列,這樣產生的密文能形成有規律的反覆,易被破譯;後來採用的密鑰與明文同長,且密鑰序列只用一次,稱為“一次一密體制”。
Vernam類:
- using System;
- using System.IO;
-
- public class Vernam
- {
- /// <summary>
- /// Encrypts a file by the Vernam-algorithm
- /// </summary>
- /// <param name="originalFile">
- /// Name of the file to be encrypted. Data is read from this file.
- /// </param>
- /// <param name="encryptedFile">
- /// Name of the encrypted file. The encrypted data gets written to that file.
- /// </param>
- /// <param name="keyFile">
- /// Name of the key file. The one time key gets written to that file.
- /// </param>
- public void EncryptFile(string originalFile, string encryptedFile, string keyFile)
- {
- // Read in the bytes from the original file:
- byte[] originalBytes;
- using (FileStream fs = new FileStream(originalFile, FileMode.Open))
- {
- originalBytes = new byte[fs.Length];
- fs.Read(originalBytes, 0, originalBytes.Length);
- }
-
- // Create the one time key for encryption. This is done
- // by generating random bytes that are of the same lenght
- // as the original bytes:
- byte[] keyBytes = new byte[originalBytes.Length];
- Random random = new Random();
- random.NextBytes(keyBytes);
-
- // Write the key to the file:
- using (FileStream fs = new FileStream(keyFile, FileMode.Create))
- {
- fs.Write(keyBytes, 0, keyBytes.Length);
- }
-
- // Encrypt the data with the Vernam-algorithm:
- byte[] encryptedBytes = new byte[originalBytes.Length];
- DoVernam(originalBytes, keyBytes, ref encryptedBytes);
-
- // Write the encrypted file:
- using (FileStream fs = new FileStream(encryptedFile, FileMode.Create))
- {
- fs.Write(encryptedBytes, 0, encryptedBytes.Length);
- }
- }
- //---------------------------------------------------------------------
- /// <summary>
- /// Decrypts a file by Vernam-algorithm
- /// </summary>
- /// <param name="encryptedFile">
- /// Name of the encrypted file
- /// </param>
- /// <param name="keyFile">
- /// Name of the key file. The content of this file has to be the same
- /// as the content generated while encrypting
- /// </param>
- /// <param name="decryptedFile">
- /// Name of the decrypted file. The decrypted data gets written to this
- /// file
- /// </param>
- public void DecryptFile(string encryptedFile, string keyFile, string decryptedFile)
- {
- // Read in the encrypted bytes:
- byte[] encryptedBytes;
- using (FileStream fs = new FileStream(encryptedFile, FileMode.Open))
- {
- encryptedBytes = new byte[fs.Length];
- fs.Read(encryptedBytes, 0, encryptedBytes.Length);
- }
-
- // Read in the key:
- byte[] keyBytes;
- using (FileStream fs = new FileStream(keyFile, FileMode.Open))
- {
- keyBytes = new byte[fs.Length];
- fs.Read(keyBytes, 0, keyBytes.Length);
- }
-
- // Decrypt the data with the Vernam-algorithm:
- byte[] decryptedBytes = new byte[encryptedBytes.Length];
- DoVernam(encryptedBytes, keyBytes, ref decryptedBytes);
-
- // Write the decrypted file:
- using (FileStream fs = new FileStream(decryptedFile, FileMode.Create))
- {
- fs.Write(decryptedBytes, 0, decryptedBytes.Length);
- }
- }
- //---------------------------------------------------------------------
- /// <summary>
- /// Computes the Vernam-encryption/decryption
- /// </summary>
- /// <param name="inBytes"></param>
- /// <param name="keyBytes"></param>
- /// <param name="outBytes"></param>
- private void DoVernam(byte[] inBytes, byte[] keyBytes, ref byte[] outBytes)
- {
- // Check arguments:
- if ((inBytes.Length != keyBytes.Length) ||
- (keyBytes.Length != outBytes.Length))
- throw new ArgumentException("Byte-array are not of same length");
-
- // Encrypt/decrypt by XOR:
- for (int i = 0; i < inBytes.Length; i++)
- outBytes[i] = (byte)(inBytes[i] ^ keyBytes[i]);
- }
- }
使用範例:
- class Program
- {
- static void Main(string[] args)
- {
- Vernam vernam = new Vernam();
-
- // Test with an image:
- vernam.EncryptFile("Image.gif", "Image_encrypted.gif", "Key01.dat");
- vernam.DecryptFile("Image_encrypted.gif", "Key01.dat", "Image_decrypted.gif");
-
- // Test with text file:
- vernam.EncryptFile("Text.txt", "Text_encrypted.txt", "Key02.dat");
- vernam.DecryptFile("Text_encrypted.txt", "Key02.dat", "Text_decrypted.txt");
-
- // Test with pdf file:
- vernam.EncryptFile("Text.pdf", "Text_encrypted.pdf", "Key03.dat");
- vernam.DecryptFile("Text_encrypted.pdf", "Key03.dat", "Text_decrypted.pdf");
- }
- }