2012-02-28 78 views
15

例如,命令:與OpenSSL命令兼容的密鑰功能密碼?

key = 33D890D33F91D52FC9B405A0DDA65336C3C4B557A3D79FE69AB674BE82C5C3D2 
iv = 677C95C475C0E057B739750748608A49 

是如何生成的關鍵:

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

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

看起來像某種十六進制給我。

回答

30

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

1

如果有人正在尋找實現在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

0

這裏是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; 
} 
0

如果有人通過路過此地正在尋找工作,高性能的參考實現在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的元組。

相關問題