与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_BytesToKey
和openssl enc
之类的命令。
如果有人正在寻找实现在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
*“这是一个更清洁的方式,因为苹果不建议在iOS中使用OpenSSL ...” - - OpenSSL得到更新; iOS被遗弃。从长远来看,不要依赖苹果。 – jww 2016-07-15 17:23:34
@jww从我的经验,当苹果说“不推荐”必须认真对待。我同意你的说法,但我不会拒绝我的应用程序。我知道很多ppl在iOS中仍然使用OpenSSL(我也是)。我真的害怕苹果需要做出什么决定 – spaceMonkey 2016-07-15 18:05:28
这个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的元组。
真棒负鼠! – Tudorizer 2012-02-29 20:27:41
这救了我的命。我无法使用passssrase和salt(在ios中)获得openssl的密钥和iv。在将openssl库嵌入到我的项目之后,我能够使用它。 – 2012-04-11 08:52:19
在crypto ++中是否有这个函数或类似的实现? – goji 2012-09-08 09:37:38