2012-02-28 6 views
15

उदाहरण के लिए, आदेश:ओपनएसएसएल कमांड के साथ संगत कुंजी फ़ंक्शन पर पासवर्ड?

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

आउटपुट की तरह कुछ:

key = 33D890D33F91D52FC9B405A0DDA65336C3C4B557A3D79FE69AB674BE82C5C3D2 
iv = 677C95C475C0E057B739750748608A49 

कैसे है कि कुंजी उत्पन्न होता है? (उत्तर के रूप में सी कोड पूछने के लिए बहुत ही बढ़िया होगा :)) इसके अलावा, iv उत्पन्न कैसे किया जाता है?

मुझे किसी प्रकार का हेक्स जैसा दिखता है।

उत्तर

30

ओपनएसएसएल फ़ंक्शन EVP_BytesToKey का उपयोग करता है। आप इसे apps/enc.c में कॉल कर सकते हैं। enc उपयोगिता ने मुख्य रूप से -md तर्क के साथ एक अलग डाइजेस्ट निर्दिष्ट नहीं किया है, तो मुख्य व्युत्पन्न एल्गोरिदम (केडीएफ) में डिफ़ॉल्ट रूप से MD5 डाइजेस्ट का उपयोग करने के लिए उपयोग किया जाता है। अब यह डिफ़ॉल्ट रूप से SHA-256 का उपयोग करता है।

#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 का उपयोग कर अवयव। पूर्व में, एमडी 5 का इस्तेमाल किया गया था, और 1.1.0 एसएचए 256 पर स्विच किया गया था। सावधान रहें कि परिवर्तन EVP_BytesToKey और openssl enc जैसे कमांड में आपको प्रभावित नहीं कर रहा है।

+0

बहुत बढ़िया possum! – Tudorizer

+1

इसने मेरे जीवन को बचाया। मैं openssl की कुंजी और iv पासफ्रेज़ और नमक (आईओएस में) का उपयोग नहीं कर सका। मेरे प्रोजेक्ट में openssl पुस्तकालयों को एम्बेड करने के बाद, मैं इसका उपयोग करने में सक्षम था। –

+0

क्या इस फ़ंक्शन का कार्यान्वयन या क्रिप्टो ++ में समान है? – goji

1

किसी स्विफ्ट में एक ही लागू करने के लिए लग रही है अगर मैं तेजी से

/* 
- 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 का उपयोग करें। परीक्षण किया है और काम कर रहा - यहाँ mbedTLS/ध्रुवीय एसएसएल के लिए एक संस्करण है स्विफ्ट 3

+0

* "यह एक बहुत साफ तरीका है क्योंकि सेब आईओएस में ओपनएसएसएल की सिफारिश नहीं करता है ..." * - ओपनएसएसएल अपडेट हो जाता है; आईओएस छोड़ दिया जाता है। लंबे समय तक, ऐप्पल पर निर्भर नहीं है। – jww

+0

@jww मेरे अनुभव से जब सेब कहता है "अनुशंसित नहीं" गंभीरता से लिया जाना चाहिए। मैं जो कहता हूं उससे सहमत हूं लेकिन मैं अपना ऐप अस्वीकार नहीं कर रहा हूं। मुझे पता है कि बहुत सारे पीपीएल अभी भी आईओएस में ओपनएसएसएल का उपयोग करते हैं (मैंने भी किया)। मुझे सच में डर है कि एप्पल क्या निर्णय लेता है – spaceMonkey

+0

क्या यह स्विफ्ट संस्करण वास्तव में काम करता है? आप "addmd" चर का उपयोग नहीं करते हैं और लूप के माध्यम से पहली बार के बाद अंतिम पाचन की प्रतिक्रिया छोड़ दी है ... – PatchyFog

0

: इस सेब के रूप में एक अधिक स्वच्छ रास्ता आईओएस में OpenSSL की सिफारिश नहीं करता

अद्यतन है।


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

किसी के माध्यम से यहां से गुजर रहा एक काम कर, हास्केल में performant संदर्भ कार्यान्वयन की तलाश में है, तो यहां उसे है:

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 पैकेज द्वारा प्रदान की हैश एल्गोरिदम का उपयोग करता। तर्क बाइट्स में वांछित कुंजी और चौथाई आकार हैं, हैश एल्गोरिदम का उपयोग करने के लिए (उदाहरण के लिए (undefined :: MD5)), वैकल्पिक नमक और पासवर्ड। नतीजा कुंजी और चौथाई का एक गुच्छा है।

संबंधित मुद्दे