/**********************************************************************************
* nWordPress is an automated migration of WordPress 2.5.1 performed by Numiton.
*
* copyright : (C) 2008 Numiton - www.numiton.com
* email : numiton@users.sourceforge.net
*
* $Id: PasswordHash.java,v 1.2 2008/10/03 18:45:30 numiton Exp $
*
**********************************************************************************/
/**********************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
**********************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
package org.numiton.nwp.wp_includes;
import static com.numiton.VarHandling.*;
import java.io.Serializable;
import org.apache.log4j.Logger;
import org.numiton.nwp.GlobalConsts;
import org.numiton.nwp.GlobalVars;
import com.numiton.*;
import com.numiton.Math;
import com.numiton.file.FileSystemOrSocket;
import com.numiton.generic.ContextCarrierInterface;
import com.numiton.generic.GlobalConstantsInterface;
import com.numiton.generic.GlobalVariablesContainer;
import com.numiton.ntile.til.libraries.php.quercus.QMisc;
import com.numiton.ntile.til.libraries.php.quercus.QStrings;
import com.numiton.string.Strings;
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5
* @version 0.1
* @link http://www.openwall.com/phpass/
*/
//
// Portable PHP password hashing framework.
//
// Version 0.1 / genuine.
//
// Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
// the public domain.
//
// There's absolutely no warranty.
//
// The homepage URL for this framework is:
//
// http://www.openwall.com/phpass/
//
// Please be sure to update the Version line if you edit this file in any way.
// It is suggested that you leave the main version number intact, but indicate
// your project name (after the slash) and add your own revision information.
//
// Please do not change the "private" password hashing method implemented in
// here, thereby making your hashes incompatible. However, if you must, please
// change the hash type identifier (the "$P$") to something different.
//
// Obviously, since this code is in the public domain, the above are not
// requirements (there can be none), but merely suggestions.
//
public class PasswordHash implements ContextCarrierInterface, Serializable, Cloneable {
protected static final Logger LOG = Logger.getLogger(PasswordHash.class.getName());
public GlobalConsts gConsts;
public GlobalVars gVars;
public String itoa64;
public int iteration_count_log2;
public boolean portable_hashes;
public String random_state;
public PasswordHash(GlobalVars javaGlobalVariables, GlobalConsts javaGlobalConstants, int iteration_count_log2, boolean portable_hashes) {
setContext(javaGlobalVariables, javaGlobalConstants);
this.itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
if (iteration_count_log2 < 4 || iteration_count_log2 > 31) {
iteration_count_log2 = 8;
}
this.iteration_count_log2 = iteration_count_log2;
this.portable_hashes = portable_hashes;
this.random_state = strval(DateTime.microtime()) + (false ? /*Modified by Numiton*/strval(Unsupported.getmypid()) : "") + Misc.uniqid(strval(Math.rand()), true);
}
public String get_random_bytes(int count) {
String output = null;
int fh = 0;
int i = 0;
output = "";
if (booleanval(fh = FileSystemOrSocket.fopen(gVars.webEnv, "/dev/urandom", "rb"))) {
output = FileSystemOrSocket.fread(gVars.webEnv, fh, count);
FileSystemOrSocket.fclose(gVars.webEnv, fh);
}
if (Strings.strlen(output) < count) {
output = "";
for (i = 0; i < count; i = i + 16) {
this.random_state = Strings.md5(strval(DateTime.microtime()) + this.random_state);
output = output + QMisc.pack("H*", Strings.md5(this.random_state));
}
output = Strings.substr(output, 0, count);
}
return output;
}
public String encode64(String input, int count) {
String output = null;
int i = 0;
int value = 0;
output = "";
i = 0;
do {
value = Strings.ord(Strings.getCharAt(input, i++));
output = output + Strings.getCharAt(this.itoa64, value & 63);
if (i < count) {
value = value | Strings.ord(Strings.getCharAt(input, i)) << 8;
}
output = output + Strings.getCharAt(this.itoa64, value >> 6 & 63);
if (i++ >= count) {
break;
}
if (i < count) {
value = value | Strings.ord(Strings.getCharAt(input, i)) << 16;
}
output = output + Strings.getCharAt(this.itoa64, value >> 12 & 63);
if (i++ >= count) {
break;
}
output = output + Strings.getCharAt(this.itoa64, value >> 18 & 63);
}
while (i < count);
return output;
}
public String gensalt_private(String input) {
String output = null;
output = "$P$";
output = output + Strings.getCharAt(this.itoa64, intval(Math.min(this.iteration_count_log2 + ((intval("PHP_VERSION") >= intval("5")) ? 5 : 3), 30)));
output = output + this.encode64(input, 6);
return output;
}
public String crypt_private(String password, String setting) {
String output = null;
int count_log2 = 0;
int count = 0;
String salt = null;
String hash = null;
output = "*0";
if (equal(Strings.substr(setting, 0, 2), output)) {
output = "*1";
}
if (!equal(Strings.substr(setting, 0, 3), "$P$")) {
return output;
}
count_log2 = Strings.strpos(this.itoa64, Strings.getCharAt(setting, 3));
if (count_log2 < 7 || count_log2 > 30) {
return output;
}
count = 1 << count_log2;
salt = Strings.substr(setting, 4, 8);
if (!equal(Strings.strlen(salt), 8)) {
return output;
}
// We're kind of forced to use MD5 here since it's the only
// cryptographic primitive available in all versions of PHP
// currently in use. To implement our own low-level crypto
// in PHP would result in much worse performance and
// consequently in lower iteration counts and hashes that are
// quicker to crack (by non-PHP code).
if (intval("PHP_VERSION") >= intval("5")) {
hash = Strings.md5(salt + password, true);
do {
hash = Strings.md5(hash + password, true);
}
while (booleanval(--count));
}
else {
hash = QMisc.pack("H*", Strings.md5(salt + password));
do {
hash = QMisc.pack("H*", Strings.md5(hash + password));
}
while (booleanval(--count));
}
output = Strings.substr(setting, 0, 12);
output = output + this.encode64(hash, 16);
return output;
}
public String gensalt_extended(Object input) {
Object count_log2 = null;
int count = 0;
String output = null;
count_log2 = Math.min(this.iteration_count_log2 + 8, 24);
// This should be odd to not reveal weak DES keys, and the
// maximum valid value is (2**24 - 1) which is odd anyway.
count = (1 << intval(count_log2)) - 1;
output = "_";
output = output + Strings.getCharAt(this.itoa64, count & 63);
output = output + Strings.getCharAt(this.itoa64, count >> 6 & 63);
output = output + Strings.getCharAt(this.itoa64, count >> 12 & 63);
output = output + Strings.getCharAt(this.itoa64, count >> 18 & 63);
output = output + this.encode64(strval(input), 3);
return output;
}
public String gensalt_blowfish(String input) {
String itoa64 = null;
String output = null;
int i = 0;
int c1 = 0;
int c2 = 0;
// This one needs to use a different order of characters and a
// different encoding scheme from the one in encode64() above.
// We care because the last character in our encoded string will
// only represent 2 bits. While two known implementations of
// bcrypt will happily accept and correct a salt string which
// has the 4 unused bits set to non-zero, we do not want to take
// chances and we also do not want to waste an additional byte
// of entropy.
itoa64 = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
output = "$2a$";
output = output + Strings.chr(intval(floatval(Strings.ord("0")) + floatval(this.iteration_count_log2) / floatval(10)));
output = output + Strings.chr(Strings.ord("0") + this.iteration_count_log2 % 10);
output = output + "$";
i = 0;
do {
c1 = Strings.ord(Strings.getCharAt(input, i++));
output = output + Strings.getCharAt(itoa64, c1 >> 2);
c1 = (c1 & 3) << 4;
if (i >= 16) {
output = output + Strings.getCharAt(itoa64, c1);
break;
}
c2 = Strings.ord(Strings.getCharAt(input, i++));
c1 = c1 | c2 >> 4;
output = output + Strings.getCharAt(itoa64, c1);
c1 = (c2 & 15) << 2;
c2 = Strings.ord(Strings.getCharAt(input, i++));
c1 = c1 | c2 >> 6;
output = output + Strings.getCharAt(itoa64, c1);
output = output + Strings.getCharAt(itoa64, c2 & 63);
}
while (booleanval(1));
return output;
}
public String HashPassword(String password) {
String random = null;
String hash = null;
random = "";
if (equal(Strings.CRYPT_BLOWFISH, 1) && !this.portable_hashes) {
random = this.get_random_bytes(16);
hash = QStrings.crypt(password, this.gensalt_blowfish(random));
if (equal(Strings.strlen(hash), 60)) {
return hash;
}
}
if (equal(Strings.CRYPT_EXT_DES, 1) && !this.portable_hashes) {
if (Strings.strlen(random) < 3) {
random = this.get_random_bytes(3);
}
hash = QStrings.crypt(password, this.gensalt_extended(random));
if (equal(Strings.strlen(hash), 20)) {
return hash;
}
}
if (Strings.strlen(random) < 6) {
random = this.get_random_bytes(6);
}
hash = this.crypt_private(password, this.gensalt_private(random));
if (equal(Strings.strlen(hash), 34)) {
return hash;
}
// Returning '*' on error is safe here, but would _not_ be safe
// in a crypt(3)-like function used _both_ for generating new
// hashes and for validating passwords against existing hashes.
return "*";
}
public boolean CheckPassword(String password, String stored_hash) {
String hash = null;
hash = this.crypt_private(password, stored_hash);
if (equal(Strings.getCharAt(hash, 0), "*")) {
hash = QStrings.crypt(password, stored_hash);
}
return equal(hash, stored_hash);
}
public void setContext(GlobalVariablesContainer javaGlobalVariables, GlobalConstantsInterface javaGlobalConstants) {
gConsts = (GlobalConsts) javaGlobalConstants;
gVars = (GlobalVars) javaGlobalVariables;
gVars.gConsts = gConsts;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public GlobalVariablesContainer getGlobalVars() {
return gVars;
}
}