Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.IO;
- using System.Security.Cryptography;
- using System.Text;
- namespace cryptolab
- {
- /// <summary>
- /// Utilidades criptográficas
- /// </summary>
- public static class CryptoUtils
- {
- /// <summary>
- /// Pacote contendo dados encriptados, juntamente com um HMAC
- /// para verificacao da integridade e assinatura digital para reconhecer
- /// o criador do documento
- /// </summary>
- public class EncryptedPacket
- {
- /// <summary>
- /// Chave se sessão utilizada para encryptar os dados
- /// Essa chave é encryptada utilizando a chave pública do receptor
- /// </summary>
- /// <value></value>
- public byte[] EncryptedSessionKey { get; set; }
- /// <summary>
- /// Vetor de inicializacao do AES
- /// </summary>
- /// <value></value>
- public byte[] IV { get; set; }
- /// <summary>
- /// Dados encryptados utilizando a SessionKey (Decriptada) e IV
- /// </summary>
- /// <value></value>
- public byte[] EncryptedData { get; set; }
- /// <summary>
- /// HMAC para verificar integridade da mensagem (a chave do HMAC é a SessionKey)
- /// </summary>
- /// <value></value>
- public byte[] HMAC { get; set; }
- /// <summary>
- /// Assinatura do sender, compare-a ao HMAC com a chave pública do Sender
- /// </summary>
- /// <value></value>
- public byte[] Signature { get; set; }
- }
- /// <summary>
- /// Prepara um pacote com dados encryptados com suporte a
- /// confidencialidade (Dados encryptados), integridade (HMAC),
- /// autenticação e não repúdio (Assinatura Digital)
- /// </summary>
- /// <param name="data"></param>
- /// <param name="senderPrivateKey"></param>
- /// <param name="recipientPublicKey"></param>
- /// <returns></returns>
- public static EncryptedPacket PackEncryptedData(byte[] data, RSAParameters senderPrivateKey, RSAParameters recipientPublicKey)
- {
- //Número qualquer
- var sessionKey = GenerateRandomNumberV2(32);
- var iv = GenerateRandomNumberV2(16);
- //Encrypt data using session key and iv
- var encryptedData = EncryptWithAES(data, sessionKey, iv);
- //The session key will be sended encrypted by the recipient public key (only him will be able to decrypt)
- var encryptedSesionKey = EncryptWithRSA(sessionKey, recipientPublicKey);
- //HMAC based on the session key
- var hmac = ComputeHmacSHA256(encryptedData, sessionKey);
- //And finally the signature of the hmac
- var signature = SignData(hmac, senderPrivateKey);
- return new EncryptedPacket
- {
- EncryptedSessionKey = encryptedSesionKey,
- IV = iv,
- EncryptedData = encryptedData,
- HMAC = hmac,
- Signature = signature
- };
- }
- /// <summary>
- /// Recupera os dados encryptados do pacote
- /// </summary>
- /// <param name="packet"></param>
- /// <param name="recipientPrivateKey"></param>
- /// <param name="senderPublicKey"></param>
- /// <returns></returns>
- public static byte[] UnpackEncryptedData(EncryptedPacket packet, RSAParameters recipientPrivateKey, RSAParameters senderPublicKey)
- {
- var decryptedSessionKey = DecryptWithRSA(packet.EncryptedSessionKey, recipientPrivateKey);
- var hmacToCheck = ComputeHmacSHA256(packet.EncryptedData, decryptedSessionKey);
- if (!CompareByteArrays(packet.HMAC, hmacToCheck))
- {
- throw new CryptographicException("HMAC invalid");
- }
- if (!VerifySignature(packet.HMAC, packet.Signature, senderPublicKey))
- {
- throw new CryptographicException("Digital signature can not be verified");
- }
- return DecryptWithAES(packet.EncryptedData, decryptedSessionKey, packet.IV);
- }
- /// <summary>
- /// Gera números aleatórios utilizando RNGCryptoServiceProvider
- /// </summary>
- /// <param name="size"></param>
- /// <returns></returns>
- public static byte[] GenerateRandomNumberV2(int size)
- {
- using (var rnd = new RNGCryptoServiceProvider())
- {
- var result = new byte[size];
- rnd.GetBytes(result);
- return result;
- }
- }
- /// <summary>
- /// Calcula um hash SHA-1
- /// </summary>
- /// <param name="data"></param>
- /// <returns></returns>
- public static byte[] ComputeSHA1(byte[] data)
- {
- using (var sha1 = SHA1.Create())
- {
- return sha1.ComputeHash(data);
- }
- }
- /// <summary>
- /// Calcula um hash SHA-256
- /// </summary>
- /// <param name="data"></param>
- /// <returns></returns>
- public static byte[] ComputeSHA256(byte[] data)
- {
- using (var sha256 = SHA256.Create())
- {
- return sha256.ComputeHash(data);
- }
- }
- /// <summary>
- /// Calcula um hash MD5
- /// </summary>
- /// <param name="data"></param>
- /// <returns></returns>
- public static byte[] ComputeMD5(byte[] data)
- {
- using (var md5 = MD5.Create())
- {
- return md5.ComputeHash(data);
- }
- }
- /// <summary>
- /// Calcula um HMAC do tipo SHA-1
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <returns></returns>
- public static byte[] ComputeHmacSHA1(byte[] data, byte[] key)
- {
- using (var hmac = new HMACSHA1(key))
- {
- return hmac.ComputeHash(data);
- }
- }
- /// <summary>
- /// Calcula HMAC do tipo SHA-256
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <returns></returns>
- public static byte[] ComputeHmacSHA256(byte[] data, byte[] key)
- {
- using (var hmac = new HMACSHA256(key))
- {
- return hmac.ComputeHash(data);
- }
- }
- /// <summary>
- /// Calcula um HMAC do tipo MD5
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <returns></returns>
- public static byte[] ComputeHmacMD5(byte[] data, byte[] key)
- {
- using (var hmac = new HMACMD5(key))
- {
- return hmac.ComputeHash(data);
- }
- }
- /// <summary>
- /// Gera password utilizando uma técnica de key derivation
- /// </summary>
- /// <param name="original"></param>
- /// <param name="salt"></param>
- /// <param name="numberOfRounds"></param>
- /// <returns></returns>
- public static byte[] GeneratePassword(byte[] original, byte[] salt, int numberOfRounds)
- {
- using (var rfc = new Rfc2898DeriveBytes(original, salt, numberOfRounds))
- {
- return rfc.GetBytes(32);
- }
- }
- /// <summary>
- /// Gera SALT aleatório para ser utilizado na geração de senhas
- /// </summary>
- /// <returns></returns>
- public static byte[] GenerateSalt()
- {
- return GenerateRandomNumberV2(32);
- }
- /// <summary>
- /// Realiza encrypt utilizando DES
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <param name="iv"></param>
- /// <returns></returns>
- public static byte[] EncryptWithDES(byte[] data, byte[] key, byte[] iv)
- {
- using (var des = new DESCryptoServiceProvider())
- {
- return EncryptSymetric(des, data, key, iv);
- }
- }
- /// <summary>
- /// Realiza decrypt utilizando DES
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <param name="iv"></param>
- /// <returns></returns>
- public static byte[] DecryptWithDES(byte[] data, byte[] key, byte[] iv)
- {
- using (var des = new DESCryptoServiceProvider())
- {
- return DecryptSymetric(des, data, key, iv);
- }
- }
- /// <summary>
- /// Realiza encrypt utilizando 3DES
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <param name="iv"></param>
- /// <returns></returns>
- public static byte[] EncryptWithTripleDES(byte[] data, byte[] key, byte[] iv)
- {
- using (var tdes = new TripleDESCryptoServiceProvider())
- {
- return EncryptSymetric(tdes, data, key, iv);
- }
- }
- /// <summary>
- /// Realiza decrypt utilizando 3DES
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <param name="iv"></param>
- /// <returns></returns>
- public static byte[] DecryptWithTripleDES(byte[] data, byte[] key, byte[] iv)
- {
- using (var tdes = new TripleDESCryptoServiceProvider())
- {
- return DecryptSymetric(tdes, data, key, iv);
- }
- }
- /// <summary>
- /// Realiza encrypt utilizando AES
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <param name="iv"></param>
- /// <returns></returns>
- public static byte[] EncryptWithAES(byte[] data, byte[] key, byte[] iv)
- {
- using (var aes = new AesCryptoServiceProvider())
- {
- return EncryptSymetric(aes, data, key, iv);
- }
- }
- /// <summary>
- /// Realiza decrypt utilizando AES
- /// </summary>
- /// <param name="data"></param>
- /// <param name="key"></param>
- /// <param name="iv"></param>
- /// <returns></returns>
- public static byte[] DecryptWithAES(byte[] data, byte[] key, byte[] iv)
- {
- //using (var aes = new AesCryptoServiceProvider()) //WINAPI
- using (var aes = new AesManaged()) //.NET
- {
- return DecryptSymetric(aes, data, key, iv);
- }
- }
- /// <summary>
- /// Gera e recupera um par de chaves RSA
- /// </summary>
- public static (RSAParameters puK, RSAParameters prK) GenerateRSAKeyPair(int keySize = 2048)
- {
- using (var rsa = new RSACryptoServiceProvider(keySize))
- {
- rsa.PersistKeyInCsp = false;
- return (rsa.ExportParameters(false), rsa.ExportParameters(true));
- }
- }
- /// <summary>
- /// Gera e armazena chaves em um key container do sistema
- /// </summary>
- /// <param name="containerName"></param>
- /// <returns></returns>
- public static CspParameters GenerateAndStoreRSAKeys(string containerName)
- {
- var cspParams = new CspParameters(1);
- cspParams.KeyContainerName = containerName;
- cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
- cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
- var rsa = new RSACryptoServiceProvider(cspParams)
- {
- PersistKeyInCsp = true
- };
- return cspParams;
- }
- /// <summary>
- /// Remove chaves armazenadas no container informado
- /// </summary>
- /// <param name="containerName"></param>
- public static void RemoveRSAKeysFromContainer(string containerName)
- {
- var cspParams = new CspParameters { KeyContainerName = containerName };
- var rsa = new RSACryptoServiceProvider(cspParams) { PersistKeyInCsp = false };
- rsa.Clear();
- }
- /// <summary>
- /// Realiza encrypt utiliznado chave pública
- /// </summary>
- /// <param name="data"></param>
- /// <param name="publicKey"></param>
- /// <returns></returns>
- public static byte[] EncryptWithRSA(byte[] data, RSAParameters publicKey)
- {
- using (var rsa = new RSACryptoServiceProvider(2048))
- {
- rsa.PersistKeyInCsp = false;
- rsa.ImportParameters(publicKey);
- return rsa.Encrypt(data, true);
- }
- }
- /// <summary>
- /// Realiza encrypt utilizando chaves armazenadas no container informado
- /// </summary>
- /// <param name="data"></param>
- /// <param name="containerName"></param>
- /// <returns></returns>
- public static byte[] EncryptWithRSA(byte[] data, string containerName)
- {
- using (var rsa = new RSACryptoServiceProvider(2048, new CspParameters { KeyContainerName = containerName }))
- {
- return rsa.Encrypt(data, false);
- }
- }
- /// <summary>
- /// Realiza decrypt utilizando chaves armazenadas no container informado
- /// </summary>
- /// <param name="data"></param>
- /// <param name="containerName"></param>
- /// <returns></returns>
- public static byte[] DecryptWithRSA(byte[] data, string containerName)
- {
- using (var rsa = new RSACryptoServiceProvider(2048, new CspParameters { KeyContainerName = containerName }))
- {
- return rsa.Decrypt(data, false);
- }
- }
- /// <summary>
- /// Realiza decrypt utilizando chave privada
- /// </summary>
- /// <param name="data"></param>
- /// <param name="privateKey"></param>
- /// <returns></returns>
- public static byte[] DecryptWithRSA(byte[] data, RSAParameters privateKey)
- {
- using (var rsa = new RSACryptoServiceProvider(2048))
- {
- rsa.PersistKeyInCsp = false;
- rsa.ImportParameters(privateKey);
- return rsa.Decrypt(data, true);
- }
- }
- /// <summary>
- /// Calcula assinatura dos dados utilizando a privateKey informada
- /// </summary>
- /// <param name="hashDataToSign"></param>
- /// <param name="privateKey"></param>
- /// <returns></returns>
- public static byte[] SignData(byte[] hashDataToSign, RSAParameters privateKey)
- {
- using (var rsa = new RSACryptoServiceProvider(2048))
- {
- rsa.PersistKeyInCsp = false;
- rsa.ImportParameters(privateKey);
- var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
- rsaFormatter.SetHashAlgorithm("SHA256");
- return rsaFormatter.CreateSignature(hashDataToSign);
- }
- }
- /// <summary>
- /// Verifica se a assinatura digital é válida, utilizando a chave publicKey informada
- /// </summary>
- /// <param name="hashOfData"></param>
- /// <param name="signature"></param>
- /// <param name="publicKey"></param>
- /// <returns></returns>
- public static bool VerifySignature(byte[] hashOfData, byte[] signature, RSAParameters publicKey)
- {
- using (var rsa = new RSACryptoServiceProvider(2048))
- {
- rsa.ImportParameters(publicKey);
- var rsaFormatter = new RSAPKCS1SignatureDeformatter(rsa);
- rsaFormatter.SetHashAlgorithm("SHA256");
- return rsaFormatter.VerifySignature(hashOfData, signature);
- }
- }
- /// <summary>
- /// Converte vetor de bytes em formato HEX
- /// </summary>
- /// <param name="bytes"></param>
- /// <returns></returns>
- public static string ToHexString(byte[] bytes)
- {
- var sb = new StringBuilder();
- foreach (var t in bytes)
- {
- sb.Append(t.ToString("x2"));
- }
- return sb.ToString();
- }
- /// <summary>
- /// Recupera vetor de bytes a partir de uma string em formato HEX
- /// </summary>
- /// <param name="hexString"></param>
- /// <returns></returns>
- public static byte[] FromHexString(string hexString)
- {
- var bytes = new byte[hexString.Length / 2];
- for (var i = 0; i < bytes.Length; i++)
- {
- bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
- }
- return bytes;
- }
- /// <summary>
- /// Compara conteúdo de dois vetores de bytes (bit a bit)
- /// </summary>
- /// <param name="array1"></param>
- /// <param name="array2"></param>
- /// <param name="bytesToCompare"></param>
- /// <returns></returns>
- public static bool CompareByteArrays(byte[] array1, byte[] array2, int bytesToCompare = 0)
- {
- if (array1.Length != array2.Length) return false;
- var length = (bytesToCompare == 0) ? array1.Length : bytesToCompare;
- var tailIdx = length - length % sizeof(Int64);
- //check in 8 byte chunks
- for (var i = 0; i < tailIdx; i += sizeof(Int64))
- {
- if (BitConverter.ToInt64(array1, i) != BitConverter.ToInt64(array2, i)) return false;
- }
- //check the remainder of the array, always shorter than 8 bytes
- for (var i = tailIdx; i < length; i++)
- {
- if (array1[i] != array2[i]) return false;
- }
- return true;
- }
- /// ///////////////////////////////////////
- private static byte[] DecryptSymetric(SymmetricAlgorithm algorithm, byte[] data, byte[] key, byte[] iv)
- {
- algorithm.Mode = CipherMode.CBC;
- algorithm.Padding = PaddingMode.PKCS7;
- algorithm.Key = key;
- algorithm.IV = iv;
- using (var mem = new MemoryStream())
- {
- var cryptoStream = new CryptoStream(mem, algorithm.CreateDecryptor(), CryptoStreamMode.Write);
- cryptoStream.Write(data, 0, data.Length);
- cryptoStream.FlushFinalBlock();
- return mem.ToArray();
- }
- }
- private static byte[] EncryptSymetric(SymmetricAlgorithm algorithm, byte[] data, byte[] key, byte[] iv)
- {
- algorithm.Mode = CipherMode.CBC;
- algorithm.Padding = PaddingMode.PKCS7;
- algorithm.Key = key;
- algorithm.IV = iv;
- using (var mem = new MemoryStream())
- {
- var cryptoStream = new CryptoStream(mem, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
- cryptoStream.Write(data, 0, data.Length);
- cryptoStream.FlushFinalBlock();
- return mem.ToArray();
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement