ASi

PBKDF2 HMAC-SHA512 by Java & Javascript on Web Browser

https://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors にある test vector と同じ結果が出せるか確認した。

Input:
  P = "password"
  S = "salt"
  c = 2
  dkLen = 64

Output:
  DK = e1 d9 c1 6a a6 81 70 8a 
       45 f5 c7 c4 e2 15 ce b6 
       6e 01 1a 2e 9f 00 40 71 
       3f 18 ae fd b8 66 d5 3c 
       f7 6c ab 28 68 a3 9b 9f 
       78 40 ed ce 4f ef 5a 82 
       be 67 33 5c 77 a6 06 8e 
       04 11 27 54 f2 7c cf 4e

iteration 2, salt="salt" では同一の結果となった。

OpenJDK12

public static byte[] PBKDF2_SHA512(char[] chars, byte[] salt, int itercnt) {
    String ALGORITHM = "PBKDF2WithHmacSHA512";
    int keyLengh = 512; // bits
    try {
        PBEKeySpec keySpec = new PBEKeySpec(chars, salt, itercnt, keyLengh);
        SecretKeyFactory skf = SecretKeyFactory.getInstance(ALGORITHM);
        SecretKey sk = skf.generateSecret(keySpec);
        return sk.getEncoded();
    } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
        throw new AssertionError(e);
    }
}

public void test() {
    String pass = "password";
    byte[] salt = "salt".getBytes();
    
    byte[] derivedPassBytes = Util.PBKDF2_SHA512(pass.toCharArray(), salt, 2);

    Log.d("derivedPassBytes:" + 
        DatatypeConverter.printHexBinary(derivedPassBytes).toLowerCase());
}

Chrome 77.0.3865.120, Safari 12.1.2 (14607.3.9),

<html>
<head>
<script>
  const calcPBKDF2 = (str, salt) => {
    return new Promise((resolve, reject) => {
      const byteList = new Uint8Array(Array.prototype.map.call(str, (c) => {
        return c.charCodeAt(0)
      }))
      window.crypto.subtle.importKey('raw', byteList, { name: 'PBKDF2', }, false, ['deriveBits'])
        .then((key) => {
          const opt = {
            name: 'PBKDF2',
            salt: salt,
            iterations: 2,
            hash: {name: 'SHA-512'},
          }
          return window.crypto.subtle.deriveBits(opt, key, 512).then((buf) => {
            resolve(buf)
            console.log('deriveBits ends')
          })
        })
    })
  }

  const buf2hex = (buf) => {
    return Array.prototype.map.call(new Uint8Array(buf), x => ('00' + x.toString(16)).slice(-2)).join('')
  }

  const main = async () => {
    const pass = 'password'
    const saltstr = 'salt';
    const salt = new Uint8Array(Array.prototype.map.call(saltstr, (c) => {
      return c.charCodeAt(0)
    }));

    const pbkdf2 = await calcPBKDF2(pass, salt)
    console.log(buf2hex(pbkdf2));
  }

  main()

</script>
</head>
</html>


https://qiita.com/px_dog/items/be9c05fb483066547247 の記事に感謝。