/** * Runs the runtime tests. * * @throws Ex\EnvironmentIsBrokenException */ public static function runtimeTest() { // 0: Tests haven't been run yet. // 1: Tests have passed. // 2: Tests are running right now. // 3: Tests have failed. static $test_state = 0; if ($test_state === 1 || $test_state === 2) { return; } if ($test_state === 3) { /* If an intermittent problem caused a test to fail previously, we * want that to be indicated to the user with every call to this * library. This way, if the user first does something they really * don't care about, and just ignores all exceptions, they won't get * screwed when they then start to use the library for something * they do care about. */ throw new Ex\EnvironmentIsBrokenException('Tests failed previously.'); } try { $test_state = 2; Core::ensureFunctionExists('openssl_get_cipher_methods'); if (\in_array(Core::CIPHER_METHOD, \openssl_get_cipher_methods()) === false) { throw new Ex\EnvironmentIsBrokenException('Cipher method not supported. This is normally caused by an outdated ' . 'version of OpenSSL (and/or OpenSSL compiled for FIPS compliance). ' . 'Please upgrade to a newer version of OpenSSL that supports ' . Core::CIPHER_METHOD . ' to use this library.'); } RuntimeTests::AESTestVector(); RuntimeTests::HMACTestVector(); RuntimeTests::HKDFTestVector(); RuntimeTests::testEncryptDecrypt(); if (Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) != Core::KEY_BYTE_SIZE) { throw new Ex\EnvironmentIsBrokenException(); } if (Core::ENCRYPTION_INFO_STRING == Core::AUTHENTICATION_INFO_STRING) { throw new Ex\EnvironmentIsBrokenException(); } } catch (Ex\EnvironmentIsBrokenException $ex) { // Do this, otherwise it will stay in the "tests are running" state. $test_state = 3; throw $ex; } // Change this to '0' make the tests always re-run (for benchmarking). $test_state = 1; }