Passwort für Schlüsselfunktion kompatibel mit OpenSSL-Befehlen?

Lesezeit: 9 Minuten

Benutzer-Avatar
Tudor

Zum Beispiel der Befehl:

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

gibt sowas aus wie:

key = 33D890D33F91D52FC9B405A0DDA65336C3C4B557A3D79FE69AB674BE82C5C3D2
iv  = 677C95C475C0E057B739750748608A49

Wie wird dieser Schlüssel generiert? (C-Code als Antwort wäre zu großartig, um danach zu fragen :)) Außerdem, wie wird das iv generiert?

Sieht für mich nach einer Art Hex aus.

Benutzer-Avatar
Einzeln

OpenSSL verwendet die Funktion EVP_BytesToKey. Den Aufruf dazu findet ihr in apps/enc.c. Das enc Dienstprogramm verwendet, um den MD5-Digest standardmäßig im Key Derivation Algorithm (KDF) zu verwenden, wenn Sie mit dem keinen anderen Digest angegeben haben -md Streit. Jetzt verwendet es standardmäßig SHA-256. Hier ist ein funktionierendes Beispiel mit 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;
}

Beispielnutzung:

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

Was denselben Schlüssel generiert wie diese OpenSSL-Befehlszeile:

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

OpenSSL 1.1.0c hat den in einigen internen Komponenten verwendeten Digest-Algorithmus geändert. Früher wurde MD5 verwendet und mit 1.1.0 auf SHA256 umgestellt. Seien Sie vorsichtig, dass die Änderung Sie nicht in beiden betrifft EVP_BytesToKey und Befehle wie openssl enc.

  • das hat mir das Leben gerettet. Ich konnte den Schlüssel von openssl und iv nicht mit Passphrase und Salt (in ios) abrufen. Nach dem Einbetten von Openssl-Bibliotheken in mein Projekt konnte ich diese verwenden.

    – Furkan Mustafa

    11. April 2012 um 8:52 Uhr

  • Gibt es eine Implementierung dieser Funktion oder ähnliches in Crypto++?

    – goji

    8. September 2012 um 9:37 Uhr

  • @ Troy: Ich weiß es nicht. Sie sollten es wahrscheinlich als Frage stellen, anstatt es zu kommentieren.

    – individuell

    10. September 2012 um 0:08 Uhr

  • Ist es möglich, ein Zeichen* oder eine Datei mit dieser Methode zu verschlüsseln, z. B. mit C:\>openssl enc –e -in data.bin -out data.enc -aes-256-cbc -p –nosalt , wo data.bin ist die Eingabedatei und data.enc die verschlüsselte Datei ?

    – angereichert

    6. September 2013 um 14:51 Uhr


  • Beachten Sie, dass enc Die Standardeinstellung auf SHA-256 ist nur in 1.1.0 enthalten, das ab Juni 2016 noch Beta ist.

    – dave_thompson_085

    10. Juni 2016 um 15:52 Uhr

Benutzer-Avatar
spaceMonkey

Wenn jemand nach der Implementierung des gleichen in SWIFT sucht, habe ich das konvertiert EVP_BytesToKey schnell

 /*
 - 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

}

ich benutze CryptoSwift für den Hasch. Dies ist ein viel saubererer Weg, da Apples OpenSSL in iOS nicht empfiehlt

Update: Swift 3

  • “Dies ist ein viel saubererer Weg, da Apples OpenSSL in iOS nicht empfiehlt …” – OpenSSL wird aktualisiert; iOS wird aufgegeben. Verlassen Sie sich langfristig nicht auf Apple.

    – jww

    15. Juli 2016 um 17:23 Uhr


  • @jww aus meiner Erfahrung, wenn Apple “Nicht empfohlen” sagt, muss ernst genommen werden. Ich stimme dem zu, was du sagst, aber meine App wird nicht abgelehnt. Ich weiß, dass viele Leute immer noch OpenSSL in iOS verwenden (ich auch). Ich bin wirklich erschrocken, welche Entscheidungen Apple trifft

    – SpaceMonkey

    15. Juli 2016 um 18:05 Uhr

  • Funktioniert diese Swift-Version tatsächlich? Sie verwenden die Variable “addmd” nicht und haben die Rückkopplung des letzten Digests in den nächsten nach dem ersten Durchlaufen der Schleife weggelassen …

    – PatchyFog

    5. April 2017 um 6:21 Uhr

  • Ich nehme an, das liegt daran, dass der Digest in der ersten Schleife Ihrer Verwendung groß genug ist, um Ihren Schlüssel und IV zu füllen. Wenn Sie mehr Digest erstellen müssten, indem Sie Ihre äußere Schleife mehr als einmal nehmen, wäre das “rechte Ende” Ihrer Ausgabe falsch. Je nach Größe der angeforderten keyLen können diese fehlerhaften Bytes am rechten Ende des Ausgabeschlüssels oder im IV liegen.

    – PatchyFog

    7. April 2017 um 15:04 Uhr


Hier ist eine Version für mbedTLS / Polar SSL – getestet und funktioniert.


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

Wenn jemand, der hier vorbeikommt, nach einer funktionierenden, performanten Referenzimplementierung in Haskell sucht, hier ist sie:

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)

Es verwendet Hash-Algorithmen, die von bereitgestellt werden Kryptonit Paket. Die Argumente sind der gewünschte Schlüssel und die IV-Größe in Bytes, der zu verwendende Hash-Algorithmus (wie z (undefined :: MD5)), optional Salt und das Passwort. Das Ergebnis ist ein Tupel aus Schlüssel und IV.

1216290cookie-checkPasswort für Schlüsselfunktion kompatibel mit OpenSSL-Befehlen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy