*/ class ParTCP_Crypto { static $privKeySign; static $privKeyCrypt; static $remoteKeySign; static $remoteKeyCrypt; static $useLegacyKx = FALSE; static $errors; static function get_signature_length(){ return 88; } static function get_pubkey_length(){ return 88; } static function get_privkey_length(){ return 128; } static function generate_keys( $setLocalPrivKey = FALSE ){ $keyPair = sodium_crypto_sign_keypair(); $privKeySign = sodium_crypto_sign_secretkey( $keyPair ); $pubKeySign = sodium_crypto_sign_publickey( $keyPair ); $keyPair = sodium_crypto_box_keypair(); $privKeyCrypt = sodium_crypto_box_secretkey( $keyPair ); $pubKeyCrypt = sodium_crypto_box_publickey( $keyPair ); $keys = [ base64_encode( $pubKeySign . $pubKeyCrypt ), base64_encode( $privKeySign . $privKeyCrypt ), ]; if ( $setLocalPrivKey ){ self::$privKeySign = $privKeySign; self::$privKeyCrypt = $privKeyCrypt; } return $keys; } static function set_remote_pubkey( $key ){ if ( strlen( $key ) != self::get_pubkey_length() ){ throw new Exception('Invalid public key length ' . strlen( $key ) ); } $key = base64_decode( $key ); self::$remoteKeySign = substr( $key, 0, SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES ); self::$remoteKeyCrypt = substr( $key, SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES ); } static function set_local_privkey( $key ){ if ( strlen( $key ) != self::get_privkey_length() ){ throw new Exception('Invalid private key length ' . strlen( $key ) ); } $key = base64_decode( $key ); self::$privKeySign = substr( $key, 0, SODIUM_CRYPTO_SIGN_SECRETKEYBYTES ); self::$privKeyCrypt = substr( $key, SODIUM_CRYPTO_SIGN_SECRETKEYBYTES ); } static function generate_private_hash( $data ){ if ( ! self::$privKeySign ){ throw new Exception('No private key for signing specified'); } $hash = hash( 'sha256', $data . self::$privKeySign ); return base64_encode( $hash ); } static function generate_signature( $data ){ if ( ! self::$privKeySign ){ throw new Exception('No private key for signing specified'); } $data = str_replace( ["\r\n", "\r"], "\n", trim( $data ) ); $signature = sodium_crypto_sign_detached( $data, self::$privKeySign ); return base64_encode( $signature ); } static function verify_signature( $signature, $data ){ if ( ! self::$remoteKeySign ){ throw new Exception('No remote key specified'); } if ( strlen( $signature ) != self::get_signature_length() ){ throw new Exception('Invalid signature length'); } $data = str_replace( ["\r\n", "\r"], "\n", trim( $data ) ); $signature = base64_decode( $signature ); $result = sodium_crypto_sign_verify_detached( $signature, $data, self::$remoteKeySign ); if ( $result != 1 ){ return FALSE; } return TRUE; } static function encrypt( $data ){ if ( ! self::$privKeyCrypt ){ throw new Exception('No private key for encryption specified'); } if ( ! self::$remoteKeyCrypt ){ throw new Exception('No remote key specified'); } $iv = openssl_random_pseudo_bytes( 16 ); $secret = sodium_crypto_scalarmult( self::$privKeyCrypt, self::$remoteKeyCrypt ); if ( self::$useLegacyKx ){ $encrypted = openssl_encrypt( $data, 'aes-256-ctr', $secret, 0, $iv ); } else { $secret = hash( 'sha256', $secret, TRUE ); $encrypted = openssl_encrypt( $data, 'aes-256-cbc', $secret, 0, $iv ); } return base64_encode( $iv ) . ':' . $encrypted; } static function decrypt( $data ){ if ( ! self::$privKeyCrypt ){ throw new Exception('No private key for encryption specified'); } if ( ! self::$remoteKeyCrypt ){ throw new Exception('No remote key specified'); } list( $iv, $encrypted ) = explode( ':', $data ) + [ '', '' ]; $iv = base64_decode( $iv ); if ( ! $iv || strlen( $iv ) != 16 ){ throw new Exception('Missing or invalid initialization vector'); } $secret = sodium_crypto_scalarmult( self::$privKeyCrypt, self::$remoteKeyCrypt ); if ( self::$useLegacyKx ){ $decrypted = openssl_decrypt( $encrypted, 'aes-256-ctr', $secret, 0, $iv ); } else { $secret = hash( 'sha256', $secret, TRUE ); $decrypted = openssl_decrypt( $encrypted, 'aes-256-cbc', $secret, 0, $iv ); } if ( $decrypted === FALSE ){ while ( $msg = openssl_error_string() ){ self::$errors[] = $msg; } } return $decrypted; } } // end of file crypto.class.php