Sorcerer's IsleCode cfPassphrase / files

     1// Copyright (C) 2011 - Will Glozer.  All rights reserved.
     2
     3package com.lambdaworks.crypto;
     4
     5import javax.crypto.Mac;
     6import javax.crypto.spec.SecretKeySpec;
     7import java.security.GeneralSecurityException;
     8import 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 */
    16public 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}