-
-
Save scottlowe/1411917 to your computer and use it in GitHub Desktop.
require 'rubygems' | |
require 'bundler' | |
require 'gibberish' | |
password = '181cc0b200124dc748c96d8fdefe2cb3f21b48212898c2e3dd705a4c8415a5abb15b3c43ccb9e9db27e6c9ad1df1b927377c8dd6bb3d07746bc3cec7c67ca016' | |
cipher = Gibberish::AES.new(password) | |
cypher_text = cipher.encrypt("Hello from Ruby!") | |
plain_text = cipher.decrypt('U2FsdGVkX18GXWJnusOQi55IhmvfdVyjTLjAmmtcAmg=') | |
print "Encrypted string is: " | |
p cypher_text | |
puts "Decrypted string is: '#{plain_text}'" |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Security.Cryptography; | |
using System.Text; | |
namespace dotnet_aes | |
{ | |
public class OpenSslAes | |
{ | |
public static string Encrypt(string plainText, string passphrase) | |
{ | |
byte[] key, iv; | |
var salt = new byte[8]; | |
new RNGCryptoServiceProvider().GetNonZeroBytes(salt); | |
EvpBytesToKey(passphrase, salt, out key, out iv); | |
byte[] encryptedBytes = AesEncrypt(plainText, key, iv); | |
var encryptedBytesWithSalt = CombineSaltAndEncryptedData(encryptedBytes, salt); | |
return Convert.ToBase64String(encryptedBytesWithSalt); | |
} | |
// OpenSSL prefixes the combined encrypted data and salt with "Salted__" | |
private static byte[] CombineSaltAndEncryptedData(byte[] encryptedData, byte[] salt) | |
{ | |
var encryptedBytesWithSalt = new byte[salt.Length + encryptedData.Length + 8]; | |
Buffer.BlockCopy(Encoding.ASCII.GetBytes("Salted__"), 0, encryptedBytesWithSalt, 0, 8); | |
Buffer.BlockCopy(salt, 0, encryptedBytesWithSalt, 8, salt.Length); | |
Buffer.BlockCopy(encryptedData, 0, encryptedBytesWithSalt, salt.Length + 8, encryptedData.Length); | |
return encryptedBytesWithSalt; | |
} | |
public static string Decrypt(string encrypted, string passphrase) | |
{ | |
byte[] encryptedBytesWithSalt = Convert.FromBase64String(encrypted); | |
var salt = ExtractSalt(encryptedBytesWithSalt); | |
var encryptedBytes = ExtractEncryptedData(salt, encryptedBytesWithSalt); | |
byte[] key, iv; | |
EvpBytesToKey(passphrase, salt, out key, out iv); | |
return AesDecrypt(encryptedBytes, key, iv); | |
} | |
// Pull the data out from the combined salt and data | |
private static byte[] ExtractEncryptedData(byte[] salt, byte[] encryptedBytesWithSalt) | |
{ | |
var encryptedBytes = new byte[encryptedBytesWithSalt.Length - salt.Length - 8]; | |
Buffer.BlockCopy(encryptedBytesWithSalt, salt.Length + 8, encryptedBytes, 0, encryptedBytes.Length); | |
return encryptedBytes; | |
} | |
// The salt is located in the first 8 bytes of the combined encrypted data and salt bytes | |
private static byte[] ExtractSalt(byte[] encryptedBytesWithSalt) | |
{ | |
var salt = new byte[8]; | |
Buffer.BlockCopy(encryptedBytesWithSalt, 8, salt, 0, salt.Length); | |
return salt; | |
} | |
// Key derivation algorithm used by OpenSSL | |
// | |
// Derives a key and IV from the passphrase and salt using a hash algorithm (in this case, MD5). | |
// | |
// Refer to http://www.openssl.org/docs/crypto/EVP_BytesToKey.html#KEY_DERIVATION_ALGORITHM | |
private static void EvpBytesToKey(string passphrase, byte[] salt, out byte[] key, out byte[] iv) | |
{ | |
var concatenatedHashes = new List<byte>(48); | |
byte[] password = Encoding.UTF8.GetBytes(passphrase); | |
byte[] currentHash = new byte[0]; | |
MD5 md5 = MD5.Create(); | |
bool enoughBytesForKey = false; | |
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[] AesEncrypt(string plainText, byte[] key, byte[] iv) | |
{ | |
MemoryStream memoryStream; | |
RijndaelManaged aesAlgorithm = null; | |
try | |
{ | |
aesAlgorithm = new RijndaelManaged | |
{ | |
Mode = CipherMode.CBC, | |
KeySize = 256, | |
BlockSize = 128, | |
Key = key, | |
IV = iv | |
}; | |
var cryptoTransform = aesAlgorithm.CreateEncryptor(aesAlgorithm.Key, aesAlgorithm.IV); | |
memoryStream = new MemoryStream(); | |
using (var cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write)) | |
{ | |
using (var streamWriter = new StreamWriter(cryptoStream)) | |
{ | |
streamWriter.Write(plainText); | |
streamWriter.Flush(); | |
streamWriter.Close(); | |
} | |
} | |
} | |
finally | |
{ | |
if (aesAlgorithm != null) aesAlgorithm.Clear(); | |
} | |
return memoryStream.ToArray(); | |
} | |
static string AesDecrypt(byte[] cipherText, byte[] key, byte[] iv) | |
{ | |
RijndaelManaged aesAlgorithm = null; | |
string plaintext; | |
try | |
{ | |
aesAlgorithm = new RijndaelManaged | |
{ | |
Mode = CipherMode.CBC, | |
KeySize = 256, | |
BlockSize = 128, | |
Key = key, | |
IV = iv | |
}; | |
ICryptoTransform decryptor = aesAlgorithm.CreateDecryptor(aesAlgorithm.Key, aesAlgorithm.IV); | |
using (var memoryStream = new MemoryStream(cipherText)) | |
{ | |
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) | |
{ | |
using (var streamReader = new StreamReader(cryptoStream)) | |
{ | |
plaintext = streamReader.ReadToEnd(); | |
streamReader.Close(); | |
} | |
} | |
} | |
} | |
finally | |
{ | |
if (aesAlgorithm != null) aesAlgorithm.Clear(); | |
} | |
return plaintext; | |
} | |
} | |
} |
using System; | |
namespace dotnet_aes | |
{ | |
class Program | |
{ | |
private const string DotNetPlainText = "Hello from .NET"; | |
private const string CipherBase64 = "U2FsdGVkX1+wqU8tchOuA2G2I5ceNzad86pb7p2371vKJulvMCuBPQTKo5vG\ncEF9\n"; | |
private const string Password = "181cc0b200124dc748c96d8fdefe2cb3f21b48212898c2e3dd705a4c8415a5abb15b3c43ccb9e9db27e6c9ad1df1b927377c8dd6bb3d07746bc3cec7c67ca016"; | |
static void Main() | |
{ | |
DemoDecryption(); | |
DemoEncryption(); | |
Console.ReadLine(); | |
} | |
private static void DemoDecryption() | |
{ | |
var plainText = OpenSslAes.Decrypt(CipherBase64, Password); | |
Console.WriteLine("Decrypted string is: '{0}'", plainText); | |
} | |
private static void DemoEncryption() | |
{ | |
var plainText = OpenSslAes.Encrypt(DotNetPlainText, Password); | |
Console.WriteLine("Encrypted string is: '{0}'", plainText); | |
} | |
} | |
} |
@onyxraven Hi there.
I'm sorry that I've only just seen your message after all this time. You don't need to attribute me... this is public, after all. I don't remember the details concerning the writing of this, but I suspect that I patched it together from various snippets of code lying about the web, anyway!
Hi Scott, exactly what I was looking. Works on the ruby and .net sides. However, if I change the password it encrypts OK but on the .Net side I get an exception (same password of course)
password = '7B932AFA6AA07F75D2F3F6997C5809ECBB845FCD619265D52AE6F3FA29911C1E834AFAC5E06D3AA568FE8D9321CBB27FB9916620EC9B5756A20C97DE1DB2B5D7'
Private Const as String = "7B932AFA6AA07F75D2F3F6997C5809ECBB845FCD619265D52AE6F3FA29911C1E834AFAC5E06D3AA568FE8D9321CBB27FB9916620EC9B5756A20C97DE1DB2B5D7"
Any ideas ??
Thanks , this is very usefull to me.