Wednesday, July 30, 2008

Easy encrypt/decrypt in .Net

Задался я целью побыстрому зашифровать/расшифровать небольшую строчку на asp странице. Как полагается поискал готовое. Нашел несколько ужасных реализаций. Например, на CodeProject автор статьи наляпал изрядное кол-во грубых ошибок. Имхо, это непростительно при написании статьи. Но код в статье на codeproject хоть и бажный, но изредка работает, если попадутся удачная строка и ключ.. Однако, все это еще цветочки по сравнению с говнокодом, который я нашел в msdn. Тут явно не обошлось без поочередного творчества индуса и китайца... Ихний код у меня не сработал ни разу. И сдается мне что вероятность его срабатывания стремится к нулю...
Короче, ничего приемлимого я не нашел и, к сожалению, пришлось делать велосипед:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

class Members
{
[STAThread]
static void Main()
{
Random random = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < 100000; i++)
{
string source = (Guid.NewGuid().ToString() + Guid.NewGuid()).Substring(0, random.Next(Guid.Empty.ToString().Length));
string supperKey = (Guid.NewGuid().ToString() + Guid.NewGuid()).Substring(0, random.Next(Guid.Empty.ToString().Length));
string encrypted = Cryptor.Encrypt(source, supperKey);
string decrypted = Cryptor.Decrypt(encrypted, supperKey);
if (source != decrypted)
throw new ApplicationException("This shit should never happen!!!");
}
}

}

// <summary>
/// SymmCrypto is a wrapper of System.Security.Cryptography.SymmetricAlgorithm classes
/// and simplifies the interface. It supports customized SymmetricAlgorithm as well.
/// </summary>
public static class Cryptor
{
private static readonly SymmetricAlgorithm mobjCryptoService;

/// <remarks>
/// Constructor for using an intrinsic .Net SymmetricAlgorithm class.
/// </remarks>
static Cryptor()
{
//mobjCryptoService = new DESCryptoServiceProvider();
//mobjCryptoService = new RC2CryptoServiceProvider();
mobjCryptoService = new RijndaelManaged();
}

/// <remarks>
/// Depending on the legal key size limitations of a specific CryptoService provider
/// and length of the private key provided, padding the secret key with space character
/// to meet the legal size of the algorithm.
/// </remarks>
private static byte[] GetLegalKey(string Key)
{
int max = mobjCryptoService.LegalKeySizes[0].MaxSize;
int min = mobjCryptoService.LegalKeySizes[0].MinSize;
string sTemp;
int keyLength = Key.Length * 8;
if (keyLength > max)
{
sTemp = Key.Remove(max / 8);
}
else if (keyLength < min)
{
sTemp = Key.PadRight(min / 8, ' ');
}
else if (min < keyLength && keyLength < max)
{
sTemp = Key.Remove(min / 8);
}// else (keyLength == min | max => do nothing
else
{
sTemp = Key;
}
return Encoding.ASCII.GetBytes(sTemp);
}

private static byte[] GetLegalIV(string Key)
{
int min = mobjCryptoService.LegalBlockSizes[0].MinSize;
int keyLength = Key.Length * 8;
string sTemp;
if (keyLength > min)
{
sTemp = Key.Remove(min / 8);
}
else
{
sTemp = keyLength < min ? Key.PadRight(min / 8, ' ') : Key;
}
return Encoding.ASCII.GetBytes(sTemp);
}

public static string Encrypt(string Source, string Key)
{
byte[] bytIn = Encoding.ASCII.GetBytes(Source);
MemoryStream ms = new MemoryStream();
mobjCryptoService.Key = GetLegalKey(Key);
mobjCryptoService.IV = GetLegalIV(Key);
mobjCryptoService.Padding = PaddingMode.Zeros;
ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor();
CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
cs.Write(bytIn, 0, bytIn.Length);
cs.FlushFinalBlock();
byte[] bytOut = ms.GetBuffer();
int length = Source.Length > 0 && Source.Length % mobjCryptoService.IV.Length > 0
? (Source.Length / (mobjCryptoService.IV.Length) + 1) * mobjCryptoService.IV.Length
: Source.Length;
return Convert.ToBase64String(bytOut, 0, length);
}

public static string Decrypt(string Source, string Key)
{
byte[] bytIn = Convert.FromBase64String(Source);
MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length);
mobjCryptoService.Key = GetLegalKey(Key);
mobjCryptoService.IV = GetLegalIV(Key);
mobjCryptoService.Padding = PaddingMode.Zeros;
ICryptoTransform encrypto = mobjCryptoService.CreateDecryptor();
CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cs);
string result = sr.ReadToEnd();
return result.TrimEnd('\0');
}

}