使用System.Security.Cryptography加密文本以匹配OpenSSL

时间:2010-10-15 14:35:34

标签: encryption c#-4.0 openssl sha1

我需要正确加密文本(特定密码),以便第三方可以解密它。他们为我提供了他们用来解密的密钥,并告诉我他们将使用OpenSSL解密它。

我一直在尝试使用AESManaged和System.Security.Cryptography中的RijndaelManaged类来创建可解密但不是非常成功的东西。

他们提供的加密的OpenSSL示例是:

  

回显“密码”| enc -base64   -aes-256-cbc -k“providedKey”-p -md sha1

所以我需要创建一个CryptoStream,它是一个密钥大小为256的AES加密器,以及一个CBC的密码模式。然后base64编码生成的字节数组。那部分非常简单。

我不确定如何创造是关键,我正在寻找正确方向的一点。

我注意到OpenSSL中这些参数创建的所有base64解码文本都以相同的8个字符“Salted__”开头。所以我猜这是用来生成密钥的Salt。

任何人都知道如何使用私钥和“Salted __”创建SHA1密钥?

我知道OpenSSL.Net项目用于包装OpenSSL dll,但我希望尽可能避免使用该路由。

2 个答案:

答案 0 :(得分:3)

感谢GregS's Point in the right direction,复制EVP_BytesToKey()中发生的密钥和初始向量生成非常容易。

基本上他们创建了一个48字节的数组(密钥为32字节数组,IV为16字节数组),并使用SHA1将私钥和8个盐字节散列到该缓冲区。第一个哈希只是私钥和salt,连续哈希是生成的最后一个哈希,它与key和salt字节连接起来,直到填充48字节数组。

密钥只是前32个字节,IV是最后16个字节。

使用AESManaged中的System.Security.Crytpography类以及从此方法派生的密钥和IV,我能够以使用OpenSSL库的第三方可以解密的方式加密我的密码。

这是我用来导出密钥和初始向量的算法:

    /// <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;
    }  

答案 1 :(得分:1)

我在相关的openssl源(apps/enc.c)中略微探讨了一下,我认为openssl使用了一种有点专有的方法。我承认我太懒了,无法弄清楚所有的细节,但他们在那里。看起来ASCII字符串“Salted__”后跟8个随机盐字节被添加到文件中。使用名为EVP_BytesToKey()的openssl方法从密码和salt 派生 AES的AES密钥。该手册中描述了该算法。在版本1.0.0a的enc.c source code中,此部分从第510行开始。

希望这可以让你开始。