SHA3 Secure SignOn

The aim of the SHA3 Secure SignOn project is to facilitate the development of a decentralized, uniform login schema to secure free and open communication across the web, starting with WordPress.

Employed by The White House and many other U.S. Government Agencies, WordPress is the world’s most popular content management system, running nearly a third of all online sites.

The potential applications of a standardized, hash-based naming schema are extensive and may include:

  • Stopping censorship with the ability to seamlessly transfer an online identity to competing networks.
  • Connecting complementary platforms to facilitate the growth of online research and commerce.
  • Mitigation of online impersonation scams and identity-based phishing attempts.
  • Verification of absentee or mail-in ballots.
  • Development of political and exit polling apps by independent entities.
  • Adding an additional layer of security for financial institutions and online banking.

How it works.

Data Encryption Standard (DES) Tripcode

The Data Encryption Standard (DES) Tripcode naming schema is a Unix DES-based algorithm already in use on a number of Virtual Bulletin Boards. The National Institute of Standards and Technology (NIST) has withdrawn DES in 2005 and it is provided here to demonstrate the platform crossover ability of a uniform naming schema.

Usage is as follows: (User#Passphrase), where User is the plain displayed nickname, followed by a pound sign (#) and Passphrase that is then subsequently hashed.

SHA3-244

The SHA3 example is a cryptographic hash standard, released by the NIST in 2015. Due to default username table restrictions, SHA3-224 was chosen for its output length, and there is no option for the user to add a plain user nickname display within the naming schema.

To maintain the security and decentralization of this naming schema and prevent abuse, hashed usernames should be paired with an independent password for each domain.

After registration, users may login with either their original DES User#Passphrase or SHA3 Passphrase by selecting one of the hashing options at login or their generated (hashed) username, including exclamation point designations.

Future Development.

This experimental plugin is for demonstration purposes and warrants further discussion, development and testing prior to full-scale implementation. 

A few ideas for modifications may include:

  • Salting the naming schema with user email address.
  • Peppering the naming schema on trusted sites with server or identifying information using the SHA3 one-way hashing algorithm.

 

The Code

The license under which the following is released is the GPLv2 (or later) from the Free Software Foundation. A copy of the license is included with every copy of WordPress, but you can also read the text of the license here.

Download the experimental SHA3 Secure SignOn plugin here.

sha3-secure-signon.php

<?php
/*
Plugin Name: SHA3 Secure SignOn
Plugin URI: https://www.sha3.org/
Description: Updates native wp-login.php with cross-platform SHA3 and DES Secure SignOn.
Version: 1.0
Author: SHA3.org
Author URI: https://www.sha3.org/
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/

// Add jquery for placeholder text and radio deselect
add_action('login_enqueue_scripts', 'wpse_login_enqueue_scripts', 10);
function wpse_login_enqueue_scripts()
{
    wp_enqueue_script('sha3.js', plugin_dir_url(__FILE__) . 'js/sha3-secure-signon.js', array(
        'jquery'
    ) , 1.0);
}

add_action('register_form', 'use_des_tripcode_login');

//Allow hash sign on register and disallow !username
function wscu_sanitize_user($username, $raw_username, $strict)
{

    if (isset($_POST['user_login']))
    {

        //if hash selected
        if (($_POST['hash'] == "des_tripcode") || ($_POST['hash'] == "sha3_hash"))
        {
            //sanitize_text_field may limit functionality but necessary for database security
            //not sure if we need to sanitize here or if fine with the next action. also possible sanitize_user( $username, false );
            $username = sanitize_text_field($raw_username);
        }
    }
    return $username;
}
add_filter('sanitize_user', 'wscu_sanitize_user', 10, 3);

//REGISTER
add_action('login_form_register', 'custom_user_login');
function custom_user_login()
{

    // make sure regisration form is submitted
    if ($_SERVER['REQUEST_METHOD'] != 'POST') return;

    // base of user_login
    $ulogin = $_POST['user_login'];

    //For DES Tripcode
    if (isset($_POST['user_login']) && ($_POST['hash'] == "des_tripcode"))
    {
        //if hash sign, capture nickname
        if (strpos($ulogin, '#') !== false)
        {
            $trippassword = explode('#', $ulogin);
            $tripcoded = $trippassword[1];
            $name = $trippassword[0];
            $salt = substr($tripcoded . "H.", 1, 2);
            $salt = preg_replace("[^\.-z]", ".", $salt);
            $salt = strtr($salt, ":;<=>?@[\\]^_`", "ABCDEFGabcdef");
            $tripusername = substr(crypt($tripcoded, $salt) , -10);
            $ulogin = $name . '!' . $tripusername;
            //sanitize_text_field may limit functionality but necessary for database security
            $_POST['user_login'] = sanitize_text_field($ulogin);
        }elseif
         (strpos($ulogin, '#') !== true)
        {
            $tripcoded = $ulogin;
            $salt = substr($tripcoded . "H.", 1, 2);
            $salt = preg_replace("[^\.-z]", ".", $salt);
            $salt = strtr($salt, ":;<=>?@[\\]^_`", "ABCDEFGabcdef");
            $tripusername = substr(crypt($tripcoded, $salt) , -10);
            $ulogin = '!' . $tripusername;
            $_POST['user_login'] = sanitize_text_field($ulogin);
        }

    }
    //For SHA3 hash
    if (isset($_POST['user_login']) && ($_POST['hash'] == "sha3_hash"))
    {
        $ulogin = hash('sha3-224', $ulogin);
        $ulogin = '!!' . $ulogin;
        $_POST['user_login'] = sanitize_text_field($ulogin);
    }

}

//adds DES option on login and register
add_action('login_form', 'use_des_tripcode_login');
function use_des_tripcode_login()
{

    echo '<p><input type="radio" name="hash" class="no_option" value="des_tripcode"><label for="des_tripcode">&nbsp;DES Tripcode</label></p>';
    echo '<p><input type="radio" name="hash" class="no_option" value="sha3_hash"><label for="sha3_hash">&nbsp;SHA3 Hash</label></p>';
    echo '<input type="radio" name="hash" class="no_option" value="null" style="display:none">';

}
//LOGIN
remove_action('authenticate', 'wp_authenticate_username_password', 20);
add_filter('authenticate', 'des_tripcode_login', 10, 3);
function des_tripcode_login($user, $username, $password)
{

    if (isset($_POST['hash']) && ($_POST['hash'] == "des_tripcode"))
    {
        //pound sign
        if (strpos($username, '#') !== false)
        {
            $trippassword = explode('#', $username);
            $tripcoded = $trippassword[1];
            $name = $trippassword[0];
            $salt = substr($tripcoded . "H.", 1, 2);
            $salt = preg_replace("[^\.-z]", ".", $salt);
            $salt = strtr($salt, ":;<=>?@[\\]^_`", "ABCDEFGabcdef");
            $tripusername = substr(crypt($tripcoded, $salt) , -10);
            $username = $name . '!' . $tripusername;;
            $username = sanitize_text_field($username);
        }
        //no pound sign
        elseif (strpos($username, '#') !== true)
        {
            $tripcoded = $username;
            $salt = substr($tripcoded . "H.", 1, 2);
            $salt = preg_replace("[^\.-z]", ".", $salt);
            $salt = strtr($salt, ":;<=>?@[\\]^_`", "ABCDEFGabcdef");
            $tripusername = substr(crypt($tripcoded, $salt) , -10);
            $username = '!' . $tripusername;
            $username = sanitize_text_field($username);

        }

    }

    //For SHA3 hash
    if (isset($_POST['hash']) && $_POST['hash'] == "sha3_hash")
    {
        $username = hash('sha3-224', $username);
        $username = '!!' . $username;
        $username = sanitize_text_field($username);
    }

    if (is_a($user, 'WP_User'))
    {
        return $user;
    }

    if (empty($username) || empty($password))
    {
        $error = new WP_Error();

        if (empty($username)) $error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));

        if (empty($password)) $error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));

        return $error;
    }

    $user = get_user_by('login', $username);

    if (!$user) return new WP_Error('invalid_username', sprintf(__('<strong>ERROR</strong>: Invalid username. <a href="%s" title="Password Lost and Found">Lost your password</a>?') , wp_lostpassword_url()));

    if (is_multisite())
    {
        // Is user marked as spam?
        if (1 == $user->spam) return new WP_Error('spammer_account', __('<strong>ERROR</strong>: Your account has been marked as a spammer.'));

        // Is a user's blog marked as spam?
        if (!is_super_admin($user->ID) && isset($user->primary_blog))
        {
            $details = get_blog_details($user->primary_blog);
            if (is_object($details) && $details->spam == 1) return new WP_Error('blog_suspended', __('Site Suspended.'));
        }
    }

    $user = apply_filters('wp_authenticate_user', $user, $password);
    if (is_wp_error($user)) return $user;

    if (!wp_check_password($password, $user->user_pass, $user->ID)) return new WP_Error('incorrect_password', sprintf(__('<strong>ERROR</strong>: The password you entered for the username <strong>%1$s</strong> is incorrect. <a href="%2$s" title="Password Lost and Found">Lost your password</a>?') , $username, wp_lostpassword_url()));

    return $user;
}

//Reserve exclamations to identify hash - nicknames
add_filter('pre_user_display_name', 'my_displayname_block');

function my_displayname_block($user_display_name)
{

    $current_user = wp_get_current_user();
	
	//buddypress optional name filter for exclamation
	//if (strpos($_POST['field_1'], "!") !== false)
    //    {
    //        wp_die(sprintf(__('<strong>ERROR</strong>: Exclamation points are reserved to identify SHA3 and DES hashes.&nbsp;<a href="%2$s" title="Go Back">Go back to profile</a>.') , $username, wp_get_referer()));
    //    }
	
	$current_usernick = $current_user->nickname;

    if (strpos($_POST['nickname'], "!") !== false && ($_POST['nickname'] != $current_usernick))
    {
        wp_die(sprintf(__('<strong>ERROR</strong>: Exclamation points are reserved to identify SHA3 and DES hashes.&nbsp;<a href="%2$s" title="Go Back">Go back to profile</a>.') , $username, wp_get_referer()));
    }
    return $user_display_name;

}

//Reserve exclamations to identify hash - first/last names
add_filter('insert_user_meta', function ($meta, $user, $update)
{

    if ($update)
    {
		
        if (strpos($_POST['first_name'], "!") !== false)
        {
            wp_die(sprintf(__('<strong>ERROR</strong>: Exclamation points are reserved to identify SHA3 and DES hashes.&nbsp;<a href="%2$s" title="Go Back">Go back to profile</a>.') , $username, wp_get_referer()));
        }
        if (strpos($_POST['last_name'], "!") !== false)
        {
            wp_die(sprintf(__('<strong>ERROR</strong>: Exclamation points are reserved to identify SHA3 and DES hashes.&nbsp;<a href="%2$s" title="Go Back">Go back to profile</a>.') , $username, wp_get_referer()));
        }

    }

    return $meta;
}
, 10, 3);

//edit login text
add_filter('gettext', 'sha3_text');
add_filter('ngettext', 'sha3_text');
function sha3_text($translated)
{
    $translated = str_ireplace('Username', 'Secure SignOn', $translated);
    return $translated;
}

//add usage info to footer
add_action('login_footer', 'sha3_footer');

function sha3_footer()
{
    echo '<div id="login"><p id="nav">For Secure SignOn usage, visit <a href="https://www.sha3.org">sha3.org</a>.</p></div>';
}

//disable registration bp
function my_disable_bp_registration() {
  remove_action( 'bp_init',    'bp_core_wpsignup_redirect' );
  remove_action( 'bp_screens', 'bp_core_screen_signup' );
}
add_action( 'bp_loaded', 'my_disable_bp_registration' );

add_filter( 'bp_get_signup_page', "firmasite_redirect_bp_signup_page");
    function firmasite_redirect_bp_signup_page($page ){
        return bp_get_root_domain() . '/wp-login.php?action=register'; 
    }

//disallow editing of bp name field since
function bpfr_hide_profile_field_group( $retval ) {
	if ( bp_is_active( 'xprofile' ) ) :	
	
	// hide profile group/field to all except admin	
	if ( !is_super_admin() ) {		
		//exlude fields, separated by comma
		$retval['exclude_fields'] = '1';  
		//exlude groups, separated by comma
		$retval['exclude_groups'] = '1'; 			
	} 
	return $retval;		
	
	endif;
}
add_filter( 'bp_after_has_profile_parse_args', 'bpfr_hide_profile_field_group' );

sha3-secure-signon.js

/**
 * Custom js file.
 */
jQuery(document).ready(function() {
    jQuery('#user_login').attr('placeholder', 'User#Passphrase');
    jQuery('#user_email').attr('placeholder', 'User Email');
    jQuery('#user_pass').attr('placeholder', 'Site Password');

    var checked_val = "null";
    jQuery(".no_option").on("click", function() {
        if (jQuery(this).val() == checked_val) {
            jQuery('input[name=hash][value=null]').prop("checked", true);
            checked_val = "null";
        } else {
            checked_val = jQuery(this).val();
            jQuery('input[name=hash][value=null]').propRemove("checked");
        }
    });


});