2012-02-28 2 views
15

명령 : 같은key to key 기능은 OpenSSL 명령과 호환됩니까? 예를 들어

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

출력 뭔가 :

key = 33D890D33F91D52FC9B405A0DDA65336C3C4B557A3D79FE69AB674BE82C5C3D2 
iv = 677C95C475C0E057B739750748608A49 

어떻게 그 키가 생성됩니다? (C 코드는 답을 구하기에는 너무 좋을 것입니다 :)) 또한 iv가 어떻게 생성됩니까?

나에게 어떤 종류의 헥스처럼 보입니다.

답변

30

OpenSSL은 EVP_BytesToKey 기능을 사용합니다. apps/enc.c에서 전화를 찾을 수 있습니다. enc 유틸리티는 -md 인수로 다른 다이제스트를 지정하지 않은 경우 키 유도 알고리즘 (KDF)에서 기본적으로 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; 
} 

사용 예제 :

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

OpenSSL 1.1.0c changed the digest algorithm 일부 내부에서 사용이 OpenSSL을 명령 줄과 동일한 키를 생성

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

다음은 작업 예를 사용하여 MD5입니다 구성 요소. 이전에는 MD5가 사용되고 1.1.0은 SHA256으로 전환되었습니다. 변경 사항이 EVP_BytesToKeyopenssl enc과 같은 명령에 영향을 미치지 않도록주의하십시오. 사람이 SWIFT 에서 동일하게 구현하기위한 찾고 있다면

+0

굉장한 포섬! – Tudorizer

+1

이것은 내 생명을 구했습니다. i는 openssl의 키를 얻을 수 없었고 iv는 암호와 salt (ios)를 사용했습니다. 내 프로젝트에 openssl 라이브러리를 임베드 한 후에, 나는 이것을 사용할 수 있었다. –

+0

이 함수 또는 이와 유사한 구현이 crypto ++에 있습니까? – goji

1

은 내가 해시에 대한 CryptoSwift를 사용

/* 
- 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 변환. 테스트 작업 - 여기 mbedTLS/폴라 SSL의 버전이 3

+0

* "사과가 iOS에서 OpenSSL을 권장하지 않으므로 훨씬 깨끗합니다."* - OpenSSL이 업데이트되었습니다. iOS가 포기 됨. 결국에는 애플에 의존하지 마십시오. – jww

+0

사과가 "권장하지 않음"이라고 진지하게 받아 들여야 할 때 제 경험으로 얻은 @jww. 내가 무슨 말을하지만 나는 내 애플 리케이션을 거부하지 않는 데 동의합니다. 나는 많은 ppl이 여전히 iOS에서 OpenSSL을 사용하고 있음을 안다. 정말 사과 결정이 무서워요 – spaceMonkey

+0

이 스위프트 버전이 실제로 작동합니까? 당신은 "addmd"변수를 사용하지 않고 루프를 통해 처음으로 마지막 다이제스트의 피드백을 생략했습니다 ... – PatchyFog

0

스위프트 : 이것은 아이폰 OS에

UPDATE를 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

, 여기있다 :

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의 튜플입니다.