pike.git / lib / modules / Crypto.pmod / Password.pmod

version» Context lines:

pike.git/lib/modules/Crypto.pmod/Password.pmod:88:   //! This is interpreted as the NT LANMANAGER (NTLM) password   //! hash. It is a hex representation of MD4 of the password.   //!   //! @value "$1$SSSSSSSS$XXXXXXXXXXXXXXXXXXXXXX"   //! The string is interpreted according to the GNU libc2 extension   //! of @expr{crypt(3C)@} where @expr{SSSSSSSS@} is up to 8 chars of   //! salt and the @expr{XXX@} string is an @[MD5]-based hash created   //! from the password and the salt. Source: GNU libc   //! @url{http://www.gnu.org/software/libtool/manual/libc/crypt.html@}.   //! + //! @value "$P$RSSSSSSSSXXXXXXXXXXXXXXXXXXXXXX" + //! The string is interpreted as a PHPass' Portable Hash password hash, + //! where @expr{R@} is an encoding of the 2-logarithm of the number of + //! rounds, @expr{SSSSSSSS@} is a salt of 8 characters, and + //! @expr{XXX@} is similarily the @[MIME.encode_crypt64] of running + //! @[MD5.hash()] repeatedly on the password and the salt. + //! + //! @value "$H$RSSSSSSSS.XXXXXXXXXXXXXXXXXXXXXX" + //! Same as expr{"$P$"@} above. Used by phpBB3. + //! + //! @value "U$P$RSSSSSSSSXXXXXXXXXXXXXXXXXXXXXX" + //! This is handled as a Drupal upgraded PHPass Portable Hash password. + //! The password is run once through @[MD5.hash()], and then passed + //! along to the @expr{"$P$"@}-handler above. + //! + //! @value "$Q$RSSSSSSSSXXXXXXXXXXXXXXXXXXXXXX" + //! The string is interpreted as a PHPass' Portable Hash password hash, + //! where the base hashing alorithm has been switched to @[SHA1]. + //! This method is apparently used by some versions of Escher CMS. + //! + //! @value "$S$RSSSSSSSSXXXXXXXXXXXXXXXXXXXXXX" + //! The string is interpreted as a PHPass' Portable Hash password hash, + //! where the base hashing alorithm has been switched to @[SHA256]. + //! This method is apparently used by some versions of Drupal. + //!   //! @value "XXXXXXXXXXXXX"   //! The @expr{XXX@} string (which doesn't begin with @expr{"{"@}) is   //! taken to be a password hashed using the classic unix   //! @expr{crypt(3C)@} function. If the string contains only chars   //! from the set @expr{[a-zA-Z0-9./]@} it uses DES and the first two   //! characters as salt, but other alternatives might be possible   //! depending on the @expr{crypt(3C)@} implementation in the   //! operating system.   //!   //! @value ""
pike.git/lib/modules/Crypto.pmod/Password.pmod:113:   //!   //! @note   //! This function was added in Pike 7.8.755.   //!   //! @seealso   //! @[hash()], @[predef::crypt()]   int verify(string(8bit) password, string(7bit) hash)   {    if (hash == "") return 1;    +  string(8bit) passwd = password; +  password = "CENSORED"; +  +  // Compatibility with Drupal upgraded passwords. +  if (has_prefix(hash, "U$P")) { +  password = Crypto.MD5.hash(password); +  hash = hash[1..]; +  } +     // Detect the password hashing scheme.    // First check for an LDAP-style marker.    string(7bit) scheme = "crypt";    sscanf(hash, "{%s}%s", scheme, hash);    // NB: RFC2307 proscribes lower case schemes, while    // in practise they are usually in upper case.    switch(lower_case(scheme)) {    case "md5": // RFC 2307    case "smd5":    string(8bit) bin_hash = MIME.decode_base64(hash); -  password += bin_hash[16..]; +  passwd += bin_hash[16..];    bin_hash = bin_hash[..15]; -  return Crypto.MD5.hash(password) == bin_hash; +  return Crypto.MD5.hash(passwd) == bin_hash;       case "sha": // RFC 2307    case "ssha":    // SHA1 and Salted SHA1.    bin_hash = MIME.decode_base64(hash); -  password += bin_hash[20..]; +  passwd += bin_hash[20..];    bin_hash = bin_hash[..19]; -  return Crypto.SHA1.hash(password) == bin_hash; +  return Crypto.SHA1.hash(passwd) == bin_hash;       case "crypt": // RFC 2307    // First try the operating systems crypt(3C),    // since it might support more schemes than we do.    catch { -  if ((hash == "") || crypt(password, hash)) return 1; +  if ((hash == "") || crypt(passwd, hash)) return 1;    };    if (hash[0] != '$') {    if (hash[0] == '_') {    // FIXME: BSDI-style crypt(3C).    }    return 0;    }       // Then try our implementations.    if (!sscanf(hash, "$%s$%s", scheme, hash)) return 0;    sscanf(hash, "%s$%s", string(7bit) salt, hash);    int rounds = UNDEFINED;    switch(scheme) {    case "1": // crypt_md5 -  return Nettle.crypt_md5(password, salt) == hash; +  return Nettle.crypt_md5(passwd, salt) == hash;       case "2": // Blowfish (obsolete)    case "2a": // Blowfish (possibly weak) -  +  case "2b": // Blowfish (long password bug fixed)    case "2x": // Blowfish (weak)    case "2y": // Blowfish (stronger)    break;       case "nt":    case "3": // MD4 NT LANMANAGER (FreeBSD) -  return this::hash(password, "3")[4..] == hash; -  break; +  return this::hash(passwd, scheme)[sizeof(scheme) + 2..] == hash;       // cf http://www.akkadia.org/drepper/SHA-crypt.txt    case "5": // SHA-256    if (salt && has_prefix(salt, "rounds=")) {    sscanf(salt, "rounds=%d", rounds);    sscanf(hash, "%s$%s", salt, hash);    } -  return Crypto.SHA256.crypt_hash(password, salt, rounds) == hash; +  return Crypto.SHA256.crypt_hash(passwd, salt, rounds) == hash; +    #if constant(Crypto.SHA512)    case "6": // SHA-512    if (salt && has_prefix(salt, "rounds=")) {    sscanf(salt, "rounds=%d", rounds);    sscanf(hash, "%s$%s", salt, hash);    } -  return Crypto.SHA512.crypt_hash(password, salt, rounds) == hash; +  return Crypto.SHA512.crypt_hash(passwd, salt, rounds) == hash;   #endif       case "pbkdf2": // PBKDF2 with SHA1    rounds = (int)salt;    sscanf(hash, "%s$%s", salt, hash); -  return Crypto.SHA1.crypt_pbkdf2(password, salt, rounds) == hash; +  return Crypto.SHA1.crypt_pbkdf2(passwd, salt, rounds) == hash;       case "pbkdf2-sha256": // PBKDF2 with SHA256    rounds = (int)salt;    sscanf(hash, "%s$%s", salt, hash); -  return Crypto.SHA256.crypt_pbkdf2(password, salt, rounds) == hash; +  return Crypto.SHA256.crypt_pbkdf2(passwd, salt, rounds) == hash;      #if constant(Crypto.SHA512)    case "pbkdf2-sha512": // PBKDF2 with SHA512    rounds = (int)salt;    sscanf(hash, "%s$%s", salt, hash); -  return Crypto.SHA512.crypt_pbkdf2(password, salt, rounds) == hash; +  return Crypto.SHA512.crypt_pbkdf2(passwd, salt, rounds) == hash;   #endif -  +  +  case "H": case "P": // PHPass Portable Hash. +  salt = hash[..8]; +  hash = hash[9..]; +  return Crypto.MD5.crypt_php(passwd, salt) == hash; +  break; +  +  case "Q": // PHPass Portable Hash SHA1. +  salt = hash[..8]; +  hash = hash[9..]; +  return Crypto.SHA1.crypt_php(passwd, salt) == hash; +  break; +  + #if constant(Crypto.SHA512) +  case "S": // PHPass Portable Hash SHA512. +  salt = hash[..8]; +  hash = hash[9..]; +  return Crypto.SHA512.crypt_php(passwd, salt) == hash; +  break; + #endif    }    break;    }    return 0;   }      //! Generate a hash of @[password] suitable for @[verify()].   //!   //! @param password   //! Password to hash.
pike.git/lib/modules/Crypto.pmod/Password.pmod:243:   //! of @expr{5000@} rounds.   //!   //! @value "3"   //! @value "NT"   //! The NTLM MD4 hash.   //!   //! @value "1"   //! @value "$1$"   //! @[MD5.crypt_hash()] with 48 bits of salt and @expr{1000@} rounds.   //! + //! @value "P" + //! @value "$P$" + //! @value "H" + //! @value "$H$" + //! @[MD5.crypt_php()] with 48 bits of salt and a default of + //! @expr{1<<19@} rounds. The specified number of rounds will + //! be rounded up to the closest power of @expr{2@}. + //! + //! @value "U$P$" + //! Same as @expr{"$P$"@}, the supplied @[password] is assumed to + //! have already been passed through @[MD5.hash()] once. Typically + //! used to upgrade unsalted @[MD5]-password databases. + //! + //! @value "Q" + //! @value "$Q$" + //! Same as @expr{"$P$"@}, but with @[SHA1.crypt_php()]. + //! + //! @value "S" + //! @value "$S$" + //! Same as @expr{"$S$"@}, but with @[SHA512.crypt_php()]. + //! + //! @value "pbkdf2" + //! @value "$pbkdf2$" + //! @[SHA1.pbkdf2()]. + //! + //! @value "pbkdf2-sha256" + //! @value "$pbkdf2-sha256$" + //! @[SHA256.pbkdf2()]. + //! + //! @value "pbkdf2-sha512" + //! @value "$pbkdf2-sha512$" + //! @[SHA512.pbkdf2()]. + //!   //! @value ""   //! @[predef::crypt()] with 12 bits of salt.   //!   //! @endstring   //!   //! LDAP (@rfc{2307@})-style. Don't use these if you can avoid it,   //! since they are suspectible to attacks. In particular avoid   //! the unsalted variants at all costs:   //! @string   //! @value "ssha"
pike.git/lib/modules/Crypto.pmod/Password.pmod:290:   //!   //! @note   //! This function was added in Pike 7.8.755.   //!   //! @seealso   //! @[verify()], @[predef::crypt()], @[Nettle.crypt_md5()],   //! @[Nettle.Hash()->crypt_hash()]   string(7bit) hash(string(8bit) password, string(7bit)|void scheme,    int|void rounds)   { -  function(string(8bit), string(7bit), int:string(8bit)) crypt_hash; +  function(string(8bit), string(7bit), int:string(7bit)) crypt_hash;    int(0..) salt_size = 16;    int default_rounds = 5000;       string(7bit) render_crypt_hash(string(7bit) scheme, string(7bit) salt, -  string(8bit) hash, int rounds) +  string(7bit) hash, int rounds)    {    if (rounds != default_rounds) {    salt = "rounds=" + rounds + "$" + salt;    } -  -  // We claim this to be a string(7bit) string, even though we add -  // the string(0..256). It will however only be called with the -  // already base64 encoded hashes. -  return sprintf("$%s$%s$%s", scheme, salt, [string(7bit)]hash); +  return sprintf("$%s$%s$%s", scheme, salt, hash);    };       string(7bit) render_old_crypt_hash(string(7bit) scheme, string(7bit) salt, -  string(8bit) hash, int rounds) +  string(7bit) hash, int rounds)    { -  // We claim this to be a string(7bit) string, even though we add -  // the string(0..256). It will however only be called with the -  // already base64 encoded hashes. -  return sprintf("$%s$%d$%s$%s", scheme, rounds, salt, [string(7bit)]hash); +  return sprintf("$%s$%d$%s$%s", scheme, rounds, salt, hash);    };    -  +  string(7bit) render_php_crypt_hash(string(7bit) scheme, string(7bit) salt, +  string(7bit) hash, int rounds) +  { +  if (!has_value(scheme, '$')) scheme = "$" + scheme + "$"; +  int exp2 = 0; +  if (rounds < (1<<7)) exp2 = 7; +  else if (rounds > (1<<30)) exp2 = 30; +  else { +  if (rounds & (rounds - 1)) exp2 = 1; +  while (rounds) { +  rounds >>= 1; +  exp2++; +  } +  } +  return sprintf("%s%c%s%s", +  scheme, "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[exp2], +  salt, hash); +  }; +     string(7bit) render_ldap_hash(string(8bit) scheme, string(7bit) salt,    string(8bit) hash, int rounds)    {    if (scheme[0] != '{') scheme = "{" + scheme + "}";    return [string(7bit)]upper_case(scheme) + MIME.encode_base64(hash + salt);    };       function(string(7bit), string(7bit), string(8bit), int:string(7bit)) render_hash = render_crypt_hash;       switch(lower_case(scheme)) {
pike.git/lib/modules/Crypto.pmod/Password.pmod:415: Inside #if constant(Crypto.SHA512)
   case "$pbkdf2-sha512$":    crypt_hash = Crypto.SHA512.crypt_pbkdf2;    render_hash = render_old_crypt_hash;    // Defaults taken from Passlib.    salt_size = 22; // 16 bytes after base64-encoding.    default_rounds = 29000; // NB: The Passlib example defaults to 6400.    scheme = "pbkdf2-sha512";    break;   #endif    +  case "P": +  case "$P$": +  case "U$P$": +  case "H": +  case "$H$": +  crypt_hash = Crypto.MD5.crypt_php; +  render_hash = render_php_crypt_hash; +  salt_size = 8; +  default_rounds = 1<<19; +  break; +  +  case "Q": +  case "$Q$": +  crypt_hash = Crypto.SHA1.crypt_php; +  render_hash = render_php_crypt_hash; +  salt_size = 8; +  default_rounds = 1<<19; +  break; +  + #if constant(Crypto.SHA512) +  case "S": +  case "$S$": +  crypt_hash = Crypto.SHA512.crypt_php; +  render_hash = render_php_crypt_hash; +  salt_size = 8; +  default_rounds = 1<<19; +  break; + #endif +     default:    error("Unsupported hashing scheme: %O\n", scheme);    }       if (!rounds) rounds = default_rounds;       // NB: The salt must be printable.    string(7bit) salt =    [string(7bit)]replace(MIME.encode_base64(random_string(salt_size))[..salt_size-1], "+", ".");    -  string(8bit) hash = crypt_hash(password, salt, rounds); +  string(7bit) hash = crypt_hash(password, salt, rounds);       return render_hash([string(7bit)]scheme, salt, hash, rounds);   }