All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lambdaworks.crypto.SCryptUtil Maven / Gradle / Ivy

// Copyright (C) 2011 - Will Glozer.  All rights reserved.

package com.lambdaworks.crypto;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;

import static com.lambdaworks.crypto.Base64.*;

/**
 * Simple {@link SCrypt} interface for hashing passwords using the
 * scrypt key derivation fuction
 * and comparing a plain text password to a hashed one. The hashed output is an
 * extended implementation of the Modular Crypt Format that also includes the scrypt
 * algorithm parameters.
 *
 * Format: $s0$PARAMS$SALT$KEY.
 *
 * 
*
PARAMS
32-bit hex integer containing log2(N) (16 bits), r (8 bits), and p (8 bits)
*
SALT
base64-encoded salt
*
KEY
base64-encoded derived key
*
* * s0 identifies version 0 of the scrypt format, using a 128-bit salt and 256-bit derived key. * * @author Will Glozer */ public class SCryptUtil { /** * Hash the supplied plaintext password and generate output in the format described * in {@link SCryptUtil}. * * @param passwd Password. * @param N CPU cost parameter. * @param r Memory cost parameter. * @param p Parallelization parameter. * * @return The hashed password. */ public static String scrypt(String passwd, int N, int r, int p) { try { byte[] salt = new byte[16]; SecureRandom.getInstance("SHA1PRNG").nextBytes(salt); byte[] derived = SCrypt.scrypt(passwd.getBytes("UTF-8"), salt, N, r, p, 32); String params = Integer.toString(log2(N) << 16 | r << 8 | p, 16); StringBuilder sb = new StringBuilder((salt.length + derived.length) * 2); sb.append("$s0$").append(params).append('$'); sb.append(encodeToChar(salt, false)).append('$'); sb.append(encodeToChar(derived, false)); return sb.toString(); } catch (UnsupportedEncodingException e) { throw new IllegalStateException("JVM doesn't support UTF-8?"); } catch (GeneralSecurityException e) { throw new IllegalStateException("JVM doesn't support SHA1PRNG or HMAC_SHA256?"); } } /** * Compare the supplied plaintext password to a hashed password. * * @param passwd Plaintext password. * @param hashed scrypt hashed password. * * @return true if passwd matches hashed value. */ public static boolean check(String passwd, String hashed) { try { String[] parts = hashed.split("\\$"); if (parts.length != 5 || !parts[1].equals("s0")) { throw new IllegalArgumentException("Invalid hashed value"); } int params = Integer.parseInt(parts[2], 16); byte[] salt = decodeFast(parts[3].toCharArray()); byte[] derived0 = decodeFast(parts[4].toCharArray()); int N = (int) Math.pow(2, params >> 16 & 0xff); int r = params >> 8 & 0x0f; int p = params & 0x0f; byte[] derived1 = SCrypt.scrypt(passwd.getBytes("UTF-8"), salt, N, r, p, 32); if (derived0.length != derived1.length) return false; int result = 0; for (int i = 0; i < derived0.length; i++) { result |= derived0[i] ^ derived1[i]; } return result == 0; } catch (UnsupportedEncodingException e) { throw new IllegalStateException("JVM doesn't support UTF-8?"); } catch (GeneralSecurityException e) { throw new IllegalStateException("JVM doesn't support SHA1PRNG or HMAC_SHA256?"); } } private static int log2(int n) { int log = 0; if ((n & 0xffff0000 ) != 0) { n >>>= 16; log = 16; } if (n >= 256) { n >>>= 8; log += 8; } if (n >= 16 ) { n >>>= 4; log += 4; } if (n >= 4 ) { n >>>= 2; log += 2; } return log + (n >>> 1); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy