rugk/threema-msgapi-sdk-php

View on GitHub
source/Threema/MsgApi/Tools/CryptToolSodium.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 * @author Threema GmbH
 * @copyright Copyright (c) 2015-2016 Threema GmbH
 */


namespace Threema\MsgApi\Tools;

use Threema\Core\Exception;
use Threema\Core\KeyPair;

/**
 * Contains static methods to do various Threema cryptography related tasks.
 * Support libsodium >= 0.2.0 (Namespaces)
 *
 * @package Threema\Core
 */
class CryptToolSodium extends CryptTool {
    /**
     * @param string $data
     * @param string $nonce
     * @param string $senderPrivateKey
     * @param string $recipientPublicKey
     * @return string encrypted box
     */
    protected function makeBox($data, $nonce, $senderPrivateKey, $recipientPublicKey) {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        $kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($senderPrivateKey, $recipientPublicKey);

        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\crypto_box($data, $nonce, $kp);
    }

    /**
     * make a secret box
     *
     * @param $data
     * @param $nonce
     * @param $key
     * @return mixed
     */
    protected function makeSecretBox($data, $nonce, $key) {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\crypto_secretbox($data, $nonce, $key);
    }


    /**
     * @param string $box
     * @param string $recipientPrivateKey
     * @param string $senderPublicKey
     * @param string $nonce
     * @return null|string
     */
    protected function openBox($box, $recipientPrivateKey, $senderPublicKey, $nonce) {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        $kp = \Sodium\crypto_box_keypair_from_secretkey_and_publickey($recipientPrivateKey, $senderPublicKey);
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\crypto_box_open($box, $nonce, $kp);
    }

    /**
     * decrypt a secret box
     *
     * @param string $box as binary
     * @param string $nonce as binary
     * @param string $key as binary
     * @return string as binary
     */
    protected function openSecretBox($box, $nonce, $key) {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\crypto_secretbox_open($box, $nonce, $key);
    }

    /**
     * Generate a new key pair.
     *
     * @return KeyPair the new key pair
     */
    final public function generateKeyPair() {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        $kp = \Sodium\crypto_box_keypair();
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return new KeyPair(\Sodium\crypto_box_secretkey($kp), \Sodium\crypto_box_publickey($kp));
    }

    /**
     * @param int $size
     * @return string
     */
    protected function createRandom($size) {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\randombytes_buf($size);
    }

    /**
     * Derive the public key
     *
     * @param string $privateKey in binary
     * @return string public key as binary
     */
    final public function derivePublicKey($privateKey) {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\crypto_box_publickey_from_secretkey($privateKey);
    }

    /**
     * Converts a binary string to an hexdecimal string.
     *
     * This is the same as PHP's bin2hex() implementation, but it is resistant to
     * timing attacks.
     *
     * @link https://paragonie.com/book/pecl-libsodium/read/03-utilities-helpers.md#bin2hex
     * @param  string $binaryString The binary string to convert
     * @return string
     */
    public function bin2hex($binaryString)
    {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\bin2hex($binaryString);
    }

    /**
     * Converts an hexdecimal string to a binary string.
     *
     * This is the same as PHP's hex2bin() implementation, but it is resistant to
     * timing attacks.
     *
     * @link https://paragonie.com/book/pecl-libsodium/read/03-utilities-helpers.md#hex2bin
     * @param  string $hexString The hex string to convert
     * @param  string|null $ignore    (optional) Characters to ignore
     * @throws \Threema\Core\Exception
     * @return string
     */
    public function hex2bin($hexString, $ignore = null)
    {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\hex2bin($hexString, $ignore);
    }


    /**
     * Compares two strings in a secure way.
     *
     * This is the same as PHP's strcmp() implementation, but it is resistant to
     * timing attacks.
     *
     * @link https://paragonie.com/book/pecl-libsodium/read/03-utilities-helpers.md#compare
     * @param  string $str1 The first string
     * @param  string $str2 The second string
     * @return bool
     */
    public function stringCompare($str1, $str2)
    {
        // check variable type manually
        if (!is_string($str1) || !is_string($str2)) {
            return false;
        }

        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\memcmp($str1, $str2) === 0;
    }

    /**
     * Unsets/removes a variable.
     *
     * Important: When using PHPv7, make sure to have at least version 1.0.1 of
     * the Libsodium PECL (libsodium-php) installed. Otherwise this falls back to
     * the (insecure) PHP method of removing a variable.
     *
     * @link https://paragonie.com/book/pecl-libsodium/read/03-utilities-helpers.md#memzero
     * @param  string $var A variable, passed by reference
     */
    public function removeVar(&$var)
    {
        // check if version is compatible
        if (version_compare(PHP_VERSION, '7.0', '>=') &&
            version_compare(phpversion('libsodium'), '1.0.1', '<')
        ) {
            // if not, fall back to PHP implementation
            return parent::removeVar($var);
        }

        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return \Sodium\memzero($var);
    }

    /**
     * Check if implementation supported
     * @return bool
     */
    public function isSupported() {
        return true === extension_loaded('libsodium')
            && false === method_exists('Sodium', 'sodium_version_string');
    }

    /**
     * Validate crypt tool
     *
     * @return bool
     * @throws Exception
     */
    public function validate() {
        if(false === $this->isSupported()) {
            throw new Exception('Sodium implementation not supported');
        }
        return true;
    }

    /**
     * @return string
     */
    public function getName() {
        return 'sodium';
    }

    /**
     * Description of the CryptTool
     * @return string
     */
    public function getDescription() {
        /** @noinspection PhpUndefinedNamespaceInspection @noinspection PhpUndefinedFunctionInspection */
        return 'Sodium implementation '.\Sodium\version_string().' with PHP binding '.phpversion('libsodium');
    }
}