online encrypt ejemplo c# .net encryption openssl aes

c# - ejemplo - encrypt aes 128 php



Cifrado OpenSSL usando clases.NET (2)

Finalmente descubrí esto. En el caso de que alguien necesite integrar openssl y .NET sin utilizar los envoltorios openssl, compartiré los resultados aquí.

1) El problema principal con mi código original (como en la pregunta) es que debe inicializar BlockSize y KeySize en su instancia de RijndaelManaged ANTES de configurar la clave o IV.

2) También tenía BlockSize establecido en 256 cuando solo debería ser 128

3) El resto de mi problema llegó al hecho de que openssl pone y espera "Salted__" en la parte frontal de la sal antes de agregar la cadena encriptada y luego la codificación de base64. (Inicialmente, vi esto en la documentación de openssl con respecto al cifrado de archivos, pero no pensé que lo hiciera al hacerlo directamente a través de la línea de comandos. ¡Aparentemente estaba equivocado! ¡Tenga en cuenta también el uso de mayúsculas en la S en Salted!)

Con todo esto en mente, aquí está mi código "fijo":

public class Protection { public string OpenSSLEncrypt(string plainText, string passphrase) { // generate salt byte[] key, iv; byte[] salt = new byte[8]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetNonZeroBytes(salt); DeriveKeyAndIV(passphrase, salt, out key, out iv); // encrypt bytes byte[] encryptedBytes = EncryptStringToBytesAes(plainText, key, iv); // add salt as first 8 bytes byte[] encryptedBytesWithSalt = new byte[salt.Length + encryptedBytes.Length + 8]; Buffer.BlockCopy(Encoding.ASCII.GetBytes("Salted__"), 0, encryptedBytesWithSalt, 0, 8); Buffer.BlockCopy(salt, 0, encryptedBytesWithSalt, 8, salt.Length); Buffer.BlockCopy(encryptedBytes, 0, encryptedBytesWithSalt, salt.Length + 8, encryptedBytes.Length); // base64 encode return Convert.ToBase64String(encryptedBytesWithSalt); } public string OpenSSLDecrypt(string encrypted, string passphrase) { // base 64 decode byte[] encryptedBytesWithSalt = Convert.FromBase64String(encrypted); // extract salt (first 8 bytes of encrypted) byte[] salt = new byte[8]; byte[] encryptedBytes = new byte[encryptedBytesWithSalt.Length - salt.Length - 8]; Buffer.BlockCopy(encryptedBytesWithSalt, 8, salt, 0, salt.Length); Buffer.BlockCopy(encryptedBytesWithSalt, salt.Length + 8, encryptedBytes, 0, encryptedBytes.Length); // get key and iv byte[] key, iv; DeriveKeyAndIV(passphrase, salt, out key, out iv); return DecryptStringFromBytesAes(encryptedBytes, key, iv); } private static void DeriveKeyAndIV(string passphrase, byte[] salt, out byte[] key, out byte[] iv) { // generate key and iv List<byte> concatenatedHashes = new List<byte>(48); byte[] password = Encoding.UTF8.GetBytes(passphrase); byte[] currentHash = new byte[0]; MD5 md5 = MD5.Create(); bool enoughBytesForKey = false; // See http://www.openssl.org/docs/crypto/EVP_BytesToKey.html#KEY_DERIVATION_ALGORITHM while (!enoughBytesForKey) { int preHashLength = currentHash.Length + password.Length + salt.Length; byte[] preHash = new byte[preHashLength]; Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length); Buffer.BlockCopy(password, 0, preHash, currentHash.Length, password.Length); Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + password.Length, salt.Length); currentHash = md5.ComputeHash(preHash); concatenatedHashes.AddRange(currentHash); if (concatenatedHashes.Count >= 48) enoughBytesForKey = true; } key = new byte[32]; iv = new byte[16]; concatenatedHashes.CopyTo(0, key, 0, 32); concatenatedHashes.CopyTo(32, iv, 0, 16); md5.Clear(); md5 = null; } static byte[] EncryptStringToBytesAes(string plainText, byte[] key, byte[] iv) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); if (key == null || key.Length <= 0) throw new ArgumentNullException("key"); if (iv == null || iv.Length <= 0) throw new ArgumentNullException("iv"); // Declare the stream used to encrypt to an in memory // array of bytes. MemoryStream msEncrypt; // Declare the RijndaelManaged object // used to encrypt the data. RijndaelManaged aesAlg = null; try { // Create a RijndaelManaged object // with the specified key and IV. aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128, Key = key, IV = iv }; // Create an encryptor to perform the stream transform. ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for encryption. msEncrypt = new MemoryStream(); using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Write all data to the stream. swEncrypt.Write(plainText); swEncrypt.Flush(); swEncrypt.Close(); } } } finally { // Clear the RijndaelManaged object. if (aesAlg != null) aesAlg.Clear(); } // Return the encrypted bytes from the memory stream. return msEncrypt.ToArray(); } static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv) { // Check arguments. if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (key == null || key.Length <= 0) throw new ArgumentNullException("key"); if (iv == null || iv.Length <= 0) throw new ArgumentNullException("iv"); // Declare the RijndaelManaged object // used to decrypt the data. RijndaelManaged aesAlg = null; // Declare the string used to hold // the decrypted text. string plaintext; try { // Create a RijndaelManaged object // with the specified key and IV. aesAlg = new RijndaelManaged {Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128, Key = key, IV = iv}; // Create a decrytor to perform the stream transform. ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for decryption. using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { // Read the decrypted bytes from the decrypting stream // and place them in a string. plaintext = srDecrypt.ReadToEnd(); srDecrypt.Close(); } } } } finally { // Clear the RijndaelManaged object. if (aesAlg != null) aesAlg.Clear(); } return plaintext; } }

Estoy buscando crear una clase que use las bibliotecas .NET que son compatibles con OpenSSL. Soy consciente de que hay un contenedor OpenSSL.Net, pero preferiría evitar hacer referencia a un código de terceros no administrado. No estoy buscando una discusión sobre si esta es la opción correcta, pero hay razones para ello.

Actualmente tengo lo siguiente, que creo que debería ser compatible con OpenSSL: hace efectivamente lo que creo que OpenSSL hace desde la documentación de OpenSSL Sin embargo, incluso cuando solo utilizo esta clase para realizar tanto el cifrado como el descifrado, recibo el siguiente error:

[CryptographicException] Padding is invalid and cannot be removed.

He revisado el código y he verificado que la sal / clave / iv son todas iguales durante el proceso de cifrado y descifrado.

Vea a continuación la clase de muestra y llame para cifrar descifrar. Cualquier idea o puntero sería bienvenido.

public class Protection { public string OpenSSLEncrypt(string plainText, string passphrase) { // generate salt byte[] key, iv; byte[] salt = new byte[8]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetNonZeroBytes(salt); DeriveKeyAndIV(passphrase, salt, out key, out iv); // encrypt bytes byte[] encryptedBytes = EncryptStringToBytesAes(plainText, key, iv); // add salt as first 8 bytes byte[] encryptedBytesWithSalt = new byte[salt.Length + encryptedBytes.Length]; Buffer.BlockCopy(salt, 0, encryptedBytesWithSalt, 0, salt.Length); Buffer.BlockCopy(encryptedBytes, 0, encryptedBytesWithSalt, salt.Length, encryptedBytes.Length); // base64 encode return Convert.ToBase64String(encryptedBytesWithSalt); } public string OpenSSLDecrypt(string encrypted, string passphrase) { // base 64 decode byte[] encryptedBytesWithSalt = Convert.FromBase64String(encrypted); // extract salt (first 8 bytes of encrypted) byte[] salt = new byte[8]; byte[] encryptedBytes = new byte[encryptedBytesWithSalt.Length - salt.Length]; Buffer.BlockCopy(encryptedBytesWithSalt, 0, salt, 0, salt.Length); Buffer.BlockCopy(encryptedBytesWithSalt, salt.Length, encryptedBytes, 0, encryptedBytes.Length); // get key and iv byte[] key, iv; DeriveKeyAndIV(passphrase, salt, out key, out iv); return DecryptStringFromBytesAes(encryptedBytes, key, iv); } private static void DeriveKeyAndIV(string passphrase, byte[] salt, out byte[] key, out byte[] iv) { // generate key and iv List<byte> concatenatedHashes = new List<byte>(48); byte[] password = Encoding.UTF8.GetBytes(passphrase); byte[] currentHash = new byte[0]; MD5 md5 = MD5.Create(); bool enoughBytesForKey = false; // See http://www.openssl.org/docs/crypto/EVP_BytesToKey.html#KEY_DERIVATION_ALGORITHM while (!enoughBytesForKey) { int preHashLength = currentHash.Length + password.Length + salt.Length; byte[] preHash = new byte[preHashLength]; Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length); Buffer.BlockCopy(password, 0, preHash, currentHash.Length, password.Length); Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + password.Length, salt.Length); currentHash = md5.ComputeHash(preHash); concatenatedHashes.AddRange(currentHash); if (concatenatedHashes.Count >= 48) enoughBytesForKey = true; } key = new byte[32]; iv = new byte[16]; concatenatedHashes.CopyTo(0, key, 0, 32); concatenatedHashes.CopyTo(32, iv, 0, 16); md5.Clear(); md5 = null; } static byte[] EncryptStringToBytesAes(string plainText, byte[] key, byte[] iv) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); if (key == null || key.Length <= 0) throw new ArgumentNullException("key"); if (iv == null || iv.Length <= 0) throw new ArgumentNullException("iv"); // Declare the stream used to encrypt to an in memory // array of bytes. MemoryStream msEncrypt; // Declare the RijndaelManaged object // used to encrypt the data. RijndaelManaged aesAlg = null; try { // Create a RijndaelManaged object // with the specified key and IV. aesAlg = new RijndaelManaged { Key = key, IV = iv, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 256 }; // Create an encryptor to perform the stream transform. ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for encryption. msEncrypt = new MemoryStream(); using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Write all data to the stream. swEncrypt.Write(plainText); swEncrypt.Flush(); swEncrypt.Close(); } } } finally { // Clear the RijndaelManaged object. if (aesAlg != null) aesAlg.Clear(); } // Return the encrypted bytes from the memory stream. return msEncrypt.ToArray(); } static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv) { // Check arguments. if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (key == null || key.Length <= 0) throw new ArgumentNullException("key"); if (iv == null || iv.Length <= 0) throw new ArgumentNullException("iv"); // Declare the RijndaelManaged object // used to decrypt the data. RijndaelManaged aesAlg = null; // Declare the string used to hold // the decrypted text. string plaintext; try { // Create a RijndaelManaged object // with the specified key and IV. aesAlg = new RijndaelManaged { Key = key, IV = iv, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 256}; // Create a decrytor to perform the stream transform. ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for decryption. using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { // Read the decrypted bytes from the decrypting stream // and place them in a string. plaintext = srDecrypt.ReadToEnd(); srDecrypt.Close(); } } } } finally { // Clear the RijndaelManaged object. if (aesAlg != null) aesAlg.Clear(); } return plaintext; } }

Entonces llamo a esto para probarlo:

Protection protection = new Protection(); const string passphrase = "<passphrase>"; string encrypted = protection.OpenSSLEncrypt(jobid, passphrase); string decrypted = protection.OpenSSLDecrypt(encrypted, passphrase);


Temerosos de que haya problemas con este último código, así como con OpenSSLDecrypt se produce un error:

El relleno no es válido y no se puede eliminar.

Descripción: se produjo una excepción no controlada durante la ejecución de la solicitud web actual. Revise el seguimiento de la pila para obtener más información sobre el error y dónde se originó en el código.

Detalles de la excepción: System.Security.Cryptography.CryptographicException: El relleno no es válido y no se puede eliminar.

Ocurre en el cierre de este código:

utilizando (CryptoStream csDecrypt = new CryptoStream (msDecrypt, decryptor, CryptoStreamMode.Read)) en "cadena estática DecryptStringFromBytesAes (byte [] cipherText, byte [] key, byte [] iv)

No tenía idea de que sería tan difícil cifrar un blob de texto de una computadora y luego enviarlo para su almacenamiento y descifrado a otra.