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;
  8
  9import static java.lang.Integer.MAX_VALUE;
 10import static java.lang.System.arraycopy;
 11
 12/**
 13 * An implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt</a>
 14 * key derivation function. This class will attempt to load a native library
 15 * containing the optimized C implementation from
 16 * <a href="http://www.tarsnap.com/scrypt.html">http://www.tarsnap.com/scrypt.html<a> and
 17 * fall back to the pure Java version if that fails.
 18 *
 19 * @author  Will Glozer
 20 */
 21public class SCrypt {
 22
 23    /**
 24     * Implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt KDF</a>.
 25     * Calls the native implementation {@link #scryptN} when the native library was successfully
 26     * loaded, otherwise calls {@link #scryptJ}.
 27     *
 28     * @param passwd    Password.
 29     * @param salt      Salt.
 30     * @param N         CPU cost parameter.
 31     * @param r         Memory cost parameter.
 32     * @param p         Parallelization parameter.
 33     * @param dkLen     Intended length of the derived key.
 34     *
 35     * @return The derived key.
 36     *
 37     * @throws GeneralSecurityException when HMAC_SHA256 is not available.
 38     */
 39    public static byte[] scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) throws GeneralSecurityException {
 40        return scryptJ(passwd, salt, N, r, p, dkLen);
 41    }
 42
 43
 44    /**
 45     * Pure Java implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt KDF</a>.
 46     *
 47     * @param passwd    Password.
 48     * @param salt      Salt.
 49     * @param N         CPU cost parameter.
 50     * @param r         Memory cost parameter.
 51     * @param p         Parallelization parameter.
 52     * @param dkLen     Intended length of the derived key.
 53     *
 54     * @return The derived key.
 55     *
 56     * @throws GeneralSecurityException when HMAC_SHA256 is not available.
 57     */
 58    public static byte[] scryptJ(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) throws GeneralSecurityException {
 59        if (N < 2 || (N & (N - 1)) != 0) throw new IllegalArgumentException("N must be a power of 2 greater than 1");
 60
 61        if (N > MAX_VALUE / 128 / r) throw new IllegalArgumentException("Parameter N is too large");
 62        if (r > MAX_VALUE / 128 / p) throw new IllegalArgumentException("Parameter r is too large");
 63
 64        Mac mac = Mac.getInstance("HmacSHA256");
 65        mac.init(new SecretKeySpec(passwd, "HmacSHA256"));
 66
 67        byte[] DK = new byte[dkLen];
 68
 69        byte[] B  = new byte[128 * r * p];
 70        byte[] XY = new byte[256 * r];
 71        byte[] V  = new byte[128 * r * N];
 72        int i;
 73
 74        PBKDF.pbkdf2(mac, salt, 1, B, p * 128 * r);
 75
 76        for (i = 0; i < p; i++) {
 77            smix(B, i * 128 * r, r, N, V, XY);
 78        }
 79
 80        PBKDF.pbkdf2(mac, B, 1, DK, dkLen);
 81
 82        return DK;
 83    }
 84
 85    public static void smix(byte[] B, int Bi, int r, int N, byte[] V, byte[] XY) {
 86        int Xi = 0;
 87        int Yi = 128 * r;
 88        int i;
 89
 90        arraycopy(B, Bi, XY, Xi, 128 * r);
 91
 92        for (i = 0; i < N; i++) {
 93            arraycopy(XY, Xi, V, i * (128 * r), 128 * r);
 94            blockmix_salsa8(XY, Xi, Yi, r);
 95        }
 96
 97        for (i = 0; i < N; i++) {
 98            int j = integerify(XY, Xi, r) & (N - 1);
 99            blockxor(V, j * (128 * r), XY, Xi, 128 * r);
100            blockmix_salsa8(XY, Xi, Yi, r);
101        }
102
103        arraycopy(XY, Xi, B, Bi, 128 * r);
104    }
105
106    public static void blockmix_salsa8(byte[] BY, int Bi, int Yi, int r) {
107        byte[] X = new byte[64];
108        int i;
109
110        arraycopy(BY, Bi + (2 * r - 1) * 64, X, 0, 64);
111
112        for (i = 0; i < 2 * r; i++) {
113            blockxor(BY, i * 64, X, 0, 64);
114            salsa20_8(X);
115            arraycopy(X, 0, BY, Yi + (i * 64), 64);
116        }
117
118        for (i = 0; i < r; i++) {
119            arraycopy(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64);
120        }
121
122        for (i = 0; i < r; i++) {
123            arraycopy(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64);
124        }
125    }
126
127    public static int R(int a, int b) {
128        return (a << b) | (a >>> (32 - b));
129    }
130
131    public static void salsa20_8(byte[] B) {
132        int[] B32 = new int[16];
133        int[] x   = new int[16];
134        int i;
135
136        for (i = 0; i < 16; i++) {
137            B32[i]  = (B[i * 4 + 0] & 0xff) << 0;
138            B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
139            B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
140            B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
141        }
142
143        arraycopy(B32, 0, x, 0, 16);
144
145        for (i = 8; i > 0; i -= 2) {
146            x[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);
147            x[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);
148            x[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);
149            x[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);
150            x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);
151            x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);
152            x[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);
153            x[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);
154            x[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);
155            x[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);
156            x[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);
157            x[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);
158            x[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);
159            x[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);
160            x[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);
161            x[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);
162        }
163
164        for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i];
165
166        for (i = 0; i < 16; i++) {
167            B[i * 4 + 0] = (byte) (B32[i] >> 0  & 0xff);
168            B[i * 4 + 1] = (byte) (B32[i] >> 8  & 0xff);
169            B[i * 4 + 2] = (byte) (B32[i] >> 16 & 0xff);
170            B[i * 4 + 3] = (byte) (B32[i] >> 24 & 0xff);
171        }
172    }
173
174    public static void blockxor(byte[] S, int Si, byte[] D, int Di, int len) {
175        for (int i = 0; i < len; i++) {
176            D[Di + i] ^= S[Si + i];
177        }
178    }
179
180    public static int integerify(byte[] B, int Bi, int r) {
181        int n;
182
183        Bi += (2 * r - 1) * 64;
184
185        n  = (B[Bi + 0] & 0xff) << 0;
186        n |= (B[Bi + 1] & 0xff) << 8;
187        n |= (B[Bi + 2] & 0xff) << 16;
188        n |= (B[Bi + 3] & 0xff) << 24;
189
190        return n;
191    }
192}