encryption bechmarks.

main
Robert 3 years ago
parent 127a31958d
commit b8051fba32
  1. 5
      documents/folders.txt
  2. 2
      src/classes/app.php
  3. 33
      src/classes/security.php
  4. 162
      src/classes/services/encryption.php
  5. 137
      src/classes/services/obsolete/crypto.php
  6. 4
      src/classes/services/obsolete/http_socket_request.php
  7. 25
      src/classes/services/paragon_crypto/crypto.php
  8. 11
      src/classes/services/paragon_crypto/password_storage.php

@ -50,6 +50,7 @@ tts_framework/src
   ├── safer_sql.php (Play-Testing SQL filter)
   ├── security.php (hasing, csrf_token\session_hijacking_functions)
   ├── services
     ├── encryption.php (Symmetric encryption based on openssl)
     ├── emailer.php (PHPMailer helper to send an email out)
     ├── html_filter.php (HTMLPurifier Bootstraper)
     ├── http_requests
@ -57,8 +58,6 @@ tts_framework/src
     ├── liquid_templates.php (Sets up Liquid Templates Engine for Views)
     ├── log.php (Appends new Log to Project's logs folder)
     ├── obsolete
       ├── crypto.php (Old Sodium code for Public-key, or asymmetric cryptography)
       ├── encryption.php (Old symmetric encryption based on openssl)
       └── http_socket_request.php (Failed to get Sockets working, use Guzzle, PHP HTTP client instead!)
     ├── paragon_crypto
       ├── crypto.php (Newer sodium_crypto)
@ -92,4 +91,4 @@ tts_framework/src
   └── broken.php (Debug Trace)
└── errors.php (when Live, this: Sorry, we had an error... Page is used)
~73 files
~72 files

@ -15,7 +15,7 @@ use Exception;
/**
*
* @todo Ensure tts JS error reporting works
* @todo
* @todo Finish Session MGT, Encrypted Sessions
* @todo Make Cached Sessions
* @todo Force Database methods to try Cache First and Save Cache Data
*/

@ -40,6 +40,9 @@ final class security {
if (strpos($algo, "md") !== false) {
throw new \Exception("MD is too weak!");
}
if (strpos($algo, "sha1") !== false) {
throw new \Exception("sha1 is too weak!");
}
$allowed = hash_hmac_algos();
if (in_array(strtolower($algo), $allowed)) {
return hash_hmac($algo, $pepper);
@ -47,6 +50,20 @@ final class security {
throw new \Exception("hmac algo not found!");
}
/*
* Consider MD5 and SHA1 which are fast and efficient,
* making them ideal for check summing and file verification.
* However, their speed makes them unsuitable for hashing a
* user’s password. With today’s computational power of
* modern CPUs/GPUs and cloud computing, a hashed password
* can be cracked by brute force in a matter of minutes.
* It’s fairly trivial to quickly generate billions of MD5
* hashes from random words until a match is found, thereby
* revealing the original plain-text password. Instead,
* intentionally slower hashing algorithms such as bcrypt
* or Argon2 should be used.
*/
public static function find_default_hash_algo() {
if (defined("PASSWORD_ARGON2ID"))
return PASSWORD_ARGON2ID;
@ -59,6 +76,12 @@ final class security {
return false;
}
/*
* The password_hash() function not only uses a secure
* one-way hashing algorithm, but it automatically handles
* salt and prevents time based side-channel attacks.
*/
public static function do_password_hash(string $password): bool | string {
$pwd_peppered = self::make_hash($password);
$hash_algo = \main_tts\configure::get(
@ -87,7 +110,7 @@ final class security {
public static function make_hash(string $text): string {
$level = \main_tts\configure::get('security', 'hash_level');
if (empty($level)) {
$level = "high";
$level = "normal";
}
$pepper = \main_tts\configure::get('security', 'pepper_pwd');
if (strlen($pepper) < 12) {
@ -108,7 +131,7 @@ final class security {
if (function_exists("hash")) {
return hash("sha512", $salt . $text . $pepper);
}
case 'high':
case 'normal':
// Prefer computing using HMAC
if (function_exists("hash_hmac")) {
return hash_hmac("sha256", $text, $pepper);
@ -118,9 +141,11 @@ final class security {
return hash("sha256", $salt . $text . $pepper);
}
case 'weak':
return sha1($salt . $text . $pepper);
throw \Exception("Too weak of a Hash FN");
// return sha1($salt . $text . $pepper);
case 'low':
return md5($salt . md5($text . $pepper));
throw \Exception("Too weak of a Hash FN");
// return md5($salt . md5($text . $pepper));
default:
break;
}

@ -8,11 +8,9 @@ declare(strict_types=1);
* @license https://mit-license.org/
*/
namespace tts\services\obsolete;
namespace tts\services;
/*
* NOTICE: This file is just for PLAY, not for PRODUCTION system!
*
* var_dump($enc->list_ssl_methods());
* var_dump($enc->list_hashes());
*/
@ -34,30 +32,82 @@ final class encryption {
$this->random_engine = new \tts\random_engine();
}
public function change_security_level(string $level): bool {
switch (strtolower($level)) {
case 'blaze':
$this->set_loops(1843);
$this->set_length(32);
/**
* About blowfish ->
* Designers: Bruce Schneier
* First published: 1993
* Successors: Twofish
* Key sizes: 32–448 bits
* Block sizes: 64 bits
* Structure: Feistel network
* Rounds: 16
*/
/*
* In cryptography, Twofish is a symmetric key block cipher
* with a block size of 128 bits and key sizes up to 256 bits.
* Twofish was slightly slower than Rijndael for 128-bit keys,
* but somewhat faster for 256-bit keys.
*/
/*
* AES is the main block cipher in use today, standardized by NIST. Camellia is a Japanese standardized cipher. ChaCha is a fast stream cipher specified by Bernstein and incorporated into TLS with support from Google.
* Serpent and Twofish were AES last round candidates that didn't make it. Serpent is not that fast, and Twofish is relatively fast but not compared to AES when hardware acceleration is used. Both are block ciphers that are really not needed as long as we deem AES to be secure.
* Threefish was mainly designed for the Skein hash function. This tweakable block cipher is not used much. It Skein had been chosen as SHA-3 then it would have stood a better chance. For now an authenticated form of Keccak would make more sense.
* So yeah, two standardized ciphers and a fast stream ciphers are supported, none of which are broken. There is no reason to include the also-ran's and a cipher made specifically for a hash function which was also not standardized.
*/
/**
* lighting, blaze, and quick are not for sensitive data,
* it is good for making sure data was not tampered with
* like encrypted sessions. Where as, good, normal,
* and paranoid are for cookies, DB storage, etc...
*/
case 'lighting': // 0.0001 Seconds
$this->set_loops(3); // Very very fast
$this->set_length(64);
$this->set_key_bits(16);
$this->method = 'blowfish';
$this->default_hash = 'md5';
$this->method = 'AES-128-CBC';
$this->default_hash = 'sha256';
return true;
case 'blaze': // 0.0109 Seconds
$this->set_loops(1843);
$this->set_length(64);
$this->set_key_bits(32);
$this->method = 'AES-128-CBC';
$this->default_hash = 'sha256';
return true;
case 'quick': // 0.0167 Seconds
$this->set_loops(2843);
$this->set_length(64);
$this->set_key_bits(32);
$this->method = 'AES-192-CBC';
$this->default_hash = 'sha256';
return true;
case 'normal':
$this->set_loops(81952);
case 'good': // 0.0732 Seconds
$this->set_loops(11952);
$this->set_length(64);
$this->set_key_bits(32);
$this->method = 'AES-256-CBC';
$this->default_hash = 'sha256';
return true;
case 'normal': // 0.4901 Seconds
$this->set_loops(81952); // slow
$this->set_length(64);
$this->set_key_bits(32);
$this->method = 'AES-256-CBC';
$this->default_hash = 'sha256';
return true;
case 'max':
case 'paranoid': // 0.6167 Seconds
case 'max':
case 'high':
case 'slow-secure':
$this->set_loops(77891);
case 'slow-secure': // Very slow
$this->set_loops(82952);
$this->set_length(128);
$this->set_key_bits(64);
$this->method = 'AES-256-XTS';
$this->method = 'AES-256-CBC';
$this->default_hash = 'sha512';
return true;
}
@ -124,8 +174,26 @@ final class encryption {
return false;
}
/**
* SHA-224, with 224 bit hash values
* SHA-256, with 256 bit hash values
* SHA-384, with 384 bit hash values
* SHA-512, with 512 bit hash values
* SHA-512/224, with 512 bit hash values
* SHA-512/256, with 512 bit hash values
* Among these, SHA-256 and SHA-512 are the most commonly
* accepted and used hash functions computed with 32-bit
* and 64-bit words, respectively. SHA-224 and SHA-384 are
* truncated versions of SHA-256 and SHA-512 respectively,
* computed with different initial values.
*/
public function list_hashes(): array {
return hash_algos();
$hash = hash_algos();
// Filter out weak Hash FNs
$hash = array_filter( $hash, function($n) { return stripos($n,"crc")===FALSE; } );
$hash = array_filter( $hash, function($n) { return stripos($n,"md")===FALSE; } );
$hash = array_filter( $hash, function($n) { return stripos($n,"sha1")===FALSE; } );
return $hash;
}
public function change_hash(string $hash): bool {
@ -165,9 +233,13 @@ final class encryption {
OPENSSL_RAW_DATA,
$iv
);
sodium_memzero($text);
sodium_memzero($key);
sodium_memzero($encKey);
$hmac = hash_hmac($this->default_hash, $iv . $ciphertext, $hmacKey);
sodium_memzero($hmacKey);
if (! $this->binary) {
return (! $this->url_encode) ? base64_encode($hmac . $iv . $ciphertext) : px_base64url_encode($hmac . $iv . $ciphertext);
return (! $this->url_encode) ? base64_encode($hmac . $iv . $ciphertext) : \tts\misc::base64url_encode($hmac . $iv . $ciphertext);
} else {
return $hmac . $iv . $ciphertext;
}
@ -179,35 +251,38 @@ final class encryption {
* @param string $data encoded text
* @return string plain text
*/
public function decrypt(string $key, string $data, bool $validate = true): string {
public function decrypt(string $key, string $data, bool $validate = true): false|string {
$key = ($validate) ? $this->get_valid_key($key) : $key;
if (! $this->binary) {
$text = (! $this->url_encode) ? base64_decode($data) : px_base64url_decode($data);
$text = (! $this->url_encode) ? base64_decode($data) : \tts\misc::base64url_decode($data);
} else {
$text = $data;
}
$hmac = substr($text, 0, $this->_length);
$ivsize = openssl_cipher_iv_length($this->method);
$iv = (! $this->binary) ? substr($text, $this->_length, $ivsize) : $ivsize;
$ivsize = openssl_cipher_iv_length($this->method);
$iv = (! $this->binary) ? substr($text, $this->_length, $ivsize) : $ivsize;
$ciphertext = substr($text, $ivsize + $this->_length);
// Generate the encryption and hmac keys
$keys = hash_pbkdf2($this->default_hash, $key, $iv, $this->_iterations, $this->_length, $this->_raw);
$encKey = substr($keys, 0, $this->_key_bits); // X bit encryption key
$hmacNew = hash_hmac($this->default_hash, $iv . $ciphertext, substr($keys, $this->_key_bits));
if (! hash_equals($hmac, $hmacNew)) { // to prevent timing attacks
return 'FALSE'; // Note: hash_equals() requires PHP5.6+
return false; // Note: hash_equals() requires PHP5.6+
}
return openssl_decrypt(
$ret = openssl_decrypt(
$ciphertext,
$this->method,
$encKey,
OPENSSL_RAW_DATA,
$iv
);
sodium_memzero($ciphertext);
sodium_memzero($key);
sodium_memzero($encKey);
sodium_memzero($keys);
return $ret;
}
/**
* Try to make sure you have a valid key
* @param string $key as input
@ -227,7 +302,9 @@ final class encryption {
throw new \Exception('Unable to use ENC key: None HEX Digits!');
}
return bin2hex(pack('H*', $key));
$ret = bin2hex(pack('H*', $key));
sodium_memzero($key);
return $ret;
}
/**
@ -238,14 +315,29 @@ final class encryption {
$ivsize = openssl_cipher_iv_length($this->method);
return bin2hex($this->random_engine->get_bytes($ivsize));
}
}
/*
* INSERT:
INSERT INTO users (username, password) VALUES ('root', AES_ENCRYPT('somepassword', 'key12346123'));
and SELECT:
/**
* Also, this requires SSL connection to the database.
* So, the KEY does not get exposed!!!!
*/
public function mysql_aes_encode(string $data, string $key, bool $bind = true) {
$safe_text = addslashes($data);
$safe_key = addslashes($key);
$parm = ($bind) ? ":{$safe_text}" : "'{$safe_text}'";
$ret = "HEX(AES_ENCRYPT($parm},'{$safe_key}'))";
sodium_memzero($key);
sodium_memzero($safe_key);
sodium_memzero($data);
sodium_memzero($safe_text);
sodium_memzero($parm);
return $ret;
}
SELECT AES_DECRYPT(password, 'key12346123') AS pwd FROM users WHERE username = 'root';
Also, this requires SSL connection to the database.
*/
public function mysql_aes_decode(string $field_name, string $key, bool $add_as = false) {
$safe_field = addslashes($field_name);
$safe_key = addslashes($key);
$as = ($add_as === true) ? " AS `{$safe_field}`" : "";
return "CAST(AES_DECRYPT(UNHEX(`{$safe_field}`),'{$safe_key}') AS char){$as}";
}
}

@ -1,137 +0,0 @@
<?php
declare(strict_types=1);
/**
* @author Robert Strutts <Robert@TryingToScale.com>
* @copyright Copyright (c) 2022, Robert Strutts.
* @license https://mit-license.org/
*/
/**
* NOTICE: This file is just for PLAY, not for PRODUCTION system!
*/
namespace tts\services\obsolete;
class crypto {
private string $nonce;
private $random_engine;
/**
* Method to construct instance of Crypto
*
* @param string $nonce Nonce to crypt string
*/
public function __construct($nonce = '') {
if (is_array($nonce)) {
$this->nonce = $this->generateNonce();
} else {
$this->nonce = !empty($nonce) ? base64_decode($nonce) : $this->generateNonce();
}
$this->random_engine = new \tts\random_engine();
}
/**
* Method to encode string
*
* @param string $key Key to encode
* @param mixed $input Input to crypt
* @return string
*/
public function encode(string $key, $input): string {
$keyDecode = base64_decode($key);
$keypair1_public = $this->getPublic($keyDecode);
$keypair1_secret = $this->getSecret($keyDecode);
return $this->_encode(serialize($input), $keypair1_public, $keypair1_secret);
}
/**
* Method to decode string
*
* @param string $key Key to decode
* @param string $input String to decode
*/
public function decode(string $key, string $input): mixed {
$keyDecode = base64_decode($key);
$keypair1_public = $this->getPublic($keyDecode);
$keypair1_secret = $this->getSecret($keyDecode);
return unserialize($this->_decode($input, $keypair1_public, $keypair1_secret));
}
/**
* Method to generate new key
*
* @return string
*/
public function generateKey(): string {
return base64_encode(sodium_crypto_box_keypair());
}
/**
* Method to generate new key
*
* @return string
*/
public static function getKey(): string {
return base64_encode(sodium_crypto_box_keypair());
}
/**
* Method to generate new nonce
*
* @return string
*/
public function generateNonce(): string {
return $this->random_engine->get_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES);
}
public function getNonce(): string {
return base64_encode($this->nonce);
}
public function setNonce(string $nonce): void {
$this->nonce = base64_decode($nonce);
}
/**
* Method to decode string
*
* @param string $input Input to decode
* @param string $keyPublic Key public
* @param string $keySecret Key secret
*/
private function _decode(string $input, string $keyPublic, string $keySecret): false|string {
$decryption_key = sodium_crypto_box_keypair_from_secretkey_and_publickey(base64_decode($keySecret), base64_decode($keyPublic));
return sodium_crypto_box_open(base64_decode($input), $this->nonce, $decryption_key);
}
/**
* Method to encode string
*
* @param string $input Input to encode
* @param string $keyPublic Key public
* @param string $keySecret Key secret
* @return string
*/
private function _encode(string $input, string $keyPublic, string $keySecret): string {
$encryption_key = sodium_crypto_box_keypair_from_secretkey_and_publickey(base64_decode($keySecret), base64_decode($keyPublic));
return base64_encode(sodium_crypto_box($input, $this->nonce, $encryption_key));
}
/**
* Method to return secret of key
*/
private function getSecret(string $key): string {
return base64_encode(sodium_crypto_box_secretkey($key));
}
/**
* Method to return public of key
*/
private function getPublic(string $key): string {
return base64_encode(sodium_crypto_box_publickey($key));
}
}

@ -8,6 +8,10 @@ declare(strict_types=1);
* @license https://mit-license.org/
*/
/**
* @todo Still messing with this to get it to work!
*/
namespace tts\services\obsolete\http_requests;
use \tts\contacts\http_request_options as HTTP_Requests;

@ -14,6 +14,31 @@ class crypto {
const single_key = true;
const multiple_keys = false;
/*
* Secret key encryption (or symmetric encryption as it’s also
* known) uses a single key to both encrypt and decrypt data.
* In the past PHP relied on mcrypt and openssl for secret key
* encryption. PHP 7.2 introduced Sodium, which is more modern
* and widely considered more secure.
*
* In order to encrypt a value, first you’ll need an encryption
* key, which can be generated using the
* sodium_crypto_secretbox_keygen() function.
*
* $key = sodium_crypto_secretbox_keygen();
* You can also use the random_bytes() function with the
* SODIUM_CRYPTO_SECRETBOX_KEYBYTES integer constant for the
* key length, but using sodium_crypto_secretbox_keygen()
* ensures that the key length is always correct (i.e. not too
* short), and it’s easier.
*
* $key = random_bytes( SODIUM_CRYPTO_SECRETBOX_KEYBYTES );
* Either way, you’ll usually only do this once and store the
* result as an environment variable. Remember that this key
* must be kept secret at all costs. If the key is ever
* compromised, so is any data encrypted by using it.
*/
public static function safe_encrypt(
string $message,
string $key,

@ -18,6 +18,10 @@ class password_storage {
public function __construct() {
$this->random_engine = new \tts\random_engine();
}
public function generate_a_key(): string {
return sodium_bin2hex($this->random_engine->get_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES));
}
/**
* Hash then encrypt a password
@ -36,6 +40,7 @@ class password_storage {
$salt = $this->random_engine->get_bytes(self::SALT_SIZE_IN_BYTES);
list ($enc_key, $auth_key) = $this->split_keys($secret_key, sodium_bin2hex($salt));
sodium_memzero($secret_key);
sodium_memzero($password);
$nonce = $this->random_engine->get_bytes(
SODIUM_CRYPTO_STREAM_NONCEBYTES
);
@ -92,7 +97,9 @@ class password_storage {
$hash_str = sodium_crypto_stream_xor($cipher_text, $nonce, $enc_key);
sodium_memzero($enc_key);
if ($hash_str !== false) {
return sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($hash_str, $password);
$ret = sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($hash_str, $password);
sodium_memzero($password);
return $ret;
}
} else {
sodium_memzero($auth_key);
@ -114,7 +121,7 @@ class password_storage {
/*
$c = new \tts\services\paragon_crypto\password_storage();
$k = sodium_bin2hex(random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES));
$k = $c->generate_a_key();
$h = $c->hash("HelpMe", $k);
var_dump( $c->verify("HelpMe", $h, $k) );
*/

Loading…
Cancel
Save