2009-06-09 18 views
11

Básicamente quiero usar System.Security.Cryptography.AesManaged (¿o una clase mejor, si cree que hay uno?) Para tomar una matriz de bytes y crear otra matriz de bytes cifrados, usando una clave simétrica dada (supongo que ' ¿Necesito uno?).Cómo usar 'System.Security.Cryptography.AesManaged' para cifrar un byte []?

También necesitaré la forma de invertir este procedimiento.

El objetivo es cifrar las contraseñas almacenadas. ¿Supongo que hay una manera simple de hacer esto?

Gracias

Respuesta

7

Simple encrypting and decrypting data in C#.

Editar: Para las contraseñas, yo recomendaría usar BCrypt en vez de hacer un cifrado de doble sentido, a menos que realmente necesita para recuperar la contraseña original. Normalmente solo necesita el hecho de que alguien conocía la contraseña, no la contraseña en sí misma.

+0

Se ve bien, pero ¿qué es un IV? Pensé que solo necesitaría una clave de 16 bytes. – Chris

+0

http://en.wikipedia.org/wiki/Initialization_vector. Puede aumentar la fuerza si coloca elementos aleatorios allí, pero también podría usar ceros. –

+0

Necesito las contraseñas para pasarlas a otro servicio. – Chris

10

EDIT: Noted edición de eed3si9n ... Acepto, el cifrado simétrico es una mala opción para las contraseñas. Use hashes (y no MD5) en su lugar. Aquí está a very complete example.

Un ejemplo sencillo:

byte[] clear = GetCleartext(); 
HashAlgorithm sha2 = SHA256CryptoServiceProvider.Create(); 
byte[] hashed = sha2.ComputeHash(clear); 

Para validar una contraseña correcta, se correría el mismo cálculo sobre la contraseña proporcionada, y comparar el resultado con el hash que tiene en su base de datos.

Es una buena práctica agregar sal (datos aleatorios) al texto sin formato para evitar rainbow table attacks. Básicamente, agregue un valor conocido generado aleatoriamente, exclusivo de ese usuario, al texto sin formato antes del hash.

+0

Y una aclaración: el valor de sal debe mantenerse junto con el hash para las comparaciones posteriores. Y genere una sal nueva cada vez que el usuario cambie la contraseña. – devstuff

+3

Necesito las contraseñas para pasarlas a otro servicio. – Chris

11

Esto es lo que hice al final, inspirado en (una versión anterior de) la respuesta de Michael:

private string Encrypt(string input) 
{ 
    return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(input))); 
} 
private byte[] Encrypt(byte[] input) 
{ 
    PasswordDeriveBytes pdb = new PasswordDeriveBytes("hjiweykaksd", new byte[] { 0x43, 0x87, 0x23, 0x72, 0x45, 0x56, 0x68, 0x14, 0x62, 0x84 }); 
    MemoryStream ms = new MemoryStream(); 
    Aes aes = new AesManaged(); 
    aes.Key = pdb.GetBytes(aes.KeySize/8); 
    aes.IV = pdb.GetBytes(aes.BlockSize/8); 
    CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write); 
    cs.Write(input, 0, input.Length); 
    cs.Close(); 
    return ms.ToArray(); 
} 
private string Decrypt(string input) 
{ 
    return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(input))); 
} 
private byte[] Decrypt(byte[] input) 
{ 
    PasswordDeriveBytes pdb = new PasswordDeriveBytes("hjiweykaksd", new byte[] { 0x43, 0x87, 0x23, 0x72, 0x45, 0x56, 0x68, 0x14, 0x62, 0x84 }); 
    MemoryStream ms = new MemoryStream(); 
    Aes aes = new AesManaged(); 
    aes.Key = pdb.GetBytes(aes.KeySize/8); 
    aes.IV = pdb.GetBytes(aes.BlockSize/8); 
    CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write); 
    cs.Write(input, 0, input.Length); 
    cs.Close(); 
    return ms.ToArray(); 
} 
+6

Dado su código anterior, terminará con la misma clave cada vez, lo cual es bueno, ** pero también terminará con el mismo IV cada vez, lo cual es malo **. Estoy bastante seguro de que el IV debe ser específico para los datos que está encriptando, mientras que el Key puede ser "global". –

0

El PO estados que tienen que pasar las credenciales a otro servicio, lo cual es un tema completamente diferente a la de almacenamiento de contraseñas y verificación.

Dependiendo de cuánto control tenga sobre el servicio de socio, o qué exponen, las mejores soluciones implican un proveedor proporcionado o enfoques estándar de la industria como Kerberos, SAML u otro token de soporte estable y seguro para transmitir confianza. Este es un tema profundo.

Pero supongamos que necesita pasar credenciales a través de Basic Auth SSL/TLS. Entonces ahora necesita almacenarlos de forma segura y reversible. Para resolver este problema, he tenido éxito con la clave secreta que se transmite utilizando una clave privada de certificado. Esto ofrece cierta protección de su secreto por parte del sistema operativo y permite a las personas OPS administrar las claves, lo cual es deseable. La cuenta utilizada para ejecutar su proceso debe tener derechos para ver la clave privada, que luego termina la cadena de confianza en el sistema operativo.

Quizás tenga que pensar en la rotación de teclas, lo que requerirá que almacene un número de versión con el texto de cifrado.

También, SecureString podría ser de interés, pero hasta que todas las API de .NET permitan que SecureString pase como parte de una credencial, muchas veces terminas con una cadena en el montón administrado que no puedes destruir.

De todos modos, esta no es una respuesta alimentada por cuchara con código, pero por experiencia, he encontrado que administrar la cadena de secretos siempre es un problema, y ​​si no puede terminar en una infraestructura reforzada como Active Directory, certificados son la segunda mejor opción.