.Net提供了很多已经实现好的加密类,详见这篇文章。
下面的代码生成一个key file,这个key file在加密解密时使用,解密时如果没有key file,或者key file 不是加密时用的key file,将不能解密。虽然可以把key写死在程序中,但是保密性就太低了。
用私匙(也叫对称加密)加密文件速度很快。
第一次贴的代码有点问题,晚23点更新正确代码,请往后看
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace MyCryptography
{
class Cryptography
{
private const int KEYSIZE = 128;
private const int KEYSIZEINBYTE = KEYSIZE / 8;
///
/// Save key file to the specified path
///
/// The key file path
internal void CreateKeyFile(string path)
{
TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
//KeySize is in bit
tDESalg.KeySize = KEYSIZE;
tDESalg.GenerateIV();
tDESalg.GenerateKey();
using (FileStream fs = new FileStream(path, FileMode.Create))
{
fs.Write(tDESalg.Key, 0, tDESalg.Key.Length);
fs.Write(tDESalg.IV, 0, tDESalg.IV.Length);
}
//Release all resouse used by the algorithm.
//CLR won't dispose the memory untill Clear() is called.
tDESalg.Clear();
}
///
/// Read IV and Key from the specified file path
///
/// The key file path
/// byte array list. The first array is key. The second is IV.
private List<byte[]> ReadIVKey(string keypath)
{
List<byte[]> list = new List<byte[]>(2);
if (File.Exists(keypath))
{
byte[] ivkey = File.ReadAllBytes(keypath);
byte[] key = new byte[KEYSIZEINBYTE];
byte[] iv = new byte[ivkey.Length - KEYSIZEINBYTE];
for (int i = 0; i < KEYSIZEINBYTE; i++)
{
key[i] = ivkey[i];
}
for (int i = 0; i < iv.Length; i++)
{
iv[i] = ivkey[KEYSIZEINBYTE + i];
}
list.Add(key);
list.Add(iv);
}
return list;
}
///
/// Use the specified key to encrypt the given file.
///
/// The file to be encrypted.
/// Key file path
/// The output encrypted file path.
internal void Encrypt(string filepath, string keypath, string savepath)
{
List<byte[]> ivkey = ReadIVKey(keypath);
using (FileStream fs = new FileStream(savepath, FileMode.Create))
{
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms,
new TripleDESCryptoServiceProvider().CreateEncryptor(ivkey[0], ivkey[1]),
CryptoStreamMode.Write))
{
byte[] content = File.ReadAllBytes(filepath);
cs.Write(content, 0, content.Length);
cs.FlushFinalBlock();
}
fs.Write(ms.ToArray(), 0, ms.ToArray().Length);
}
}
}
///
/// Use the specified key to decrypt the given file.
///
/// The file to be decrypted.
/// Key file path
/// The output decrypted file path.
internal void Decrypt(string filepath, string keypath, string savepath)
{
List<byte[]> ivkey = ReadIVKey(keypath);
using (FileStream fs = new FileStream(savepath, FileMode.Create))
{
byte[] content = File.ReadAllBytes(filepath);
using (MemoryStream ms = new MemoryStream(content))
{
using (CryptoStream cs = new CryptoStream(ms,
new TripleDESCryptoServiceProvider().CreateDecryptor(ivkey[0], ivkey[1]),
CryptoStreamMode.Read))
{
byte[] fromEncrypt = new byte[content.Length];
cs.Read(fromEncrypt, 0, fromEncrypt.Length);
fs.Write(fromEncrypt.ToArray(), 0, fromEncrypt.ToArray().Length);
}
}
}
}
}
}
因为私匙加密需要生成IV和Key,我把他们写在一个file里,加密解密时调用ReadIVKey把IV和Key分析出来。
CryptoStream是加密解密要使用的类,这点很关键。
要注意,加密后的文件通常会比原文件多些字节,上面代码解密的文件会比原文件多出几个字节,原因应该是byte[] fromEncrypt = new byte[content.Length];,content是读加密后文件的所有字节,然后用 fromEncrypt 写到文件流时,就把多出的字节也写了进去。
其实可以不经过MemoryStream这一步,直接把byte[]写入文件流中,这样解密的文件大小和原文件是一样。若要对内存中的流加密,需要用MemoryStream,对文件加密,用FileStream。更新Encrypt和Decrypt代码:
/// <summary>
/// Use the specified key to encrypt the given file.
/// </summary>
/// <param name="filepath">The file to be encrypted.</param>
/// <param name="keypath">Key file path</param>
/// <param name="savepath">The output encrypted file path.</param>
internal void Encrypt(string filepath, string keypath, string savepath)
{
List<byte[]> ivkey = ReadIVKey(keypath);
using (FileStream fsSave = new FileStream(savepath, FileMode.Create))
{
using (CryptoStream cs = new CryptoStream(fsSave,
new TripleDESCryptoServiceProvider().CreateEncryptor(ivkey[0], ivkey[1]),
CryptoStreamMode.Write))
{
using (FileStream fs = new FileStream(filepath, FileMode.Open))
{
int bufferLen = 4096;
byte[] buffer = new byte[bufferLen];
int bytesRead;
do
{
bytesRead = fs.Read(buffer, 0, bufferLen);
cs.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
cs.FlushFinalBlock();
}
}
}
}
/// <summary>
/// Use the specified key to decrypt the given file.
/// </summary>
/// <param name="filepath">The file to be decrypted.</param>
/// <param name="keypath">Key file path</param>
/// <param name="savepath">The output decrypted file path.</param>
internal void Decrypt(string filepath, string keypath, string savepath)
{
List<byte[]> ivkey = ReadIVKey(keypath);
using (FileStream fs = new FileStream(filepath, FileMode.Open))
{
using (FileStream fsSave = new FileStream(savepath, FileMode.Create))
{
using (CryptoStream cs = new CryptoStream(fsSave,
new TripleDESCryptoServiceProvider().CreateDecryptor(ivkey[0], ivkey[1]),
CryptoStreamMode.Write))
{
int bufferLen = 4096;
byte[] buffer = new byte[bufferLen];
int bytesRead;
do
{
bytesRead = fs.Read(buffer, 0, bufferLen);
cs.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
cs.FlushFinalBlock();
}
}
}
}
附网上找的,根据给定密码生成Key和IV的方法示例,可用于根据密码加密文件
private void GenerateKey(string SecretPhrase)
{
// Initialize internal values
this._Key = new byte[24];
this._IV = new byte[16];
// Perform a hash operation using the phrase. This will
// generate a unique 32 character value to be used as the key.
byte[] bytePhrase = Encoding.ASCII.GetBytes(SecretPhrase);
SHA384Managed sha384 = new SHA384Managed();
sha384.ComputeHash(bytePhrase);
byte[] result = sha384.Hash;
// Transfer the first 24 characters of the hashed value to the key
// and the remaining 8 characters to the intialization vector.
for (int loop = 0; loop < 24; loop++) this._Key[loop] = result[loop];
for (int loop = 24; loop < 40; loop++) this._IV[loop - 24] = result[loop];
}