PHP Classes

File: tests/unit/WycheproofTest.php

Recommend this page to a friend!
  Classes of Scott Arciszewski   PHP Sodium Compat   tests/unit/WycheproofTest.php   Download  
File: tests/unit/WycheproofTest.php
Role: Class source
Content type: text/plain
Description: Class source
Class: PHP Sodium Compat
Cryptographic functions of libsodium in pure PHP
Author: By
Last change: Update Wycheproof test code to run XChaCha20 tests
Date: 1 year ago
Size: 6,494 bytes
 

Contents

Class file image Download
<?php

class WycheproofTest extends PHPUnit_Framework_TestCase
{
    private
$dir;

   
/**
     * @before
     */
   
public function before()
    {
       
ParagonIE_Sodium_Compat::$disableFallbackForUnitTests = true;
       
$this->dir = dirname(__FILE__) . '/wycheproof/';
    }

   
/**
     * @throws Exception
     */
   
public function testChaCha20Poly1305()
    {
        if (empty(
$this->dir)) {
           
$this->before();
        }
       
$this->mainTestingLoop('chacha20_poly1305_test.json', 'doChaCha20Poly1305Test', false);
    }

   
/**
     * @throws Exception
     */
   
public function testXChaCha20Poly1305()
    {
        if (empty(
$this->dir)) {
           
$this->before();
        }
       
$this->mainTestingLoop('xchacha20_poly1305_test.json', 'doXChaCha20Poly1305Test', false);
    }

   
/**
     * @throws Exception
     */
   
public function testX25519()
    {
        if (!
defined('DO_PEDANTIC_TEST')) {
           
$this->markTestSkipped('Skipping Wycheproof Tests. Use DO_PEDANTIC_TEST to enable.');
        }
        if (empty(
$this->dir)) {
           
$this->before();
        }
       
$this->mainTestingLoop('x25519_test.json', 'doX25519Test', false);
    }

   
/**
     * @param $filename
     * @param $method
     *
     * @throws Exception
     */
   
public function mainTestingLoop($filename, $method, $progress = false)
    {
       
$total = 0;
       
$document = $this->getJson($this->dir . $filename);
        if (
$progress) {
           
$groupCount = count($document['testGroups']);
           
$groupId = 1;
        }
        foreach (
$document['testGroups'] as $testGroup) {
            if (
$progress) {
               
$testCount = count($testGroup['tests']);
               
$testId = 1;
            }
            foreach (
$testGroup['tests'] as $test) {
                ++
$total;
                if (
$progress) {
                    echo
"[Group {$groupId} : Test {$testId}]", PHP_EOL;
                }
               
$message = "{$document['algorithm']} :: #{$test['tcId']} - {$test['comment']}";
                try {
                   
$result = call_user_func_array(array($this, $method), array($test));
                   
$expected = ($test['result'] === 'valid');
                    if (
$result !== $expected) {
                       
call_user_func_array(array($this, $method), array($test, true));
                    }
                   
$this->assertSame($result, $expected, $message);
                } catch (
Exception $ex) {
                    if (
$test['result'] === 'valid') {
                       
$this->fail("{$message} (" . $ex->getMessage() . ")");
                    }
                }
                if (
$progress) {
                    ++
$groupId;
                }
            }
            if (
$progress) {
                ++
$groupId;
            }
        }
    }

   
/**
     * @param array $test
     * @return bool
     */
   
public function doChaCha20Poly1305Test(array $test, $verbose = false)
    {
       
$key = ParagonIE_Sodium_Compat::hex2bin($test['key']);
       
$iv = ParagonIE_Sodium_Compat::hex2bin($test['iv']);
       
$aad = ParagonIE_Sodium_Compat::hex2bin($test['aad']);
       
$msg = ParagonIE_Sodium_Compat::hex2bin($test['msg']);
       
$ct = ParagonIE_Sodium_Compat::hex2bin($test['ct']);
       
$tag = ParagonIE_Sodium_Compat::hex2bin($test['tag']);

       
$encrypted = ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt(
           
$msg,
           
$aad,
           
$iv,
           
$key
       
);
        if (
$verbose && !ParagonIE_Sodium_Core_Util::hashEquals($ct . $tag, $encrypted)) {
            echo
'Difference in Wycheproof test vectors:', PHP_EOL;
            echo
'- ', ParagonIE_Sodium_Core_Util::bin2hex($ct . $tag), PHP_EOL;
            echo
'+ ', ParagonIE_Sodium_Core_Util::bin2hex($encrypted), PHP_EOL;
        }
        return
ParagonIE_Sodium_Core_Util::hashEquals($ct . $tag, $encrypted);
    }

   
/**
     * @param array $test
     * @return bool
     */
   
public function doXChaCha20Poly1305Test(array $test, $verbose = false)
    {
       
$key = ParagonIE_Sodium_Compat::hex2bin($test['key']);
       
$iv = ParagonIE_Sodium_Compat::hex2bin($test['iv']);
       
$aad = ParagonIE_Sodium_Compat::hex2bin($test['aad']);
       
$msg = ParagonIE_Sodium_Compat::hex2bin($test['msg']);
       
$ct = ParagonIE_Sodium_Compat::hex2bin($test['ct']);
       
$tag = ParagonIE_Sodium_Compat::hex2bin($test['tag']);

       
$encrypted = ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_encrypt(
           
$msg,
           
$aad,
           
$iv,
           
$key
       
);
        if (
$verbose && !ParagonIE_Sodium_Core_Util::hashEquals($ct . $tag, $encrypted)) {
            echo
'Difference in Wycheproof test vectors:', PHP_EOL;
            echo
'- ', ParagonIE_Sodium_Core_Util::bin2hex($ct . $tag), PHP_EOL;
            echo
'+ ', ParagonIE_Sodium_Core_Util::bin2hex($encrypted), PHP_EOL;
        }
        return
ParagonIE_Sodium_Core_Util::hashEquals($ct . $tag, $encrypted);
    }

   
/**
     * @param array $test
     * @return bool
     */
   
public function doX25519Test(array $test, $verbose = false)
    {
       
$private = ParagonIE_Sodium_Compat::hex2bin($test['private']);
       
$public = ParagonIE_Sodium_Compat::hex2bin($test['public']);
       
$shared = ParagonIE_Sodium_Compat::hex2bin($test['shared']);

       
$scalarmult = ParagonIE_Sodium_Compat::crypto_scalarmult($private, $public);
        if (
$verbose &&!ParagonIE_Sodium_Core_Util::hashEquals($shared, $scalarmult)) {
            echo
'Difference in Wycheproof test vectors:', PHP_EOL;
            echo
'- ', ParagonIE_Sodium_Core_Util::bin2hex($shared), PHP_EOL;
            echo
'+ ', ParagonIE_Sodium_Core_Util::bin2hex($scalarmult), PHP_EOL;
        }
        return
ParagonIE_Sodium_Core_Util::hashEquals($shared, $scalarmult);
    }

   
/**
     * @param string $file
     *
     * @return mixed
     * @throws Exception
     */
   
public function getJson($file = '')
    {
        if (!
is_readable($file)) {
            throw new
Exception('Could not read file');
        }
       
$contents = file_get_contents($file);
        if (!
is_string($contents)) {
            throw new
Exception('Could not read file');
        }
       
$decoded = json_decode($contents, true);
        if (!
is_array($decoded)) {
            throw new
Exception('Error decoding JSON blob');
        }
        return
$decoded;
    }
}