密钥function与OpenSSL命令兼容?

例如,命令:

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

输出类似于:

 key = 33D890D33F91D52FC9B405A0DDA65336C3C4B557A3D79FE69AB674BE82C5C3D2 iv = 677C95C475C0E057B739750748608A49 

这个密钥是如何产生的? (C代码作为一个答案将太棒了,要求:))另外,如何生成iv?

看起来像是对我的一种hex。

OpenSSL使用函数EVP_BytesToKey 。 你可以在apps/enc.cfind对它的调用。 如果您没有使用-md参数指定不同的摘要,则密钥导出algorithm(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更改了某些内部组件中使用的摘要algorithm 。 以前使用MD5,1.1.0切换到SHA256。 在EVP_BytesToKey和像openssl enc这样的命令中,注意这个改变不会影响到你。

如果有人正在寻找在SWIFT中实现相同,我迅速转换了EVP_BytesToKey

  /* - parameter keyLen: keyLen - parameter ivLen: ivLen - parameter digest: digest eg "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 } 

我使用CryptoSwift作为散列。 这是一个更清洁的方式,因为苹果不build议在iOS中使用OpenSSL

更新:Swift 3

这里是mbedTLS /极地SSL的一个版本 – testing和工作。

 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 (eg 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; }