]> WPIA git - gigi.git/blob - lib/scrypt/com/lambdaworks/crypto/PBKDF.java
Merge "upd: remove 'browser install'"
[gigi.git] / lib / scrypt / com / lambdaworks / crypto / PBKDF.java
1 // Copyright (C) 2011 - Will Glozer.  All rights reserved.
2
3 package com.lambdaworks.crypto;
4
5 import javax.crypto.Mac;
6 import javax.crypto.spec.SecretKeySpec;
7 import java.security.GeneralSecurityException;
8 import static java.lang.System.arraycopy;
9
10 /**
11  * An implementation of the Password-Based Key Derivation Function as specified
12  * in RFC 2898.
13  *
14  * @author  Will Glozer
15  */
16 public class PBKDF {
17     /**
18      * Implementation of PBKDF2 (RFC2898).
19      *
20      * @param   alg     HMAC algorithm to use.
21      * @param   P       Password.
22      * @param   S       Salt.
23      * @param   c       Iteration count.
24      * @param   dkLen   Intended length, in octets, of the derived key.
25      *
26      * @return  The derived key.
27      *
28      * @throws  GeneralSecurityException
29      */
30     public static byte[] pbkdf2(String alg, byte[] P, byte[] S, int c, int dkLen) throws GeneralSecurityException {
31         Mac mac = Mac.getInstance(alg);
32         mac.init(new SecretKeySpec(P, alg));
33         byte[] DK = new byte[dkLen];
34         pbkdf2(mac, S, c, DK, dkLen);
35         return DK;
36     }
37
38     /**
39      * Implementation of PBKDF2 (RFC2898).
40      *
41      * @param   mac     Pre-initialized {@link Mac} instance to use.
42      * @param   S       Salt.
43      * @param   c       Iteration count.
44      * @param   DK      Byte array that derived key will be placed in.
45      * @param   dkLen   Intended length, in octets, of the derived key.
46      *
47      * @throws  GeneralSecurityException
48      */
49     public static void pbkdf2(Mac mac, byte[] S, int c, byte[] DK, int dkLen) throws GeneralSecurityException {
50         int hLen = mac.getMacLength();
51
52         if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
53             throw new GeneralSecurityException("Requested key length too long");
54         }
55
56         byte[] U      = new byte[hLen];
57         byte[] T      = new byte[hLen];
58         byte[] block1 = new byte[S.length + 4];
59
60         int l = (int) Math.ceil((double) dkLen / hLen);
61         int r = dkLen - (l - 1) * hLen;
62
63         arraycopy(S, 0, block1, 0, S.length);
64
65         for (int i = 1; i <= l; i++) {
66             block1[S.length + 0] = (byte) (i >> 24 & 0xff);
67             block1[S.length + 1] = (byte) (i >> 16 & 0xff);
68             block1[S.length + 2] = (byte) (i >> 8  & 0xff);
69             block1[S.length + 3] = (byte) (i >> 0  & 0xff);
70
71             mac.update(block1);
72             mac.doFinal(U, 0);
73             arraycopy(U, 0, T, 0, hLen);
74
75             for (int j = 1; j < c; j++) {
76                 mac.update(U);
77                 mac.doFinal(U, 0);
78
79                 for (int k = 0; k < hLen; k++) {
80                     T[k] ^= U[k];
81                 }
82             }
83
84             arraycopy(T, 0, DK, (i - 1) * hLen, (i == l ? r : hLen));
85         }
86     }
87 }