org.jclouds.compute.functions.Sha512Crypt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jclouds-compute Show documentation
Show all versions of jclouds-compute Show documentation
jclouds components to access compute providers
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
Sha512Crypt.java
Created: 18 December 2007
Last Changed By: $Author: broccol $
Version: $Revision: 7692 $
Last Mod Date: $Date: 2007-12-30 01:55:31 -0600 (Sun, 30 Dec 2007) $
Java Port By: James Ratcliff, [email protected]
This class implements the new generation, scalable, SHA512-based
Unix 'crypt' algorithm developed by a group of engineers from Red
Hat, Sun, IBM, and HP for common use in the Unix and Linux
/etc/shadow files.
The Linux glibc library (starting at version 2.7) includes support
for validating passwords hashed using this algorithm.
The algorithm itself was released into the Public Domain by Ulrich
Drepper . A discussion of the rationale and
development of this algorithm is at
http://people.redhat.com/drepper/sha-crypt.html
and the specification and a sample C language implementation is at
http://people.redhat.com/drepper/SHA-crypt.txt
This Java Port is
Copyright (c) 2008 The University of Texas at Austin.
All rights reserved.
Redistribution and use in source and binary form are permitted
provided that distributions retain this entire copyright notice
and comment. Neither the name of the University nor the names of
its contributors may be used to endorse or promote products
derived from this software without specific prior written
permission. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE.
*/
package org.jclouds.compute.functions;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.Throwables;
/**
* This class defines a method,
* {@link Sha512Crypt#Sha512_crypt(java.lang.String, java.lang.String, int)
* Sha512_crypt()}, which takes a password and a salt string and generates a
* Sha512 encrypted password entry.
*
* This class implements the new generation, scalable, SHA512-based Unix 'crypt'
* algorithm developed by a group of engineers from Red Hat, Sun, IBM, and HP
* for common use in the Unix and Linux /etc/shadow files.
*
* The Linux glibc library (starting at version 2.7) includes support for
* validating passwords hashed using this algorithm.
*
* The algorithm itself was released into the Public Domain by Ulrich Drepper
* <[email protected]>. A discussion of the rationale and development of
* this algorithm is at
*
* http://people.redhat.com/drepper/sha-crypt.html
*
* and the specification and a sample C language implementation is at
*
* http://people.redhat.com/drepper/SHA-crypt.txt
*/
public class Sha512Crypt {
public static com.google.common.base.Function function() {
return Function.INSTANCE;
}
private static enum Function implements com.google.common.base.Function {
INSTANCE;
@Override
public String apply(String input) {
return Sha512Crypt.makeShadowLine(input, null);
}
@Override
public String toString() {
return "sha512Crypt()";
}
}
private static final String sha512_salt_prefix = "$6$";
private static final String sha512_rounds_prefix = "rounds=";
private static final int SALT_LEN_MAX = 16;
private static final int ROUNDS_DEFAULT = 5000;
private static final int ROUNDS_MIN = 1000;
private static final int ROUNDS_MAX = 999999999;
private static final String SALTCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
/**
* This method actually generates an Sha512 crypted password hash from a
* plaintext password and a salt.
*
*
* The resulting string will be in the form
* '$6$<rounds=n>$<salt>$<hashed mess>
*
*
* @param password
* Plaintext password
*
* @param shadowPrefix
* An encoded salt/rounds which will be consulted to determine the
* salt and round count, if not null
*
* @return The Sha512 Unix Crypt hash text for the password
*/
static String makeShadowLine(String password, @Nullable String shadowPrefix) {
MessageDigest ctx = sha512();
MessageDigest alt_ctx = sha512();
byte[] alt_result;
byte[] temp_result;
byte[] p_bytes = null;
byte[] s_bytes = null;
int cnt;
int cnt2;
int rounds = ROUNDS_DEFAULT; // Default number of rounds.
StringBuilder buffer;
/* -- */
if (shadowPrefix != null) {
if (shadowPrefix.startsWith(sha512_salt_prefix)) {
shadowPrefix = shadowPrefix.substring(sha512_salt_prefix.length());
}
if (shadowPrefix.startsWith(sha512_rounds_prefix)) {
String num = shadowPrefix.substring(sha512_rounds_prefix.length(), shadowPrefix.indexOf('$'));
int srounds = Integer.valueOf(num).intValue();
shadowPrefix = shadowPrefix.substring(shadowPrefix.indexOf('$') + 1);
rounds = Math.max(ROUNDS_MIN, Math.min(srounds, ROUNDS_MAX));
}
if (shadowPrefix.length() > SALT_LEN_MAX) {
shadowPrefix = shadowPrefix.substring(0, SALT_LEN_MAX);
}
} else {
java.util.Random randgen = new java.util.Random();
StringBuilder saltBuf = new StringBuilder();
while (saltBuf.length() < 16) {
int index = (int) (randgen.nextFloat() * SALTCHARS.length());
saltBuf.append(SALTCHARS.substring(index, index + 1));
}
shadowPrefix = saltBuf.toString();
}
byte[] key = password.getBytes();
byte[] salts = shadowPrefix.getBytes();
ctx.reset();
ctx.update(key, 0, key.length);
ctx.update(salts, 0, salts.length);
alt_ctx.reset();
alt_ctx.update(key, 0, key.length);
alt_ctx.update(salts, 0, salts.length);
alt_ctx.update(key, 0, key.length);
alt_result = alt_ctx.digest();
for (cnt = key.length; cnt > 64; cnt -= 64) {
ctx.update(alt_result, 0, 64);
}
ctx.update(alt_result, 0, cnt);
for (cnt = key.length; cnt > 0; cnt >>= 1) {
if ((cnt & 1) != 0) {
ctx.update(alt_result, 0, 64);
} else {
ctx.update(key, 0, key.length);
}
}
alt_result = ctx.digest();
alt_ctx.reset();
for (cnt = 0; cnt < key.length; ++cnt) {
alt_ctx.update(key, 0, key.length);
}
temp_result = alt_ctx.digest();
p_bytes = new byte[key.length];
for (cnt2 = 0, cnt = p_bytes.length; cnt >= 64; cnt -= 64) {
System.arraycopy(temp_result, 0, p_bytes, cnt2, 64);
cnt2 += 64;
}
System.arraycopy(temp_result, 0, p_bytes, cnt2, cnt);
alt_ctx.reset();
for (cnt = 0; cnt < 16 + (alt_result[0] & 0xFF); ++cnt) {
alt_ctx.update(salts, 0, salts.length);
}
temp_result = alt_ctx.digest();
s_bytes = new byte[salts.length];
for (cnt2 = 0, cnt = s_bytes.length; cnt >= 64; cnt -= 64) {
System.arraycopy(temp_result, 0, s_bytes, cnt2, 64);
cnt2 += 64;
}
System.arraycopy(temp_result, 0, s_bytes, cnt2, cnt);
/*
* Repeatedly run the collected hash value through SHA512 to burn CPU
* cycles.
*/
for (cnt = 0; cnt < rounds; ++cnt) {
ctx.reset();
if ((cnt & 1) != 0) {
ctx.update(p_bytes, 0, key.length);
} else {
ctx.update(alt_result, 0, 64);
}
if (cnt % 3 != 0) {
ctx.update(s_bytes, 0, salts.length);
}
if (cnt % 7 != 0) {
ctx.update(p_bytes, 0, key.length);
}
if ((cnt & 1) != 0) {
ctx.update(alt_result, 0, 64);
} else {
ctx.update(p_bytes, 0, key.length);
}
alt_result = ctx.digest();
}
buffer = new StringBuilder(sha512_salt_prefix);
if (rounds != 5000) {
buffer.append(sha512_rounds_prefix);
buffer.append(rounds);
buffer.append("$");
}
buffer.append(shadowPrefix);
buffer.append("$");
buffer.append(b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4));
buffer.append(b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4));
buffer.append(b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4));
buffer.append(b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4));
buffer.append(b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4));
buffer.append(b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4));
buffer.append(b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4));
buffer.append(b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4));
buffer.append(b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4));
buffer.append(b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4));
buffer.append(b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4));
buffer.append(b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4));
buffer.append(b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4));
buffer.append(b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4));
buffer.append(b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4));
buffer.append(b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4));
buffer.append(b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4));
buffer.append(b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4));
buffer.append(b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4));
buffer.append(b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4));
buffer.append(b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4));
buffer.append(b64_from_24bit((byte) 0x00, (byte) 0x00, alt_result[63], 2));
/*
* Clear the buffer for the intermediate result so that people attaching
* to processes or reading core dumps cannot get any information.
*/
ctx.reset();
return buffer.toString();
}
private static MessageDigest sha512() {
try {
return MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException e) {
throw Throwables.propagate(e);
}
}
private static String b64_from_24bit(byte B2, byte B1, byte B0, int size) {
int v = ((((int) B2) & 0xFF) << 16) | ((((int) B1) & 0xFF) << 8) | ((int) B0 & 0xff);
StringBuilder result = new StringBuilder();
while (--size >= 0) {
result.append(itoa64.charAt(v & 0x3f));
v >>>= 6;
}
return result.toString();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy