与OpenSSL命令兼容的密钥功能密码?

与OpenSSL命令兼容的密钥功能密码?

问题描述:

例如,命令:与OpenSSL命令兼容的密钥功能密码?

key = 33D890D33F91D52FC9B405A0DDA65336C3C4B557A3D79FE69AB674BE82C5C3D2 
iv = 677C95C475C0E057B739750748608A49 

是如何生成的关键:

openssl enc -aes-256-cbc -a -in test.txt -k pinkrhino -nosalt -p -out openssl_output.txt 

输出像? (C代码作为答案太令人敬畏了:)) 另外,如何生成iv?

看起来像某种十六进制给我。

OpenSSL使用函数EVP_BytesToKey。你可以在apps/enc.c找到它的电话。如果您没有使用-md参数指定不同的摘要,则密钥导出算法(KDF)中默认使用enc实用程序来使用MD5摘要。现在默认使用SHA-256。这里的一个工作示例使用MD5:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <openssl/evp.h> 

int main(int argc, char *argv[]) 
{ 
    const EVP_CIPHER *cipher; 
    const EVP_MD *dgst = NULL; 
    unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; 
    const char *password = "password"; 
    const unsigned char *salt = NULL; 
    int i; 

    OpenSSL_add_all_algorithms(); 

    cipher = EVP_get_cipherbyname("aes-256-cbc"); 
    if(!cipher) { fprintf(stderr, "no such cipher\n"); return 1; } 

    dgst=EVP_get_digestbyname("md5"); 
    if(!dgst) { fprintf(stderr, "no such digest\n"); return 1; } 

    if(!EVP_BytesToKey(cipher, dgst, salt, 
     (unsigned char *) password, 
     strlen(password), 1, key, iv)) 
    { 
     fprintf(stderr, "EVP_BytesToKey failed\n"); 
     return 1; 
    } 

    printf("Key: "); for(i=0; i<cipher->key_len; ++i) { printf("%02x", key[i]); } printf("\n"); 
    printf("IV: "); for(i=0; i<cipher->iv_len; ++i) { printf("%02x", iv[i]); } printf("\n"); 

    return 0; 
} 

实例:

gcc b2k.c -o b2k -lcrypto -g 
./b2k 
Key: 5f4dcc3b5aa765d61d8327deb882cf992b95990a9151374abd8ff8c5a7a0fe08 
IV: b7b4372cdfbcb3d16a2631b59b509e94 

生成相同的密钥,因为这OpenSSL的命令行:

openssl enc -aes-256-cbc -k password -nosalt -p < /dev/null 
key=5F4DCC3B5AA765D61D8327DEB882CF992B95990A9151374ABD8FF8C5A7A0FE08 
iv =B7B4372CDFBCB3D16A2631B59B509E94 

OpenSSL 1.1.0c changed the digest algorithm在一些内部使用组件。以前使用MD5,1.1.0切换到SHA256。请注意,变更不会影响您在EVP_BytesToKeyopenssl enc之类的命令。

+0

真棒负鼠! – Tudorizer 2012-02-29 20:27:41

+1

这救了我的命。我无法使用passssrase和salt(在ios中)获得openssl的密钥和iv。在将openssl库嵌入到我的项目之后,我能够使用它。 – 2012-04-11 08:52:19

+0

在crypto ++中是否有这个函数或类似的实现? – goji 2012-09-08 09:37:38

如果有人正在寻找实现在SWIFT 同我迅速

/* 
- parameter keyLen: keyLen 
- parameter ivLen: ivLen 
- parameter digest: digest e.g "md5" or "sha1" 
- parameter salt: salt 
- parameter data: data 
- parameter count: count 

- returns: key and IV respectively 
*/ 
open static func evpBytesToKey(_ keyLen:Int, ivLen:Int, digest:String, salt:[UInt8], data:Data, count:Int)-> [[UInt8]] { 
    let saltData = Data(bytes: UnsafePointer<UInt8>(salt), count: Int(salt.count)) 
    var both = [[UInt8]](repeating: [UInt8](), count: 2) 
    var key = [UInt8](repeating: 0,count: keyLen) 
    var key_ix = 0 
    var iv = [UInt8](repeating: 0,count: ivLen) 
    var iv_ix = 0 

    var nkey = keyLen; 
    var niv = ivLen; 

    var i = 0 
    var addmd = 0 
    var md:Data = Data() 
    var md_buf:[UInt8] 

    while true { 

     addmd = addmd + 1 
     md.append(data) 
     md.append(saltData) 

     if(digest=="md5"){ 
      md = NSData(data:md.md5()) as Data 
     }else if (digest == "sha1"){ 
      md = NSData(data:md.sha1()) as Data 
     } 

     for _ in 1...(count-1){ 

      if(digest=="md5"){ 
       md = NSData(data:md.md5()) as Data 
      }else if (digest == "sha1"){ 
       md = NSData(data:md.sha1()) as Data 
      } 
     } 
     md_buf = Array (UnsafeBufferPointer(start: md.bytes, count: md.count)) 
     //   md_buf = Array(UnsafeBufferPointer(start: md.bytes.bindMemory(to: UInt8.self, capacity: md.count), count: md.length)) 
     i = 0 
     if (nkey > 0) { 
      while(true) { 
       if (nkey == 0){ 
        break 
       } 
       if (i == md.count){ 
        break 
       } 
       key[key_ix] = md_buf[i]; 
       key_ix = key_ix + 1 
       nkey = nkey - 1 
       i = i + 1 
      } 
     } 
     if (niv > 0 && i != md_buf.count) { 
      while(true) { 
       if (niv == 0){ 
        break 
       } 
       if (i == md_buf.count){ 
        break 
       } 
       iv[iv_ix] = md_buf[i] 
       iv_ix = iv_ix + 1 
       niv = niv - 1 
       i = i + 1 
      } 
     } 
     if (nkey == 0 && niv == 0) { 
      break 
     } 

    } 
    both[0] = key 
    both[1] = iv 

    return both 

} 

转换的EVP_BytesToKey我用CryptoSwift为乱码。 这是苹果更清洁的方式不建议OpenSSL的iOS中

UPDATE:斯威夫特3

+0

*“这是一个更清洁的方式,因为苹果不建议在iOS中使用OpenSSL ...” - - OpenSSL得到更新; iOS被遗弃。从长远来看,不要依赖苹果。 – jww 2016-07-15 17:23:34

+0

@jww从我的经验,当苹果说“不推荐”必须认真对待。我同意你的说法,但我不会拒绝我的应用程序。我知道很多ppl在iOS中仍然使用OpenSSL(我也是)。我真的害怕苹果需要做出什么决定 – spaceMonkey 2016-07-15 18:05:28

+0

这个Swift版本实际上工作吗?你不使用“addmd”变量,并且在第一次通过循环后省略了最后一个摘要的反馈... – PatchyFog 2017-04-05 06:21:05

这里是mbedTLS /极地SSL版本 - 测试工作。


typedef int bool; 
#define false 0 
#define true (!false) 
//------------------------------------------------------------------------------ 
static bool EVP_BytesToKey(const unsigned int nDesiredKeyLen, const unsigned char* salt, 
          const unsigned char* password, const unsigned int nPwdLen, 
          unsigned char* pOutKey, unsigned char* pOutIV) 
{ 
    // This is a re-implemntation of openssl's password to key & IV routine for mbedtls. 
    // (See openssl apps/enc.c and /crypto/evp/evp_key.c) It is not any kind of 
    // standard (e.g. PBKDF2), and it only uses an interation count of 1, so it's 
    // pretty crappy. MD5 is used as the digest in Openssl 1.0.2, 1.1 and late 
    // use SHA256. Since this is for embedded system, I figure you know what you've 
    // got, so I made it compile-time configurable. 
    // 
    // The signature has been re-jiggered to make it less general. 
    // 
    // See: https://wiki.openssl.org/index.php/Manual:EVP_BytesToKey(3) 
    // And: https://www.cryptopp.com/wiki/OPENSSL_EVP_BytesToKey 

#define IV_BYTE_COUNT  16 

#if BTK_USE_MD5 
# define DIGEST_BYTE_COUNT 16 // MD5 
#else 
# define DIGEST_BYTE_COUNT 32 // SHA 
#endif 

    bool bRet; 
    unsigned char md_buf[ DIGEST_BYTE_COUNT ]; 
    mbedtls_md_context_t md_ctx; 
    bool bAddLastMD = false; 
    unsigned int nKeyToGo = nDesiredKeyLen; // 32, typical 
    unsigned int nIVToGo = IV_BYTE_COUNT; 

    mbedtls_md_init(&md_ctx); 

#if BTK_USE_MD5 
    int rc = mbedtls_md_setup(&md_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_MD5 ), 0); 
#else 
    int rc = mbedtls_md_setup(&md_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 0); 
#endif 

    if (rc != 0) 
    { 
     fprintf(stderr, "mbedutils_md_setup() failed -0x%04x\n", -rc); 
     bRet = false; 
     goto exit; 
    } 

    while(1) 
    { 
     mbedtls_md_starts(&md_ctx); // start digest 

     if (bAddLastMD == false) // first time 
     { 
      bAddLastMD = true;  // do it next time 
     } 
     else 
     { 
      mbedtls_md_update(&md_ctx, &md_buf[0], DIGEST_BYTE_COUNT); 
     } 

     mbedtls_md_update(&md_ctx, &password[0], nPwdLen); 
     mbedtls_md_update(&md_ctx, &salt[0], 8); 
     mbedtls_md_finish(&md_ctx, &md_buf[0]); 

     // 
     // Iteration loop here in original removed as unused by "openssl enc" 
     // 

     // Following code treats the output key and iv as one long, concatentated buffer 
     // and smears as much digest across it as is available. If not enough, it takes the 
     // big, enclosing loop, makes more digest, and continues where it left off on 
     // the last iteration. 
     unsigned int ii = 0; // index into mb_buf 

     if (nKeyToGo != 0) // still have key to fill in? 
     { 
      while(1) 
      { 
       if (nKeyToGo == 0)    // key part is full/done 
        break; 
       if (ii == DIGEST_BYTE_COUNT)  // ran out of digest, so loop 
        break; 

       *pOutKey++ = md_buf[ ii ];   // stick byte in output key 
       nKeyToGo--; 
       ii++; 
      } 
     } 

     if (nIVToGo != 0     // still have fill up IV 
      &&        // and 
      ii != DIGEST_BYTE_COUNT   // have some digest available 
      ) 
     { 
      while(1) 
      { 
       if (nIVToGo == 0)    // iv is full/done 
        break; 
       if (ii == DIGEST_BYTE_COUNT) // ran out of digest, so loop 
        break; 
       *pOutIV++ = md_buf[ ii ];  // stick byte in output IV 
       nIVToGo--; 
       ii++; 
      } 
     } 

     if (nKeyToGo == 0 && nIVToGo == 0) // output full, break main loop and exit 
      break; 
    } // outermost while loop 

    bRet = true; 

    exit: 
    mbedtls_md_free(&md_ctx); 
    return bRet; 
} 

如果有人通过路过此地正在寻找工作,高性能的参考实现在Haskell,那就是:

import Crypto.Hash 
import qualified Data.ByteString as B 
import Data.ByteArray    (convert) 
import Data.Monoid     ((<>)) 

evpBytesToKey :: HashAlgorithm alg => 
    Int -> Int -> alg -> Maybe B.ByteString -> B.ByteString -> (B.ByteString, B.ByteString) 
evpBytesToKey keyLen ivLen alg mSalt password = 
    let bytes  = B.concat . take required . iterate go $ hash' passAndSalt 
     (key, rest) = B.splitAt keyLen bytes 
    in (key, B.take ivLen rest) 
    where 
    hash'  = convert . hashWith alg 
    required = 1 + ((keyLen + ivLen - 1) `div` hashDigestSize alg) 
    passAndSalt = maybe password (password <>) mSalt 
    go   = hash' . (<> passAndSalt) 

它使用由cryptonite包中提供的哈希算法。这些参数是字节所需的密钥和IV大小,使用的哈希算法(例如,如(undefined :: MD5)),可选的盐和密码。结果是一个关键和IV的元组。