You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
7.4 KiB
206 lines
7.4 KiB
<?php
|
|
|
|
declare(strict_types=1);
|
|
/*
|
|
* @author Paragon Initiative Enterprises
|
|
* @copyright MIT
|
|
* https://paragonie.com/book/pecl-libsodium/read/05-publickey-crypto.md
|
|
*/
|
|
|
|
namespace tts\services\paragon_crypto;
|
|
|
|
class crypto {
|
|
|
|
const single_key = true;
|
|
const multiple_keys = false;
|
|
|
|
public static function safe_encrypt(
|
|
string $message,
|
|
string $key,
|
|
bool $key_usage = self::single_key
|
|
): string {
|
|
$rnd = new \tts\random_engine();
|
|
$nonce = $rnd->get_bytes(
|
|
SODIUM_CRYPTO_SECRETBOX_NONCEBYTES
|
|
);
|
|
$fn = ($key_usage == self::single_key) ? "sodium_crypto_secretbox" : "sodium_crypto_box";
|
|
$cipher = base64_encode(
|
|
$nonce .
|
|
$fn(
|
|
$message,
|
|
$nonce,
|
|
base64_decode($key)
|
|
)
|
|
);
|
|
sodium_memzero($message);
|
|
sodium_memzero($key);
|
|
return $cipher;
|
|
}
|
|
|
|
public static function safe_decrypt(
|
|
string $encrypted,
|
|
string $key,
|
|
bool $key_usage = self::single_key
|
|
): string | false {
|
|
$decoded = base64_decode($encrypted);
|
|
if ($decoded === false) {
|
|
throw new Exception('Unable to decode');
|
|
}
|
|
if (mb_strlen($decoded, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) {
|
|
throw new Exception('Message was truncated');
|
|
}
|
|
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
|
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
|
|
|
$fn = ($key_usage == self::single_key) ? "sodium_crypto_secretbox_open" : "sodium_crypto_box_open";
|
|
$plain = $fn(
|
|
$ciphertext,
|
|
$nonce,
|
|
base64_decode($key)
|
|
);
|
|
sodium_memzero($ciphertext);
|
|
sodium_memzero($key);
|
|
return $plain;
|
|
}
|
|
|
|
public static function make_user_box_kp() {
|
|
return sodium_crypto_box_keypair();
|
|
}
|
|
|
|
public static function make_user_sign_kp() {
|
|
return sodium_crypto_sign_keypair();
|
|
}
|
|
|
|
public static function get_user_box_secret_key(string $from_make_user_box_kp): string {
|
|
return base64_encode(sodium_crypto_box_secretkey($from_make_user_box_kp));
|
|
}
|
|
|
|
public static function get_user_box_public_key(string $from_make_user_box_kp): string {
|
|
return base64_encode(sodium_crypto_box_publickey($from_make_user_box_kp));
|
|
}
|
|
|
|
public static function get_user_sign_secret_key(string $from_make_user_sign_secret_kp): string {
|
|
return sodium_crypto_sign_secretkey($from_make_user_sign_secret_kp);
|
|
}
|
|
|
|
public static function get_user_sign_public_key(string $from_make_user_sign_public_kp): string {
|
|
return sodium_crypto_sign_secretkey($from_make_user_sign_public_kp);
|
|
}
|
|
|
|
public static function box_reassemble_keypair(
|
|
string $from_get_userA_box_secret_key,
|
|
string $from_get_userB_box_public_key
|
|
): string {
|
|
return base64_encode(sodium_crypto_box_keypair_from_secretkey_and_publickey(
|
|
base64_decode($from_get_userA_box_secret_key),
|
|
base64_decode($from_get_userB_box_public_key)
|
|
));
|
|
}
|
|
|
|
public static function sign_message(string $message, string $user_sign_secretkey): string {
|
|
return sodium_crypto_sign(
|
|
$message,
|
|
$user_sign_secretkey
|
|
);
|
|
}
|
|
|
|
public static function get_signed_message(string $signed_message, string $user_sign_publickey): string | false {
|
|
return sodium_crypto_sign_open(
|
|
$signed_message,
|
|
$user_sign_publickey
|
|
);
|
|
}
|
|
|
|
public static function make_just_signature(string $message, string $user_sign_secretkey): string {
|
|
return sodium_crypto_sign_detached(
|
|
$message,
|
|
$user_sign_secretkey
|
|
);
|
|
}
|
|
|
|
public static function is_a_valid_signature(
|
|
string $signature,
|
|
string $message,
|
|
string $user_sign_public_key
|
|
): bool {
|
|
if ( sodium_crypto_sign_verify_detached(
|
|
$signature,
|
|
$message,
|
|
$user_sign_publickey
|
|
) ) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static function a_single_key_maker(): string {
|
|
$rnd = new \tts\random_engine();
|
|
return base64_encode($rnd->get_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES));
|
|
}
|
|
/*
|
|
* Extract the public key from the secret key
|
|
*/
|
|
public static function sign_publickey_from_secretkey(string $key) {
|
|
return sodium_crypto_sign_publickey_from_secretkey($key);
|
|
}
|
|
|
|
public static function increment_sequential_nonce($x) {
|
|
return sodium_increment($x); // The obtain the next nonce
|
|
}
|
|
|
|
// Should you Proceed with crypto_box decryption, if true go ahead do it.
|
|
public static function is_safe_to_decode($message_nonce, $expected_nonce): bool {
|
|
return (sodium_compare($message_nonce, $expected_nonce) === 0);
|
|
}
|
|
|
|
/*
|
|
* Sometimes you don't need to hide the contents of a message with encryption,
|
|
* but you still want to ensure that nobody on the network can tamper with
|
|
* it. For example, if you want to eschew server-side session storage and
|
|
* instead use HTTP cookies as your storage mechanism.
|
|
*/
|
|
public static function sign_outbound_message_only(string $message, string $key): string {
|
|
$mac = sodium_crypto_auth($message, $key);
|
|
return $mac . "@@" . $message;
|
|
}
|
|
|
|
public static function is_valid_inbound_message(string $message, string $key): bool {
|
|
$a = explode("@@", $message, 2);
|
|
$mac = $a[0];
|
|
$old_message = $a[1];
|
|
$ret_bool = (sodium_crypto_auth_verify($mac, $old_message, $key));
|
|
if ($ret_bool === false) {
|
|
sodium_memzero($key);
|
|
throw new \Exception("Malformed message or invalid MAC");
|
|
}
|
|
return $ret_bool;
|
|
}
|
|
|
|
}
|
|
/*
|
|
* Usage:
|
|
*
|
|
$key = tts\services\paragon_crypto\crypto::a_single_key_maker();
|
|
$enc = tts\services\paragon_crypto\crypto::safe_encrypt('Encrypt This String...', $key, \tts\services\paragon_crypto\crypto::single_key);
|
|
echo $enc . "<br/>";
|
|
$dec = \tts\services\paragon_crypto\crypto::safe_decrypt($enc, $key, \tts\services\paragon_crypto\crypto::single_key);
|
|
echo $dec . "<br/>";;
|
|
// --------------------
|
|
|
|
$key_pair_Alice = \tts\services\paragon_crypto\crypto::make_user_box_kp();
|
|
$secret_Alice = \tts\services\paragon_crypto\crypto::get_user_box_secret_key($key_pair_Alice);
|
|
$public_Alice = \tts\services\paragon_crypto\crypto::get_user_box_public_key($key_pair_Alice);
|
|
|
|
$key_pair_Bob = \tts\services\paragon_crypto\crypto::make_user_box_kp();
|
|
$secret_Bob = \tts\services\paragon_crypto\crypto::get_user_box_secret_key($key_pair_Bob);
|
|
$public_Bob = \tts\services\paragon_crypto\crypto::get_user_box_public_key($key_pair_Bob);
|
|
|
|
$kA = \tts\services\paragon_crypto\crypto::box_reassemble_keypair($secret_Alice, $public_Bob);
|
|
$enc = \tts\services\paragon_crypto\crypto::safe_encrypt('Encrypt This String2...', $kA, \tts\services\paragon_crypto\crypto::multiple_keys);
|
|
echo $enc . "<br/>";
|
|
|
|
$kB = \tts\services\paragon_crypto\crypto::box_reassemble_keypair($secret_Bob, $public_Alice);
|
|
$dec = \tts\services\paragon_crypto\crypto::safe_decrypt($enc, $kB, \tts\services\paragon_crypto\crypto::multiple_keys);
|
|
echo $dec;
|
|
*/
|
|
|