using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
#region License
// CryptoManager - Logiciel de cryptage de fichiers
// Copyright (C) 2008 G. Villard
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#endregion
namespace CryptoManager {
public static class Crypto {
#region Imports
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean CryptAcquireContextW(ref IntPtr crypt, [MarshalAs(UnmanagedType.LPWStr)]string container, [MarshalAs(UnmanagedType.LPWStr)]string provider, UInt32 type, UInt32 flags);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean CryptGenRandom(IntPtr crypt, UInt32 len, IntPtr buffer);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean CryptReleaseContext(IntPtr crypt, UInt32 flags);
[DllImport("ntdll.dll", SetLastError = false)]
private static extern Int32 RtlFillMemory([In] IntPtr destination, UInt32 len, byte data);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern void RtlZeroMemory(IntPtr destination, uint len);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr VirtualAlloc(IntPtr address, UInt32 size, UInt32 type, UInt32 protect);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean VirtualFree(IntPtr address, UInt32 size, UInt32 type);
[DllImport("kernel32.dll", SetLastError = false)]
private static extern void RtlZeroMemory(IntPtr destination, IntPtr size);
[DllImport("kernel32.dll", EntryPoint="RtlCopyMemory")]
static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean GetFileSizeEx(IntPtr hFile, out UInt32 lpFileSize);
#endregion
#region Enums
public enum SecureEraseMode {
None,
Rand,
RandRand,
RandZeroOneRand,
Gutmann
}
#endregion
#region Méthodes static
public static ICryptoTransform getCryptoTransformer(byte[] key, byte[] iv, bool crypt) {
ICryptoTransform transformer;
try {
RijndaelManaged rm = new RijndaelManaged();
rm.Mode = CipherMode.CBC;
transformer = crypt ?
rm.CreateEncryptor(key, iv):
rm.CreateDecryptor(key, iv);
rm.Clear();
rm = null;
} catch {
transformer = null;
}
return transformer;
}
public static ICryptoTransform getCryptoTransformer(SecureString password, bool crypt) {
ICryptoTransform transformer;
try {
IntPtr ptr = Marshal.SecureStringToBSTR(password);
PasswordDeriveBytes pdb = null;
pdb = new PasswordDeriveBytes(Marshal.PtrToStringAuto(ptr), Encoding.ASCII.GetBytes(Marshal.PtrToStringAuto(ptr)), "SHA1", 2);
transformer = getCryptoTransformer(pdb.GetBytes(32), pdb.GetBytes(16), crypt);
if (IntPtr.Zero != ptr)
Marshal.ZeroFreeBSTR(ptr);
pdb.Reset();
pdb = null;
} catch {
transformer = null;
}
return transformer;
}
public static ICryptoTransform getCryptoTransformer(string password, bool crypt) {
ICryptoTransform transformer;
try {
PasswordDeriveBytes pdb = null;
pdb = new PasswordDeriveBytes(password, Encoding.ASCII.GetBytes(password), "SHA1", 2);
transformer = getCryptoTransformer(pdb.GetBytes(32), pdb.GetBytes(16), crypt);
pdb.Reset();
pdb = null;
} catch {
transformer = null;
}
return transformer;
}
public static void getCryptoTransformer(out ICryptoTransform encryptor, out ICryptoTransform decryptor, SecureString password) {
try {
IntPtr ptr = Marshal.SecureStringToBSTR(password);
PasswordDeriveBytes pdb = null;
pdb = new PasswordDeriveBytes(Marshal.PtrToStringAuto(ptr), Encoding.ASCII.GetBytes(Marshal.PtrToStringAuto(ptr)), "SHA1", 2);
getCryptoTransformer(out encryptor, out decryptor, pdb.GetBytes(32), pdb.GetBytes(16));
if (IntPtr.Zero != ptr)
Marshal.ZeroFreeBSTR(ptr);
pdb.Reset();
pdb = null;
} catch {
encryptor = null;
decryptor = null;
}
}
public static void getCryptoTransformer(out ICryptoTransform encryptor, out ICryptoTransform decryptor, string password) {
try {
PasswordDeriveBytes pdb = null;
pdb = new PasswordDeriveBytes(password, Encoding.ASCII.GetBytes(password), "SHA1", 2);
getCryptoTransformer(out encryptor, out decryptor, pdb.GetBytes(32), pdb.GetBytes(16));
pdb.Reset();
pdb = null;
} catch {
encryptor = null;
decryptor = null;
}
}
public static void getCryptoTransformer(out ICryptoTransform encryptor, out ICryptoTransform decryptor, byte[] key, byte[] iv) {
try {
RijndaelManaged rm = new RijndaelManaged();
rm.Mode = CipherMode.CBC;
encryptor = rm.CreateEncryptor(key, iv);
decryptor = rm.CreateDecryptor(key, iv);
rm.Clear();
rm = null;
} catch {
encryptor = null;
decryptor = null;
}
}
public static bool doFileSecureDelete(string fileFullPath) {
return doFileSecureDelete(fileFullPath, SecureEraseMode.Rand);
}
public static bool doFileSecureDelete(string fileFullPath, SecureEraseMode mode) {
FileStream fsIn = null;
try {
fsIn = new FileStream(fileFullPath, FileMode.Open, FileAccess.ReadWrite);
fsIn.doSecureClose(mode);
File.Delete(fileFullPath);
return true;
} catch {
if(fsIn != null)
fsIn.Dispose();
return false;
}
}
public static bool doDirectorySecureDelete(string folderFullPath) {
return doDirectorySecureDelete(folderFullPath, SecureEraseMode.Rand);
}
public static bool doDirectorySecureDelete(string folderFullPath, SecureEraseMode mode) {
bool rst = true;
foreach(string file in Directory.GetFiles(folderFullPath, "*", SearchOption.AllDirectories)) {
rst |= doFileSecureDelete(file, mode);
}
return rst;
}
#endregion
#region Extention string
public static unsafe SecureString makeSecure(this string input) {
if(input == null)
return null;
SecureString output = new SecureString();
for(int i = 0; i < input.Length; i++)
output.AppendChar(input[i]);
fixed(char* tmp = String.Intern(input)) {
for(int i = 0; i < input.Length; i++)
tmp[i] = '0';
}
return output;
}
public static string encrypt(this string input, string password) {
if(input == null || password == null)
return null;
return input.encrypt(password, false);
}
public static string encrypt(this string input, string password, bool forFile) {
if(input == null || password == null)
return null;
using(ICryptoTransform encryptor = getCryptoTransformer(password, true)) {
return input.encrypt(encryptor, forFile);
}
}
public static string encrypt(this string input, SecureString password) {
if(input == null || password == null)
return null;
return input.encrypt(password, false);
}
public static string encrypt(this string input, SecureString password, bool forFile) {
if(input == null || password == null)
return null;
using(ICryptoTransform encryptor = getCryptoTransformer(password, true)) {
return input.encrypt(encryptor, forFile);
}
}
public static string encrypt(this string input, ICryptoTransform encryptor) {
if(input == null || encryptor == null)
return null;
return input.encrypt(encryptor, false);
}
public static string encrypt(this string input, ICryptoTransform encryptor, bool forFile) {
if(input == null || encryptor == null)
return null;
byte[] o = Encoding.UTF8.GetBytes(input).cryptoTransform(encryptor);
if(o == null)
return null;
if(!forFile)
return Convert.ToBase64String(o);
return new StringBuilder(Convert.ToBase64String(o))
.Replace("/", "¤1").Replace("\\", "¤2").Replace(":", "¤3")
.Replace("*", "¤4").Replace("?", "¤5").Replace("\"", "¤6")
.Replace("<", "¤7").Replace(">", "¤8").Replace("|", "¤9").ToString();
}
public static string decrypt(this string input, string password) {
if(input == null || password == null)
return null;
return input.encrypt(password, false);
}
public static string decrypt(this string input, string password, bool forFile) {
if(input == null || password == null)
return null;
using(ICryptoTransform decryptor = getCryptoTransformer(password, false)) {
return input.decrypt(decryptor, forFile);
}
}
public static string decrypt(this string input, SecureString password) {
if(input == null || password == null)
return null;
return input.encrypt(password, false);
}
public static string decrypt(this string input, SecureString password, bool forFile) {
if(input == null || password == null)
return null;
using(ICryptoTransform decryptor = getCryptoTransformer(password, false)) {
return input.decrypt(decryptor, forFile);
}
}
public static string decrypt(this string input, ICryptoTransform decryptor) {
if(input == null || decryptor == null)
return null;
return input.decrypt(decryptor, false);
}
public static string decrypt(this string input, ICryptoTransform decryptor, bool forFile) {
if(input == null || decryptor == null)
return null;
StringBuilder sb = new StringBuilder(input);
if(forFile)
sb.Replace("¤1", "/").Replace("¤2", "\\").Replace("¤3", ":")
.Replace("¤4", "*").Replace("¤5", "?").Replace("¤6", "\"")
.Replace("¤7", "<").Replace("¤8", ">").Replace("¤9", "|");
byte[] o = Convert.FromBase64String(sb.ToString()).cryptoTransform(decryptor);
if(o == null)
return null;
return Encoding.UTF8.GetString(o);
}
#endregion
#region Extention byte[]
public static byte[] cryptoTransform(this byte[] input, ICryptoTransform cryptoTransformer) {
if(input == null || cryptoTransformer == null)
return null;
MemoryStream mem = new MemoryStream();
CryptoStream cm = null;
byte[] o = null;
try {
cm = new CryptoStream(mem, cryptoTransformer, CryptoStreamMode.Write);
cm.Write(input, 0, input.Length);
cm.FlushFinalBlock();
o = mem.ToArray();
mem.Close();
cm.Close();
} catch {
try {
if(mem != null)
mem.Close();
if(cm != null)
cm.Close();
} catch {}
return null;
}
return o;
}
public static bool fillWithRandomData(this byte[] buffer, UInt32 size) {
if(buffer == null)
return false;
buffer = new Byte[size];
return buffer.fillWithRandomData();
}
public static bool fillWithRandomData(this byte[] buffer) {
if(buffer == null)
return false;
RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider();
rnd.GetBytes(buffer);
return true;
}
public static bool fillWithByte(this byte[] buffer, UInt32 size, byte data) {
if(buffer == null)
return false;
buffer = new Byte[size];
return buffer.fillWithByte(data);
}
public static unsafe bool fillWithByte(this byte[] buffer, byte data) {
if(buffer == null)
return false;
if(buffer.LongLength > UInt32.MaxValue)
return false;
fixed(byte* b = buffer) {
IntPtr ptr = (IntPtr)b;
RtlFillMemory(ptr, (UInt32)buffer.LongLength, data);
}
return true;
}
public static bool fillWithZero(this byte[] buffer, UInt32 size) {
if(buffer == null)
return false;
buffer = new Byte[size];
return buffer.fillWithZero();
}
public static unsafe bool fillWithZero(this byte[] buffer) {
if(buffer == null)
return false;
if(buffer.LongLength > UInt32.MaxValue)
return false;
fixed(byte* b = buffer) {
IntPtr ptr = (IntPtr)b;
RtlZeroMemory(ptr, (UInt32)buffer.LongLength);
}
return true;
}
#endregion
#region Extention FileStream
public static bool cryptoTransform(this FileStream fsIn, ICryptoTransform cryptoTransformer, FileStream fsOut) {
if(cryptoTransformer == null)
throw new ArgumentNullException("L'opérateur de transformation ne doit pas être nul.");
if(fsOut == null)
throw new ArgumentNullException("Le flux d'écriture ne doit pas être nul.");
CryptoStream cs = null;
try {
cs = new CryptoStream(fsOut, cryptoTransformer, CryptoStreamMode.Write);
int bufferLen = 4096;
byte[] buffer = new byte[bufferLen];
int bytesRead;
do {
bytesRead = fsIn.Read(buffer, 0, bufferLen);
cs.Write(buffer, 0, bytesRead);
cs.Flush();
} while(bytesRead != 0);
if(cs != null)
cs.Close();
} catch {
try {
if(cs != null)
cs.Close();
} catch {}
return false;
}
return true;
}
public static void doSecureClose(this FileStream fsIn, SecureEraseMode mode) {
if(fsIn == null)
throw new ArgumentNullException();
if(fsIn.Length > UInt32.MaxValue)
throw new ArgumentOutOfRangeException("fsIn", fsIn.Length, "La taille du fichier ne doit pas excéder " + UInt32.MaxValue + ".");
UInt32 bufferLen = (fsIn.Length > (long)UInt32.MaxValue) ? UInt32.MaxValue : (UInt32)fsIn.Length;
byte[] buffer = new byte[bufferLen];
switch(mode) {
case SecureEraseMode.None:
break;
case SecureEraseMode.Rand:
// Passe random
if(!buffer.fillWithRandomData())
throw new CryptographicUnexpectedOperationException();
fsIn.fillWithBuffer(buffer);
break;
case SecureEraseMode.RandRand:
// 1ère passe random
if(!buffer.fillWithRandomData())
throw new CryptographicUnexpectedOperationException();
fsIn.fillWithBuffer(buffer);
// 2ème passe random
if(!buffer.fillWithRandomData())
throw new CryptographicUnexpectedOperationException();
fsIn.fillWithBuffer(buffer);
break;
case SecureEraseMode.RandZeroOneRand:
// 1ère passe random
if(!buffer.fillWithRandomData())
throw new CryptographicUnexpectedOperationException();
fsIn.fillWithBuffer(buffer);
// 2ème passe 00000000
buffer.fillWithZero();
fsIn.fillWithBuffer(buffer);
// 3ème passe 11111111
buffer.fillWithByte(0xF);
fsIn.fillWithBuffer(buffer);
// 4ème passe random
if(!buffer.fillWithRandomData())
throw new CryptographicUnexpectedOperationException();
fsIn.fillWithBuffer(buffer);
break;
}
fsIn.Close();
fsIn = null;
}
public static bool fillWithBuffer(this FileStream fsIn, byte[] buffer) {
if(fsIn == null)
throw new ArgumentNullException();
// if(!(fsIn.CanWrite && fsIn.CanRead && fsIn.CanSeek))
// throw new NotSupportedException();
fsIn.Seek(0, SeekOrigin.Begin);
long j = 0;
long fsLen = fsIn.Length;
for(long i = 0; i < fsLen; i++) {
fsIn.WriteByte((byte)buffer.GetValue(j));
if(++j >= long.MaxValue)
j = 0;
if(j >= buffer.LongLength)
j = 0;
}
fsIn.Flush();
fsIn.Seek(0, SeekOrigin.Begin);
return true;
}
#endregion
}
}