interpolacion - string c# ejemplos
Cifrado y descifrado de una cadena en C# (7)
Esta pregunta ya tiene una respuesta aquí:
- ¿Cifrar y descifrar una cadena en C #? 25 respuestas
¿Cuál es la forma más moderna (mejor) de satisfacer lo siguiente en C #?
string encryptedString = SomeStaticClass.Encrypt(sourceString);
string decryptedString = SomeStaticClass.Decrypt(encryptedString);
PERO con un mínimo de alboroto que involucra sales, llaves, limpieza con byte [], etc.
He estado buscando en Google y confundido con lo que estoy encontrando (puedes ver la lista de SO Q similares para ver si esta pregunta es engañosa).
La forma más fácil que he visto para hacer el cifrado es a través de RSA
Echa un vistazo a la MSDN en él: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx
Implica el uso de bytes, pero cuando se trata de eso, usted quiere que el cifrado y el descifrado sean difíciles de entender, de lo contrario, será fácil de piratear.
Prueba esta clase:
public class DataEncryptor
{
TripleDESCryptoServiceProvider symm;
#region Factory
public DataEncryptor()
{
this.symm = new TripleDESCryptoServiceProvider();
this.symm.Padding = PaddingMode.PKCS7;
}
public DataEncryptor(TripleDESCryptoServiceProvider keys)
{
this.symm = keys;
}
public DataEncryptor(byte[] key, byte[] iv)
{
this.symm = new TripleDESCryptoServiceProvider();
this.symm.Padding = PaddingMode.PKCS7;
this.symm.Key = key;
this.symm.IV = iv;
}
#endregion
#region Properties
public TripleDESCryptoServiceProvider Algorithm
{
get { return symm; }
set { symm = value; }
}
public byte[] Key
{
get { return symm.Key; }
set { symm.Key = value; }
}
public byte[] IV
{
get { return symm.IV; }
set { symm.IV = value; }
}
#endregion
#region Crypto
public byte[] Encrypt(byte[] data) { return Encrypt(data, data.Length); }
public byte[] Encrypt(byte[] data, int length)
{
try
{
// Create a MemoryStream.
var ms = new MemoryStream();
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
var cs = new CryptoStream(ms,
symm.CreateEncryptor(symm.Key, symm.IV),
CryptoStreamMode.Write);
// Write the byte array to the crypto stream and flush it.
cs.Write(data, 0, length);
cs.FlushFinalBlock();
// Get an array of bytes from the
// MemoryStream that holds the
// encrypted data.
byte[] ret = ms.ToArray();
// Close the streams.
cs.Close();
ms.Close();
// Return the encrypted buffer.
return ret;
}
catch (CryptographicException ex)
{
Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
}
return null;
}
public string EncryptString(string text)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(text)));
}
public byte[] Decrypt(byte[] data) { return Decrypt(data, data.Length); }
public byte[] Decrypt(byte[] data, int length)
{
try
{
// Create a new MemoryStream using the passed
// array of encrypted data.
MemoryStream ms = new MemoryStream(data);
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
CryptoStream cs = new CryptoStream(ms,
symm.CreateDecryptor(symm.Key, symm.IV),
CryptoStreamMode.Read);
// Create buffer to hold the decrypted data.
byte[] result = new byte[length];
// Read the decrypted data out of the crypto stream
// and place it into the temporary buffer.
cs.Read(result, 0, result.Length);
return result;
}
catch (CryptographicException ex)
{
Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
}
return null;
}
public string DecryptString(string data)
{
return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(data))).TrimEnd(''/0'');
}
#endregion
}
y úsalo así:
string message="A very secret message here.";
DataEncryptor keys=new DataEncryptor();
string encr=keys.EncryptString(message);
// later
string actual=keys.DecryptString(encr);
Puede estar buscando la clase ProtectedData
, que cifra los datos usando las credenciales de inicio de sesión del usuario.
Si está apuntando a ASP.NET Core que aún no es compatible con RijndaelManaged
, puede usar IDataProtectionProvider
.
Primero, configure su aplicación para usar protección de datos:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection();
}
// ...
}
Entonces podrá inyectar la instancia IDataProtectionProvider
y usarla para cifrar / descifrar datos:
public class MyService : IService
{
private const string Purpose = "my protection purpose";
private readonly IDataProtectionProvider _provider;
public MyService(IDataProtectionProvider provider)
{
_provider = provider;
}
public string Encrypt(string plainText)
{
var protector = _provider.CreateProtector(Purpose);
return protector.Protect(plainText);
}
public string Decrypt(string cipherText)
{
var protector = _provider.CreateProtector(Purpose);
return protector.Unprotect(cipherText);
}
}
Vea este artículo para más detalles.
Si necesita almacenar una contraseña en la memoria y desea cifrarla, debe usar SecureString :
http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx
Para usos más generales, usaría un algoritmo aprobado por FIPS como Advanced Encryption Standard, anteriormente conocido como Rijndael. Vea esta página para un ejemplo de implementación:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx
ACTUALIZACIÓN 23 / diciembre / 2015: Ya que esta respuesta parece estar recibiendo muchos votos positivos, lo he actualizado para corregir errores estúpidos y para mejorar el código en general sobre la base de los comentarios y comentarios. Consulte el final de la publicación para obtener una lista de mejoras específicas.
Como otras personas han dicho, la criptografía no es simple, así que es mejor evitar "rodar su propio algoritmo de cifrado".
Sin embargo, puede "enrollar su propia" clase de envoltorio alrededor de algo como la clase de criptografía RijndaelManaged
incorporada.
Rijndael es el nombre algorítmico del Estándar de cifrado avanzado actual, por lo que ciertamente está utilizando un algoritmo que podría considerarse "la mejor práctica".
De hecho, la clase RijndaelManaged
normalmente requiere que se "muck" con matrices de bytes, sales, claves, vectores de inicialización, etc., pero este es precisamente el tipo de detalle que puede extraerse de alguna manera dentro de su clase "wrapper".
La siguiente clase es una que escribí hace un tiempo para realizar exactamente el tipo de cosa que está buscando, una simple llamada a un solo método para permitir que parte del texto plano basado en cadena se cifre con una contraseña basada en cadena, con la cadena cifrada resultante también siendo representado como una cadena. Por supuesto, hay un método equivalente para descifrar la cadena cifrada con la misma contraseña.
A diferencia de la primera versión de este código, que usaba exactamente los mismos valores de sal y IV cada vez, esta nueva versión generará valores aleatorios de sal y IV cada vez. Dado que sal y IV deben ser iguales entre el cifrado y el descifrado de una cadena dada, la sal y IV se anteponen al texto cifrado al encriptarse y se extraen de nuevo para poder realizar el descifrado. El resultado de esto es que cifrar exactamente el mismo texto sin formato con la misma contraseña exacta da como resultado un texto cifrado completamente diferente cada vez.
La "fuerza" de usar esto proviene del uso de la clase RijndaelManaged
para realizar el cifrado por usted, junto con el uso de la función Rfc2898DeriveBytes del espacio de nombres System.Security.Cryptography
que generará su clave de cifrado utilizando un algoritmo estándar y seguro (específicamente, PBKDF2 ) basado en la contraseña basada en cadena que proporciona. (Tenga en cuenta que esto es una mejora del uso de la primera versión del algoritmo PBKDF1 anterior).
Por último, es importante tener en cuenta que esto sigue siendo un cifrado no autenticado . El cifrado solo proporciona solo privacidad (es decir, el mensaje es desconocido para terceros), mientras que el cifrado autenticado tiene como objetivo proporcionar privacidad y autenticidad (es decir, el destinatario sabe que el remitente envió el mensaje).
Sin conocer sus requisitos exactos, es difícil decir si el código aquí es lo suficientemente seguro para sus necesidades, sin embargo, se ha producido para proporcionar un buen equilibrio entre la simplicidad relativa de la implementación frente a la "calidad". Por ejemplo, si su "receptor" de una cadena encriptada recibe la cadena directamente de un "remitente" de confianza, la autenticación puede no ser necesaria .
Si necesita algo más complejo y que ofrece cifrado autenticado, consulte esta publicación para una implementación.
Aquí está el código:
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Linq;
namespace EncryptStringSample
{
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
}
La clase anterior se puede usar simplemente con un código similar al siguiente:
using System;
namespace EncryptStringSample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please enter a password to use:");
string password = Console.ReadLine();
Console.WriteLine("Please enter a string to encrypt:");
string plaintext = Console.ReadLine();
Console.WriteLine("");
Console.WriteLine("Your encrypted string is:");
string encryptedstring = StringCipher.Encrypt(plaintext, password);
Console.WriteLine(encryptedstring);
Console.WriteLine("");
Console.WriteLine("Your decrypted string is:");
string decryptedstring = StringCipher.Decrypt(encryptedstring, password);
Console.WriteLine(decryptedstring);
Console.WriteLine("");
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
}
}
(Puede descargar una solución de muestra simple VS2013 (que incluye algunas pruebas unitarias) here ).
ACTUALIZACIÓN 23 / diciembre / 2015: la lista de mejoras específicas al código es:
- Se corrigió un error tonto donde la codificación era diferente entre cifrar y descifrar. Como el mecanismo por el cual se generan los valores de sal y IV ha cambiado, la codificación ya no es necesaria.
- Debido al cambio de sal / IV, el comentario de código anterior que indicaba incorrectamente que la codificación UTF8 de una cadena de 16 caracteres produce 32 bytes ya no es aplicable (ya que la codificación ya no es necesaria).
- El uso del algoritmo PBKDF1 reemplazado ha sido reemplazado con el uso del algoritmo PBKDF2 más moderno.
- La derivación de la contraseña ahora está correctamente salada, mientras que antes no estaba en absoluto (otro bicho estúpido aplastado).
using System.IO;
using System.Text;
using System.Security.Cryptography;
public static class EncryptionHelper
{
public static string Encrypt(string clearText)
{
string EncryptionKey = "abc123";
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
public static string Decrypt(string cipherText)
{
string EncryptionKey = "abc123";
cipherText = cipherText.Replace(" ", "+");
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
}