Loading...
 

CRYPT_BLOWFISH

Intro

As of 2012-06-28, many sites (like LinkedIn and Last.fm) have recently reportedly had their user databases hacked and usernames and password exposed.  Tiki has mostly recently used per-user one-time salted hashes, using PHP’s crypt() CRYPT_MD5 option.  Inspired by fear, petjal (Pete Jalajas) began to implement CRYPT_BLOWFISH to better protect user passwords.  Work was completed on 2012-06-30 with svn commit r42170 for Tiki 9.x but reverted because it was done in the stable branch and something of this nature should first be done in trunk.

From: http://php.net/manual/en/function.crypt.php

CRYPT_BLOWFISH - Blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 digits from the alphabet "./0-9A-Za-z". Using characters outside of this range in the salt will cause crypt() to return a zero-length string. The two digit cost parameter is the base-2 logarithm of the iteration count for the underlying Blowfish-based hashing algorithmeter and must be in range 04-31, values outside this range will cause crypt() to fail.

If you have any questions or suggestions about any of this, please ask!

Properties

This CRYPT_BLOWFISH implementation has the following properties.

  • Uses a hashing algorithm that is designed to be slow (with variable key stretching).  MD5, SHA1, etc, were designed to be fast, and thus are weak for password-protection purposes.  
  • Uses /dev/random (or Windows CAPICOM,  ”Crypto API COM”) to generate cryptographically strong random numbers for salt generation.  /dev/random has the potential for being “locked” by other processes, but is chosen for use here because of it is deemed to have the highest entropy.  Experience during this development indicates that $systemSalt_tiki calculation using /dev/random hangs for a few seconds when rapidly calculated one right after one another a few times, likely because the random pool is drained and is waiting to refill. 
  • Does not fall back to a weaker source of random bytes.  If a cryptographically very strong random source is not available, I’d rather fail and throw an error, than fall-back to a less secure source and give the user/admin a false sense of security. If they choose a weaker source to begin with, that’s fine.  I don’t want a tiki admin to select crypt-blowfish only to click through some warnings about how it had to fall-back to using mt_rand(); they would think that they are using strong password salting, but they would not be. 
  • A new cryptographically very strong random salt is created unique for each user and a new one is created upon each password change.   You might call it a “per-password salt”.  
  • In addition, separately, not part of CRYPT_BLOWFISH, but implemented concurrently, a single permanent site-wide $systemSalt_tiki has been added to db/local.php during installation.  This $systemSalt_tiki is also cryptographically very strong from /dev/random.  Just another layer in the security onion.  Currently set to 100 bytes; could easily be made to be much stronger, with little if any performance hit, I believe.  From the web:  the salt should be random string with at least as many variable bits, as there are bits in the hash result.
  • Tiki (lib/userslib.php hash_pass()) smartly handles old password formats currently in the site database.  Password hashes are (only) upgraded when users change their passwords.   Site admins are advised to reset all passwords and have all users create new ones upon next login.  
  • Similarly, tiki smartly handles changes in CRYPT_BLOWFISH cost parameter. 
  • Is designed to better protect against database-only attacks (sqli, xss, misplaced db backups), using Rainbow tables, dictionary, and brute-force attacks.   
  • Perhaps the most important part of this is the selection of the best available random number generator.   The PHP rand() and mt_rand() functions are universally considered weak and should not be used for this purpose.
  • Not sure of the OS, PHP, MySQL or Tiki version requirements.
  • Not sure of TIki upgrade path regressions this might cause.
  • Presuming that we don’t create, change or validate passwords very often, so a little slow performance is worth the massive security improvement.
  • The hash field in the tiki database users_users table, contains something like:
    $2a$15$6zZPPaJ90Cz43TVT3ODTqem3nhtxyA8tEgusysAddIFsQxBqwn4X6
    Where the $2a$ indicates it’s a blowfish hash.  The $15$ indicates it is set to a key stretching cost factor of 2^15 = 32,768 rounds.  After the $15$, the next 30 or so characters are the salt, and the remaining of the 60 total characters are what could be considered the hashed password.   That takes about 4 seconds on my server.  If set to 13, it’s a fraction of a second, but only gives 8192 key-stretching rounds.   13,14, or 15 (or more) are probably good numbers to choose for your site.
  • Hasn’t been tested at all on Windows; has only been tested on CentOS. 

 

Changed files

The following files were changed for this commit: 

  1. 20120630_patch_users-users-hash-varchar60_tiki.sql: MODIFY COLUMN `hash` varchar(60)
  2. lib/userslib.php:  added CRYPTO_BLOWFISH to hash_pass().
  3. lib/prefs/feature.php:  added crypto-blowfish option to feature_crypt_passwords and make it the default.
  4. installer/tiki-installer.php:  added calculate  $systemSalt_tiki and add it to db/local.php during installation only. 
    db/local.php: added $systemSalt_tikI (inserted by installer/tiki-installer.php during installation).
  5. templates/admin/include_login.tpl: added {preference name=pass_blowfish_cost}
  6. lib/prefs/pass.php:  added pass_blowfish_cost.
  7. db/tiki.sql: arildb added  `hash` varchar(60) default NULL,

 

$systemSalt_tiki

  • This variable value is automatically generated during installation, and the resultant value is inserted into db/local.php
  • If you change this value in db/local.php, all your passwords will be no long work, including Admins. Do not change it after install; if you do, you will have to rehash a new admin password and paste it manually into your MySQL users_users table.
  • Technically, this variable is not part of CRYPT_BLOWFISH.  Use of this variable during tiki password hashing augments the security that is provided separately by the CRYPT_BLOWFISH password hashing which uses unique per-user per-password salts. 
  • This variable should be kept secret, much like $pass_tiki in db/local.php.
  • db/local.php should be chmod 660 on shared hosting especially to prevent other users from seeing db password and $systemSalt_tiki.
  • Should be as long a possible that doesn’t interfere with performance. 60-100 bytes?  Currently set to 100 bytes.
  • Should be as complex as possible, including many of each kind of character (upper, lower, numbers, special characters).
    • Tried several encodings (uuencode, quoted_printable), etc, but base64 [azAZ09+/] works best. Strong enough; simple characters.
  • Looks like:
    $systemSalt_tiki
    $systemSalt_tiki='KlbWqJRELAMADEPotrff/8I5LghTfCkhk2/h5dAqSEQXOpGiOzYFlqz5qLiJ';
  • Is appended to the user password before passing into crypt() along with the one-time per-user salt, like:
    crypt($pass . $systemSalt_tiki, $salt);

 

References

 

ToDo

  • Any benefit, or reason not, in creating a completely separate database for some small amount of highly sensitive Tiki info?  Not hard to do, doesn’t take up space, might even help performance, might slow down attackers? 
  • Extract random number generation, salt generation, hashing into separate tiki libs?
  • Use MySQL aes_encrypt to protect usernames, email addresses, etc.
  • Is there a bug in the installer or elsewhere the fails to create, or deletes, the closing php tag in db/local.php?
  • Other uses of MD5 in tiki should be reviewed. Emailing MD5 hashes of passwords should be considered risky if they exist. 
  • If using /dev/random (or /dev/urandom) and/or Windows CAPICOM are ever deemed unacceptable, we can use:
Other Entropy Sources
//http://php.net/manual/en/function.openssl-random-pseudo-bytes.php:
openssl_random_pseudo_bytes($numRandomBytes, $cstrong);  $hex = bin2hex($bytes); 

or

https://www.random.org/clients/http/archive/
  • CAPICOM is apparently deprecated.
  • I haven’t tested on Windows. 
  • Clean out code of old unsafe hash-creation options (keep old hash-reading options).
  • Use MySQL aes_encrypt to protect usernames, email addresses, etc?  Are they strong enough?  Should we use MySQL hashing tools?
  • Client-side hashing to protect username, password over non-SSL connections?
  • Use Zend tools?  My quick research indicated use of MD5 or just wrapper code.

 

Miscellaneous

  • $ find . -iname “*hash*” -o -iname “*rand*” | grep -i sec | grep -v -e .svn
    • ./lib/phpseclib/Crypt/Random.php  (uses /dev/urandom, not /dev/random)
    • ./lib/phpseclib/Crypt/Hash.php
    • ./lib/phpsec/phpsec/phpsec.hash.php
    • ./lib/phpsec/phpsec/phpsec.rand.php (uses openssl_random_pseudo_bytes and mcrypt_create_iv; falls  back to mt_rand if needed, which I find unacceptable; if I want or need to use mt_rand, I can easily just call it directly, perhaps by just selecting the crypt-md5 tiki Encryption method option instead of the stronger crypt-blowfish option.) 
  • From the web: “uniqid is not cryptographically secure, it is designed specifically to never return the same number twice”
  • $ php -r ‘print_r(hash_algos());’

 
Note: phpsec has been deprecated: https://sourceforge.net/p/tikiwiki/code/61780

Interesting links

Keywords

The following is a list of keywords that should serve as hubs for navigation within the Tiki development and should correspond to documentation keywords.

Each feature in Tiki has a wiki page which regroups all the bugs, requests for enhancements, etc. It is somewhat a form of wiki-based project management. You can also express your interest in a feature by adding it to your profile. You can also try out the Dynamic filter.

Accessibility (WAI & 508)
Accounting 7.x
Administration
Ajax 2.x
Articles & Submissions
Backlinks
Banner
Batch 6.x
BigBlueButton audio/video/chat/screensharing (5.x)
Blog
Bookmark
Browser Compatibility
Calendar
Category
Chat
Comment
Communication Center
Consistency
Contacts Address book
Contact us
Content template
Contribution 2.x
Cookie
Copyright
Credits 6.x
Custom Home (and Group Home Page)
Database MySQL - MyISAM
Database MySQL - InnoDB
Date and Time
Debugger Console
Directory (of hyperlinks)
Documentation link from Tiki to doc.tiki.org (Help System)
Docs 8.x
DogFood
Draw 7.x
Dynamic Content
Preferences
Dynamic Variable
External Authentication
FAQ
Featured links
Feeds (RSS)
File Gallery
Forum
Friendship Network (Community)
Group
Help
History
Hotword
HTML Page
i18n (Multilingual, l10n, Babelfish)
Image Gallery
Import-Export
Install
Integrator
Interoperability
Inter-User Messages
InterTiki
jQuery
Kaltura video management
Karma
Live Support
Logs (system & action)
Lost edit protection
Mail-in
Map
Menu
Meta Tag
Missing features
Visual Mapping 3.x
Mobile Tiki and Voice Tiki
Mods
Modules
MultiTiki
MyTiki
Newsletter
Notepad
OS independence (Non-Linux, Windows/IIS, Mac, BSD)
Organic Groups (Self-managed Teams)
Payment 5.x
Performance Speed / Load / Compression / Cache
Permission
Poll
Profiles
Quiz
Rating
Realname
Report
Revision Approval
Score
Search engine optimization (SEO)
Search
Security
Semantic links 3.x
Share
Shopping Cart 5.x
Shoutbox
Site Identity
Slideshow
Smarty Template
Social Networking
Spam protection (Anti-bot CATPCHA)
Spellcheck
Spreadsheet
Staging and Approval
Stats
Survey
Syntax Highlighter (Codemirror)
Tablesorter
Tags 2.x
Task
Tell a Friend, alert + Social Bookmarking
Terms and Conditions
Theme
TikiTests 2.x
Timesheet
Token Access
Toolbar (Quicktags)
Tours
Trackers
TRIM
User Administration
User Files
User Menu
Watch
WebHelp
Webmail and Groupmail
WebServices 3.x
Wiki 3D
Wiki History, page rename, etc
Wiki plugins extends basic syntax
Wiki syntax text area, parser, etc
Wiki structure (book and table of content)
Workspace and perspectives 4.x
WYSIWTSN 4.x
WYSIWYCA
WYSIWYG 2.x
XMLRPC




Useful Tools