Permalink
Browse files

initial import of pure java scrypt

  • Loading branch information...
wg committed Jan 20, 2011
0 parents commit 3b98dcccbf3ba7786d21b900a6c02059c5962466
@@ -0,0 +1 @@
+target/
10 LICENSE
@@ -0,0 +1,10 @@
+Copyright (c) 2011, Will Glozer
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the name of Will Glozer nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9 README
@@ -0,0 +1,9 @@
+Java Implementation of scrypt
+
+ An implementation of the scrypt KDF in Java. This code is based in
+ large part on Colin Percival's reference implementation contained in
+ scrypt-1.1.6/lib/crypto/crypto_scrypt-ref.c, but any errors in this
+ port are solely the fault of its author, Will Glozer.
+
+ http://www.tarsnap.com/scrypt/scrypt-1.1.6.tgz
+ http://www.tarsnap.com/scrypt/scrypt.pdf
50 pom.xml
@@ -0,0 +1,50 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.lambdaworks</groupId>
+ <artifactId>scrypt</artifactId>
+ <version>1.0</version>
+
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <groupId>org.apache.maven.plugins</groupId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <configuration>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <useFile>false</useFile>
+ <argLine>-Xmx2G -Xms512M</argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
@@ -0,0 +1,86 @@
+// Copyright (C) 2011 - Will Glozer. All rights reserved.
+
+package com.lambdaworks.crypto;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.GeneralSecurityException;
+import static java.lang.System.arraycopy;
+
+public class PBKDF {
+ /**
+ * Implementation of PBKDF2 (RFC2898).
+ *
+ * @param alg HMAC algorithm to use.
+ * @param P Password.
+ * @param S Salt.
+ * @param c Iteration count.
+ * @param dkLen Intended length, in octets, of the derived key.
+ *
+ * @return The derived key.
+ *
+ * @throws GeneralSecurityException
+ */
+ public static byte[] pbkdf2(String alg, byte[] P, byte[] S, int c, int dkLen) throws GeneralSecurityException {
+ Mac mac = Mac.getInstance(alg);
+ mac.init(new SecretKeySpec(P, alg));
+ byte[] DK = new byte[dkLen];
+ pbkdf2(mac, S, c, DK, dkLen);
+ return DK;
+ }
+
+ /**
+ * Implementation of PBKDF2 (RFC2898).
+ *
+ * @param mac Pre-initialized {@link Mac} instance to use.
+ * @param S Salt.
+ * @param c Iteration count.
+ * @param DK Byte array that derived key will be placed in.
+ * @param dkLen Intended length, in octets, of the derived key.
+ *
+ * @return The derived key.
+ *
+ * @throws GeneralSecurityException
+ */
+ public static void pbkdf2(Mac mac, byte[] S, int c, byte[] DK, int dkLen) throws GeneralSecurityException {
+ int hLen = mac.getMacLength();
+
+ if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
+ throw new GeneralSecurityException("Requested key length too long");
+ }
+
+ byte[] U = new byte[hLen];
+ byte[] T = new byte[hLen];
+ byte[] block1 = new byte[S.length + 4];
+
+ int l = (int) Math.ceil((double) dkLen / hLen);
+ int r = dkLen - (l - 1) * hLen;
+
+ arraycopy(S, 0, block1, 0, S.length);
+
+ for (int i = 1; i <= l; i++) {
+ block1[S.length + 0] = (byte) (i >> 24 & 0xff);
+ block1[S.length + 1] = (byte) (i >> 16 & 0xff);
+ block1[S.length + 2] = (byte) (i >> 8 & 0xff);
+ block1[S.length + 3] = (byte) (i >> 0 & 0xff);
+
+ mac.update(block1);
+ mac.doFinal(U, 0);
+ arraycopy(U, 0, T, 0, hLen);
+
+ for (int j = 1; j < c; j++) {
+ mac.update(U);
+ mac.doFinal(U, 0);
+
+ for (int k = 0; k < hLen; k++) {
+ T[k] ^= U[k];
+ }
+ }
+
+ arraycopy(T, 0, DK, (i - 1) * hLen, (i == l ? r : hLen));
+ }
+ }
+}
+
+
+
@@ -0,0 +1,168 @@
+// Copyright (C) 2011 - Will Glozer. All rights reserved.
+
+package com.lambdaworks.crypto;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.GeneralSecurityException;
+
+import static java.lang.System.arraycopy;
+import static java.lang.Integer.MAX_VALUE;
+
+/**
+ * An interface to the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt</a>
+ * key derivation function.
+ *
+ * @author Will Glozer
+ * @version 1.0
+ */
+public class SCrypt {
+ /**
+ * Pure Java implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt KDF</a>.
+ *
+ * @param passwd Password.
+ * @param salt Salt.
+ * @param N CPU cost parameter.
+ * @param r Memory cost parameter.
+ * @param p Parallelization parameter.
+ * @param dkLen Intended length of the derived key.
+ *
+ * @return The derived key.
+ *
+ * @throws GeneralSecurityException when HMAC_SHA256 is not available.
+ */
+ public static byte[] scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) throws GeneralSecurityException {
+ if (N == 0 || (N & (N - 1)) != 0) throw new IllegalArgumentException("N must be > 0 and a power of 2");
+
+ if (N > MAX_VALUE / 128 / r) throw new IllegalArgumentException("Parameter N is too large");
+ if (r > MAX_VALUE / 128 / p) throw new IllegalArgumentException("Parameter r is too large");
+
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(new SecretKeySpec(passwd, "HmacSHA256"));
+
+ byte[] DK = new byte[dkLen];
+
+ byte[] B = new byte[128 * r * p];
+ byte[] XY = new byte[256 * r];
+ byte[] V = new byte[128 * r * N];
+ int i;
+
+ PBKDF.pbkdf2(mac, salt, 1, B, p * 128 * r);
+
+ for (i = 0; i < p; i++) {
+ smix(B, i * 128 * r, r, N, V, XY);
+ }
+
+ PBKDF.pbkdf2(mac, B, 1, DK, dkLen);
+
+ return DK;
+ }
+
+ public static void smix(byte[] B, int Bi, int r, int N, byte[] V, byte[] XY) {
+ int Xi = 0;
+ int Yi = 128 * r;
+ int i;
+
+ arraycopy(B, Bi, XY, Xi, 128 * r);
+
+ for (i = 0; i < N; i++) {
+ arraycopy(XY, Xi, V, i * (128 * r), 128 * r);
+ blockmix_salsa8(XY, Xi, Yi, r);
+ }
+
+ for (i = 0; i < N; i++) {
+ int j = integerify(XY, Xi, r) & (N - 1);
+ blockxor(V, j * (128 * r), XY, Xi, 128 * r);
+ blockmix_salsa8(XY, Xi, Yi, r);
+ }
+
+ arraycopy(XY, Xi, B, Bi, 128 * r);
+ }
+
+ public static void blockmix_salsa8(byte[] BY, int Bi, int Yi, int r) {
+ byte[] X = new byte[64];
+ int i;
+
+ System.arraycopy(BY, Bi + (2 * r - 1) * 64, X, 0, 64);
+
+ for (i = 0; i < 2 * r; i++) {
+ blockxor(BY, i * 64, X, 0, 64);
+ salsa20_8(X);
+ arraycopy(X, 0, BY, Yi + (i * 64), 64);
+ }
+
+ for (i = 0; i < r; i++) {
+ arraycopy(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64);
+ }
+
+ for (i = 0; i < r; i++) {
+ arraycopy(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64);
+ }
+ }
+
+ public static int R(int a, int b) {
+ return (a << b) | (a >>> (32 - b));
+ }
+
+ public static void salsa20_8(byte[] B) {
+ int[] B32 = new int[16];
+ int[] x = new int[16];
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ B32[i] = (B[i * 4 + 0] & 0xff) << 0;
+ B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
+ B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
+ B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
+ }
+
+ arraycopy(B32, 0, x, 0, 16);
+
+ for (i = 8; i > 0; i -= 2) {
+ x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
+ x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);
+ x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
+ x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);
+ x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
+ x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);
+ x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
+ x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);
+ x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
+ x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);
+ x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
+ x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);
+ x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
+ x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);
+ x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
+ x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
+ }
+
+ for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i];
+
+ for (i = 0; i < 16; i++) {
+ B[i * 4 + 0] = (byte) (B32[i] >> 0 & 0xff);
+ B[i * 4 + 1] = (byte) (B32[i] >> 8 & 0xff);
+ B[i * 4 + 2] = (byte) (B32[i] >> 16 & 0xff);
+ B[i * 4 + 3] = (byte) (B32[i] >> 24 & 0xff);
+ }
+ }
+
+ public static void blockxor(byte[] S, int Si, byte[] D, int Di, int len) {
+ for (int i = 0; i < len; i++) {
+ D[Di + i] ^= S[Si + i];
+ }
+ }
+
+ public static int integerify(byte[] B, int Bi, int r) {
+ int n;
+
+ Bi += (2 * r - 1) * 64;
+
+ n = (B[Bi + 0] & 0xff) << 0;
+ n |= (B[Bi + 1] & 0xff) << 8;
+ n |= (B[Bi + 2] & 0xff) << 16;
+ n |= (B[Bi + 3] & 0xff) << 24;
+
+ return n;
+ }
+}
@@ -0,0 +1,20 @@
+package com.lambdaworks.crypto;
+
+public class CryptoTestUtil {
+ public static byte[] decode(String str) {
+ byte[] bytes = new byte[str.length() / 2];
+ int index = 0;
+
+ for (int i = 0; i < str.length(); i += 2) {
+ int high = hexValue(str.charAt(i));
+ int low = hexValue(str.charAt(i + 1));
+ bytes[index++] = (byte) ((high << 4) + low);
+ }
+
+ return bytes;
+ }
+
+ public static int hexValue(char c) {
+ return c >= 'a' ? c - 87 : c - 48;
+ }
+}
Oops, something went wrong.

0 comments on commit 3b98dcc

Please sign in to comment.