Java-эквивалент C # Rfc2898DerivedBytes - PullRequest
6 голосов
/ 18 июня 2009

Мне было интересно, пытался ли кто-нибудь сделать эквивалент

Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(secret, saltValueBytes);
byte[] secretKey = key.GetBytes(16);

на Java. Где секрет - это строка (пароль), а saltValueBytes - это массив байтов.

Я пробовал что-то, но, кажется, не могу обернуть голову вокруг него.

Ответы [ 4 ]

5 голосов
/ 24 сентября 2013

Я знаю, что это поздно для игры, но Java 6 и выше имеет встроенную реализацию PBKDF2.

int dkLen = 64;
int rounds = 1000;
PBEKeySpec keySpec = new PBEKeySpec("Some password".toCharArray(), "SomeSalt".getBytes(), rounds, dkLen * 8);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] out = factory.generateSecret(keySpec).getEncoded();

Список Java 6 Security Enhancements претендует на сопоставимость с PKCS # 5, и благодаря моему (беглому) тестированию он, похоже, дает правильные ключи PBKDF2.

4 голосов
/ 01 сентября 2009

Этот работает для меня. Я до сих пор не верю, что стандартная реализация RFK2898-совместимого PBKDF2 отсутствует в JRE. Я думаю, что я должен искать в неправильных местах. Путаница с именами (RFC2898 PKCS5 PBKDF2) не помогает.

// PBKDF2.java
// ------------------------------------------------------------------
//
// RFC2898 PBKDF2 in Java.  The RFC2898 defines a standard algorithm for
// deriving key bytes from a text password.  This is also called 
// "PBKDF2", for Password-based key derivation function #2.
//
// There's no RFC2898-compliant PBKDF2 function in the JRE, as far as I
// know, but it is available in many J2EE runtimes, including those from
// JBoss, IBM, and Oracle.
//
// It's fairly simple to implement, so here it is. 
// 
// Author: Admin
// built on host: DINOCH-2
// Created Sun Aug 09 01:06:57 2009
//
// last saved: 
// Time-stamp: <2009-August-09 11:11:47>
// ------------------------------------------------------------------
//
// code from Matthias Gartner
//
// ------------------------------------------------------------------

package cheeso.examples;


import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;


public class PBKDF2
{
    public static byte[] deriveKey( byte[] password, 
                                    byte[] salt, 
                                    int iterationCount, 
                                    int dkLen )
        throws java.security.NoSuchAlgorithmException, 
               java.security.InvalidKeyException
    {
        SecretKeySpec keyspec = new SecretKeySpec( password, "HmacSHA1" );
        Mac prf = Mac.getInstance( "HmacSHA1" );
        prf.init( keyspec );

        // Note: hLen, dkLen, l, r, T, F, etc. are horrible names for
        //       variables and functions in this day and age, but they
        //       reflect the terse symbols used in RFC 2898 to describe
        //       the PBKDF2 algorithm, which improves validation of the
        //       code vs. the RFC.
        //
        // hLen denotes the length in octets of the pseudorandom function output
        // dklen the length in octets (bytes) of the derived key. 

        int hLen = prf.getMacLength();   // 20 for SHA1
        int l = Math.ceil( dkLen/hLen ); //  1 for 128bit (16-byte) keys
        int r = dkLen - (l-1)*hLen;      // 16 for 128bit (16-byte) keys
        byte T[] = new byte[l * hLen];
        int ti_offset = 0;
        for (int i = 1; i <= l; i++) {
            F( T, ti_offset, prf, salt, iterationCount, i );
            ti_offset += hLen;
        }

        if (r < hLen) {
            // Incomplete last block
            byte DK[] = new byte[dkLen];
            System.arraycopy(T, 0, DK, 0, dkLen);
            return DK;
        }
        return T;
    } 


    private static void F( byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex ) {
        final int hLen = prf.getMacLength();
        byte U_r[] = new byte[ hLen ];
        // U0 = S || INT (i);
        byte U_i[] = new byte[S.length + 4];
        System.arraycopy( S, 0, U_i, 0, S.length );
        INT( U_i, S.length, blockIndex );
        for( int i = 0; i < c; i++ ) {
            U_i = prf.doFinal( U_i );
            xor( U_r, U_i );
        }

        System.arraycopy( U_r, 0, dest, offset, hLen );
    }

    private static void xor( byte[] dest, byte[] src ) {
        for( int i = 0; i < dest.length; i++ ) {
            dest[i] ^= src[i];
        }
    }

    private static void INT( byte[] dest, int offset, int i ) {
        dest[offset + 0] = (byte) (i / (256 * 256 * 256));
        dest[offset + 1] = (byte) (i / (256 * 256));
        dest[offset + 2] = (byte) (i / (256));
        dest[offset + 3] = (byte) (i);
    } 

    // ctor
    private PBKDF2 () {}
}
4 голосов
/ 18 июня 2009

Я нашел эту реализацию с помощью поиска Google, но я никогда не использовал ее.

Бесплатная реализация Java RFC 2898 / PKCS # 5 PBKDF2

Там, кажется, не маленький и свободно доступная реализация Java RFC 2898 / PKCS # 5 доступно. Маленький как в только несколько исходных файлов, с тривиальным компилировать и без зависимостей, бесплатно как в LGPL.

Учитывая наличие HMacSHA1 в стандартная криптография SUN JCE провайдер, такая реализация довольно просто и может быть получено из описание RFC довольно буквально. Мой код является реализацией чистой комнаты только с RFC в качестве основы.

1 голос
/ 29 июня 2012

Немного улучшен код Cheeso для работы с HMacSHA256 или HMacSHA512, добавив перегруженный DeriveKey () С этим изменением код был запущен с тестовыми векторами PKDF2-HMAC-SHA512 из
PHP Crypt lib , что привело к 6 сбоям из 100 тестовых случаев.

// PBKDF2.java
// ------------------------------------------------------------------
//
// RFC2898 PBKDF2 in Java.  The RFC2898 defines a standard algorithm for
// deriving key bytes from a text password.  This is also called 
// "PBKDF2", for Password-based key derivation function #2.
//
// There's no RFC2898-compliant PBKDF2 function in the JRE, as far as I
// know, but it is available in many J2EE runtimes, including those from
// JBoss, IBM, and Oracle.
//
// It's fairly simple to implement, so here it is. 
// 
// Author: Admin
// built on host: DINOCH-2
// Created Sun Aug 09 01:06:57 2009
//
// last saved: 
// Time-stamp: <2009-August-09 11:11:47>
// ------------------------------------------------------------------
//
// code from Matthias Gartner
//
// ------------------------------------------------------------------

package cheeso.examples;


import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;


public class PBKDF2
{
    public static byte[] deriveKey(byte[] password,
                                   byte[] salt,
                                   int iterationCount,
                                   int dkLen)
            throws NoSuchAlgorithmException,
            InvalidKeyException
    {
        return deriveKey("HmacSHA1", password, salt, iterationCount, dkLen);
    }

    public static byte[] deriveKey(String hmacAlgo,
                                   byte[] password,
                                   byte[] salt,
                                   int iterationCount,
                                   int dkLen)
            throws NoSuchAlgorithmException,
            InvalidKeyException
    {
        SecretKeySpec keyspec = new SecretKeySpec(password, hmacAlgo);
        Mac prf = Mac.getInstance(hmacAlgo);
        prf.init( keyspec );

        // Note: hLen, dkLen, l, r, T, F, etc. are horrible names for
        //       variables and functions in this day and age, but they
        //       reflect the terse symbols used in RFC 2898 to describe
        //       the PBKDF2 algorithm, which improves validation of the
        //       code vs. the RFC.
        //
        // dklen is expressed in bytes. (16 for a 128-bit key, 32 for 256)

        int hLen = prf.getMacLength();   // 20 for SHA1
        int l = Math.max( dkLen, hLen); //  1 for 128bit (16-byte) keys
        int r = dkLen - (l-1)*hLen;      // 16 for 128bit (16-byte) keys
        byte T[] = new byte[l * hLen];
        int ti_offset = 0;
        for (int i = 1; i <= l; i++) {
            F( T, ti_offset, prf, salt, iterationCount, i );
            ti_offset += hLen;
        }

        if (r < hLen) {
            // Incomplete last block
            byte DK[] = new byte[dkLen];
            System.arraycopy(T, 0, DK, 0, dkLen);
            return DK;
        }
        return T;
    } 


    private static void F( byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex ) {
        final int hLen = prf.getMacLength();
        byte U_r[] = new byte[ hLen ];
        // U0 = S || INT (i);
        byte U_i[] = new byte[S.length + 4];
        System.arraycopy( S, 0, U_i, 0, S.length );
        INT( U_i, S.length, blockIndex );
        for( int i = 0; i < c; i++ ) {
            U_i = prf.doFinal( U_i );
            xor( U_r, U_i );
        }

        System.arraycopy( U_r, 0, dest, offset, hLen );
    }

    private static void xor( byte[] dest, byte[] src ) {
        for( int i = 0; i < dest.length; i++ ) {
            dest[i] ^= src[i];
        }
    }

    private static void INT( byte[] dest, int offset, int i ) {
        dest[offset + 0] = (byte) (i / (256 * 256 * 256));
        dest[offset + 1] = (byte) (i / (256 * 256));
        dest[offset + 2] = (byte) (i / (256));
        dest[offset + 3] = (byte) (i);
    } 

    // ctor
    private PBKDF2 () {}
}
...