Package org.kocakosm.pitaya.security

Source Code of org.kocakosm.pitaya.security.SCrypt

/*----------------------------------------------------------------------------*
* This file is part of Pitaya.                                               *
* Copyright (C) 2012-2014 Osman KOCAK <kocakosm@gmail.com>                   *
*                                                                            *
* This program is free software: you can redistribute it and/or modify it    *
* under the terms of the GNU Lesser General Public License as published by   *
* the Free Software Foundation, either version 3 of the License, or (at your *
* option) any later version.                                                 *
* This program is distributed in the hope that it will be useful, but        *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public     *
* License for more details.                                                  *
* You should have received a copy of the GNU Lesser General Public License   *
* along with this program. If not, see <http://www.gnu.org/licenses/>.       *
*----------------------------------------------------------------------------*/

package org.kocakosm.pitaya.security;

import org.kocakosm.pitaya.util.Bits;
import org.kocakosm.pitaya.util.ByteBuffer;
import org.kocakosm.pitaya.util.LittleEndian;
import org.kocakosm.pitaya.util.Parameters;
import org.kocakosm.pitaya.util.XObjects;

import java.util.Arrays;

/**
* SCrypt Key Derivation Function as specified by the Internet Engineering Task
* Force (http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01). Instances
* of this class are immutable.
*
* @author Osman KOCAK
*/
final class SCrypt implements KDF
{
  private final int r;
  private final int n;
  private final int p;
  private final int dkLen;

  /**
   * Creates a new {@code SCrypt} instance.
   *
   * @param r the block size parameter.
   * @param n the CPU/Memory cost parameter.
   * @param p the parallelization parameter.
   * @param dkLen the desired length for derived keys, in bytes.
   *
   * @throws IllegalArgumentException if {@code r, dkLen} or {@code p} is
   *  negative, or if {@code n} is not greater than 1 or if it is not
   *  a power of 2 or if it is not less than 2 ^ (128 * r / 8), or if
   *  {@code p} is greater than ((2 ^ 32 - 1) * 32) / (128 * r).
   */
  SCrypt(int r, int n, int p, int dkLen)
  {
    Parameters.checkCondition(r > 0 && p > 0 && dkLen > 0);
    Parameters.checkCondition(n > 1 && (n & (n - 1)) == 0);
    Parameters.checkCondition(r == 1 ? n < (1 << 16) : true);
    Parameters.checkCondition(p * r < (1 << 30));
    this.r = r;
    this.n = n;
    this.p = p;
    this.dkLen = dkLen;
  }

  @Override
  public byte[] deriveKey(byte[] secret, byte[] salt)
  {
    KDF pbkdf2 = KDFs.pbkdf2(Algorithm.HMAC_SHA256, 1, p * 128 * r);
    byte[] b = pbkdf2.deriveKey(secret, salt);
    ByteBuffer buffer = new ByteBuffer(p * 128 * r);
    for (int i = 0; i < p; i++) {
      buffer.append(roMix(slice(b, i * 128 * r, 128 * r)));
    }
    pbkdf2 = KDFs.pbkdf2(Algorithm.HMAC_SHA256, 1, dkLen);
    return pbkdf2.deriveKey(secret, buffer.toByteArray());
  }

  @Override
  public String toString()
  {
    return XObjects.toStringBuilder("SCrypt").append("r", r)
      .append("n", n).append("p", p).append("dkLen", dkLen)
      .toString();
  }

  private byte[] roMix(byte[] x)
  {
    int len = x.length;
    ByteBuffer v = new ByteBuffer(n * len);
    for (int i = 0; i < n; i++) {
      v.append(x);
      x = blockMix(x);
    }
    int offset = (2 * r - 1) * 64;
    for (int i = 0; i < n; i++) {
      int j = LittleEndian.decodeInt(x, offset) & (n - 1);
      x = blockMix(xor(x, v.toByteArray(j * len, len)));
    }
    return x;
  }

  private byte[] blockMix(byte[] in)
  {
    byte[] x = slice(in, (2 * r - 1) * 64, 64);
    ByteBuffer buffer = new ByteBuffer(128 * r);
    for (int i = 0; i < 2 * r; i++) {
      x = salsa20(xor(x, slice(in, i * 64, 64)), 8);
      buffer.append(x);
    }
    byte[] y = buffer.toByteArray();
    byte[] b = new byte[in.length];
    for (int i = 0; i < r; i++) {
      System.arraycopy(y, (i * 2) * 64, b, i * 64, 64);
    }
    for (int i = 0; i < r; i++) {
      System.arraycopy(y, (i * 2 + 1) * 64, b, (i + r) * 64, 64);
    }
    return b;
  }

  private byte[] salsa20(byte[] buf, int rounds)
  {
    int[] in = new int[16];
    for (int i = 0; i < 16; i++) {
      in[i] = LittleEndian.decodeInt(buf, i * 4);
    }
    int[] x = Arrays.copyOf(in, in.length);
    for (int i = rounds; i > 0; i -= 2) {
      x[ 4] ^= Bits.rotateLeft(x[ 0] + x[12], 7);
      x[ 8] ^= Bits.rotateLeft(x[ 4] + x[ 0], 9);
      x[12] ^= Bits.rotateLeft(x[ 8] + x[ 4], 13);
      x[ 0] ^= Bits.rotateLeft(x[12] + x[ 8], 18);
      x[ 9] ^= Bits.rotateLeft(x[ 5] + x[ 1], 7);
      x[13] ^= Bits.rotateLeft(x[ 9] + x[ 5], 9);
      x[ 1] ^= Bits.rotateLeft(x[13] + x[ 9], 13);
      x[ 5] ^= Bits.rotateLeft(x[ 1] + x[13], 18);
      x[14] ^= Bits.rotateLeft(x[10] + x[ 6], 7);
      x[ 2] ^= Bits.rotateLeft(x[14] + x[10], 9);
      x[ 6] ^= Bits.rotateLeft(x[ 2] + x[14], 13);
      x[10] ^= Bits.rotateLeft(x[ 6] + x[ 2], 18);
      x[ 3] ^= Bits.rotateLeft(x[15] + x[11], 7);
      x[ 7] ^= Bits.rotateLeft(x[ 3] + x[15], 9);
      x[11] ^= Bits.rotateLeft(x[ 7] + x[ 3], 13);
      x[15] ^= Bits.rotateLeft(x[11] + x[ 7], 18);
      x[ 1] ^= Bits.rotateLeft(x[ 0] + x[ 3], 7);
      x[ 2] ^= Bits.rotateLeft(x[ 1] + x[ 0], 9);
      x[ 3] ^= Bits.rotateLeft(x[ 2] + x[ 1], 13);
      x[ 0] ^= Bits.rotateLeft(x[ 3] + x[ 2], 18);
      x[ 6] ^= Bits.rotateLeft(x[ 5] + x[ 4], 7);
      x[ 7] ^= Bits.rotateLeft(x[ 6] + x[ 5], 9);
      x[ 4] ^= Bits.rotateLeft(x[ 7] + x[ 6], 13);
      x[ 5] ^= Bits.rotateLeft(x[ 4] + x[ 7], 18);
      x[11] ^= Bits.rotateLeft(x[10] + x[ 9], 7);
      x[ 8] ^= Bits.rotateLeft(x[11] + x[10], 9);
      x[ 9] ^= Bits.rotateLeft(x[ 8] + x[11], 13);
      x[10] ^= Bits.rotateLeft(x[ 9] + x[ 8], 18);
      x[12] ^= Bits.rotateLeft(x[15] + x[14], 7);
      x[13] ^= Bits.rotateLeft(x[12] + x[15], 9);
      x[14] ^= Bits.rotateLeft(x[13] + x[12], 13);
      x[15] ^= Bits.rotateLeft(x[14] + x[13], 18);
    }
    byte[] out = new byte[64];
    for (int i = 0; i < 16; i++) {
      LittleEndian.encode(x[i] + in[i], out, i * 4);
    }
    return out;
  }

  private byte[] slice(byte[] src, int off, int len)
  {
    byte[] slice = new byte[len];
    System.arraycopy(src, off, slice, 0, len);
    return slice;
  }

  private byte[] xor(byte[] x, byte[] y)
  {
    int len = x.length;
    byte[] z = new byte[len];
    for (int k = 0; k < len; k++) {
      z[k] = (byte) (x[k] ^ y[k]);
    }
    return z;
  }
}
TOP

Related Classes of org.kocakosm.pitaya.security.SCrypt

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.