誰かが同等のことをしようとしたかどうか疑問に思っていました
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(secret, saltValueBytes);
byte[] secretKey = key.GetBytes(16);
ジャワで。secret は文字列 (パスワード) であり、saltValueBytes はバイト配列のソルトです。
私はいろいろ試しましたが、頭を包むことができないようです。
誰かが同等のことをしようとしたかどうか疑問に思っていました
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(secret, saltValueBytes);
byte[] secretKey = key.GetBytes(16);
ジャワで。secret は文字列 (パスワード) であり、saltValueBytes はバイト配列のソルトです。
私はいろいろ試しましたが、頭を包むことができないようです。
この実装は Google 検索で見つけましたが、使用したことはありません。
RFC 2898 / PKCS#5 PBKDF2 の無料の Java 実装
利用可能な RFC 2898 / PKCS#5 の小規模で自由に利用できる Java 実装はないようです。LGPL のように無料で、簡単なコンパイルと依存関係がなく、わずか数個のソース ファイルのように小さくなります。
標準の SUN JCE 暗号化プロバイダーで HMacSHA1 が使用できることを考えると、このような実装は非常に単純であり、RFC の説明から文字通り派生させることができます。私のコードは、RFC のみをベースとしたクリーンルーム実装です。
これが遅れていることは承知していますが、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 キーを生成するように見えます。
これは私のために働きます。私は、RFC2898 準拠の 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 () {}
}
HMacSHA256 または HMacSHA512 を操作するための Cheeso のコードを、オーバーロードされた serveKey() を追加することでわずかに改善しました。この変更により、
PHP Crypt libの PKDF2-HMAC-SHA512 テスト ベクターを使用してコードが実行され、100 件のテスト ケースのうち 6 件が失敗しました。
// 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 () {}
}