Thanks to GregS's Point in the right direction, It was pretty easy to replicate the Key and Initial Vector generation that was happening in EVP_BytesToKey().
Basically they are creating a 48 byte array (32 byte array for the key and a 16 byte array for the IV) and using SHA1 to hash the private key and the 8 salt bytes into that buffer. The first hash is just the private key and salt and the successive hashes are the last hash generated concatenated with the key and salt bytes until the 48 byte array is filled.
The key is then just the first 32 bytes and the IV is the last 16 bytes.
Using the AESManaged class from System.Security.Crytpography and the key and IV derived from this method, I was able to encrypt my passwords in a way that the 3rd party using OpenSSL libraries could decrypt.
Here is the algorithm I used to derive the key and initial vector:
/// <summary>
/// Derives the key and IV.
/// </summary>
/// <param name="saltBytes">The salt bytes.</param>
/// <param name="privateKeyBytes">The private key bytes.</param>
/// <param name="iv">The iv.</param>
/// <returns>The Key</returns>
private static byte[] DeriveKeyAndIV(byte[] saltBytes, byte[] privateKeyBytes, out byte[] iv)
{
// we are creating a 16 byte initial vector and a 32 byte key
const int ivLength = 16;
iv = new byte[ivLength];
const int keyLength = 32;
var key = new byte[keyLength];
//SHA1 creates a 20 byte hash
const int hashLength = 20;
// container to store the hashed values
var keyContainer = new byte[keyLength + ivLength];
// munge together the privateKey and salt
var privateKeyAndSalt = new byte[privateKeyBytes.Length + saltBytes.Length];
Array.Copy(privateKeyBytes, privateKeyAndSalt, privateKeyBytes.Length);
Array.Copy(saltBytes, 0, privateKeyAndSalt, privateKeyBytes.Length, saltBytes.Length);
// use SHA1 crypto to match the -md SHA1 command line.
var sha1 = new SHA1CryptoServiceProvider();
// hashtarget holds the successive hash's source bytes.
var hashtarget = new byte[hashLength + privateKeyAndSalt.Length];
byte[] currentHash = null;
var bytesCopied = 0;
// do the hashing until we fill the container
while (bytesCopied < (ivLength + keyLength))
{
// Hash(0) is an empty set so just concatenate private key and salt.
if (currentHash == null)
{
currentHash = sha1.ComputeHash(privateKeyAndSalt);
}
else
{
// successive hashes are done on Hash(prev) + private key + salt.
Array.Copy(currentHash, hashtarget, currentHash.Length);
Array.Copy(privateKeyAndSalt, 0, hashtarget, currentHash.Length, privateKeyAndSalt.Length);
currentHash = hashtarget;
currentHash = sha1.ComputeHash(currentHash);
}
var copyAmount = Math.Min(currentHash.Length, keyContainer.Length - bytesCopied);
Array.Copy(currentHash, 0, keyContainer, bytesCopied, copyAmount);
bytesCopied += copyAmount;
}
// split out bytes in the container. first 32 are key, last 16 are iv.
Array.Copy(keyContainer, 0, key, 0, key.Length);
Array.Copy(keyContainer, key.Length, iv, 0, iv.Length);
return key;
}