DefuseCryptoRuntimeTests

We're using static class inheritance to get access to protected methods inside Crypto.

Defined (1)

The class is defined in the following location(s).

/includes/gateways/direct-debit/libraries/php-encryption/RuntimeTests.php  
  1. class RuntimeTests extends Crypto 
  2. /** 
  3. * Runs the runtime tests. 
  4. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  5. */ 
  6. public static function runtimeTest() 
  7. // 0: Tests haven't been run yet. 
  8. // 1: Tests have passed. 
  9. // 2: Tests are running right now. 
  10. // 3: Tests have failed. 
  11. static $test_state = 0; 
  12.  
  13. if ($test_state === 1 || $test_state === 2) { 
  14. return; 
  15.  
  16. if ($test_state === 3) { 
  17. /** If an intermittent problem caused a test to fail previously, we 
  18. * want that to be indicated to the user with every call to this 
  19. * library. This way, if the user first does something they really 
  20. * don't care about, and just ignores all exceptions, they won't get 
  21. * screwed when they then start to use the library for something 
  22. * they do care about. */ 
  23. throw new Ex\EnvironmentIsBrokenException('Tests failed previously.'); 
  24.  
  25. try { 
  26. $test_state = 2; 
  27.  
  28. Core::ensureFunctionExists('openssl_get_cipher_methods'); 
  29. if (\in_array(Core::CIPHER_METHOD, \openssl_get_cipher_methods()) === false) { 
  30. throw new Ex\EnvironmentIsBrokenException('Cipher method not supported.'); 
  31.  
  32. RuntimeTests::AESTestVector(); 
  33. RuntimeTests::HMACTestVector(); 
  34. RuntimeTests::HKDFTestVector(); 
  35.  
  36. RuntimeTests::testEncryptDecrypt(); 
  37. if (Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) != Core::KEY_BYTE_SIZE) { 
  38. throw new Ex\EnvironmentIsBrokenException(); 
  39.  
  40. if (Core::ENCRYPTION_INFO_STRING == Core::AUTHENTICATION_INFO_STRING) { 
  41. throw new Ex\EnvironmentIsBrokenException(); 
  42. } catch (Ex\EnvironmentIsBrokenException $ex) { 
  43. // Do this, otherwise it will stay in the "tests are running" state. 
  44. $test_state = 3; 
  45. throw $ex; 
  46.  
  47. // Change this to '0' make the tests always re-run (for benchmarking). 
  48. $test_state = 1; 
  49.  
  50. /** 
  51. * High-level tests of Crypto operations. 
  52. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  53. */ 
  54. private static function testEncryptDecrypt() 
  55. $key = Key::createNewRandomKey(); 
  56. $data = "EnCrYpT EvErYThInG\x00\x00"; 
  57.  
  58. // Make sure encrypting then decrypting doesn't change the message. 
  59. $ciphertext = Crypto::encrypt($data, $key, true); 
  60. try { 
  61. $decrypted = Crypto::decrypt($ciphertext, $key, true); 
  62. } catch (Ex\WrongKeyOrModifiedCiphertextException $ex) { 
  63. // It's important to catch this and change it into a 
  64. // Ex\EnvironmentIsBrokenException, otherwise a test failure could trick 
  65. // the user into thinking it's just an invalid ciphertext! 
  66. throw new Ex\EnvironmentIsBrokenException(); 
  67. if ($decrypted !== $data) { 
  68. throw new Ex\EnvironmentIsBrokenException(); 
  69.  
  70. // Modifying the ciphertext: Appending a string. 
  71. try { 
  72. Crypto::decrypt($ciphertext . 'a', $key, true); 
  73. throw new Ex\EnvironmentIsBrokenException(); 
  74. } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /** expected */ 
  75.  
  76. // Modifying the ciphertext: Changing an HMAC byte. 
  77. $indices_to_change = [ 
  78. 0, // The header. 
  79. Core::HEADER_VERSION_SIZE + 1, // the salt 
  80. Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + 1, // the IV 
  81. Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE + 1, // the ciphertext 
  82. ]; 
  83.  
  84. foreach ($indices_to_change as $index) { 
  85. try { 
  86. $ciphertext[$index] = \chr((\ord($ciphertext[$index]) + 1) % 256); 
  87. Crypto::decrypt($ciphertext, $key, true); 
  88. throw new Ex\EnvironmentIsBrokenException(); 
  89. } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /** expected */ 
  90.  
  91. // Decrypting with the wrong key. 
  92. $key = Key::createNewRandomKey(); 
  93. $data = 'abcdef'; 
  94. $ciphertext = Crypto::encrypt($data, $key, true); 
  95. $wrong_key = Key::createNewRandomKey(); 
  96. try { 
  97. Crypto::decrypt($ciphertext, $wrong_key, true); 
  98. throw new Ex\EnvironmentIsBrokenException(); 
  99. } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /** expected */ 
  100.  
  101. // Ciphertext too small. 
  102. $key = Key::createNewRandomKey(); 
  103. $ciphertext = \str_repeat('A', Core::MINIMUM_CIPHERTEXT_SIZE - 1); 
  104. try { 
  105. Crypto::decrypt($ciphertext, $key, true); 
  106. throw new Ex\EnvironmentIsBrokenException(); 
  107. } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /** expected */ 
  108.  
  109. /** 
  110. * Test HKDF against test vectors. 
  111. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  112. */ 
  113. private static function HKDFTestVector() 
  114. // HKDF test vectors from RFC 5869 
  115.  
  116. // Test Case 1 
  117. $ikm = \str_repeat("\x0b", 22); 
  118. $salt = Encoding::hexToBin('000102030405060708090a0b0c'); 
  119. $info = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9'); 
  120. $length = 42; 
  121. $okm = Encoding::hexToBin( 
  122. '3cb25f25faacd57a90434f64d0362f2a' . 
  123. '2d2d0a90cf1a5a4c5db02d56ecc4c5bf' . 
  124. '34007208d5b887185865' 
  125. ); 
  126. $computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt); 
  127. if ($computed_okm !== $okm) { 
  128. throw new Ex\EnvironmentIsBrokenException(); 
  129.  
  130. // Test Case 7 
  131. $ikm = \str_repeat("\x0c", 22); 
  132. $length = 42; 
  133. $okm = Encoding::hexToBin( 
  134. '2c91117204d745f3500d636a62f64f0a' . 
  135. 'b3bae548aa53d423b0d1f27ebba6f5e5' . 
  136. '673a081d70cce7acfc48' 
  137. ); 
  138. $computed_okm = Core::HKDF('sha1', $ikm, $length, '', null); 
  139. if ($computed_okm !== $okm) { 
  140. throw new Ex\EnvironmentIsBrokenException(); 
  141.  
  142. /** 
  143. * Test HMAC against test vectors. 
  144. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  145. */ 
  146. private static function HMACTestVector() 
  147. // HMAC test vector From RFC 4231 (Test Case 1) 
  148. $key = \str_repeat("\x0b", 20); 
  149. $data = 'Hi There'; 
  150. $correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7'; 
  151. if (\hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) !== $correct) { 
  152. throw new Ex\EnvironmentIsBrokenException(); 
  153.  
  154. /** 
  155. * Test AES against test vectors. 
  156. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  157. */ 
  158. private static function AESTestVector() 
  159. // AES CTR mode test vector from NIST SP 800-38A 
  160. $key = Encoding::hexToBin( 
  161. '603deb1015ca71be2b73aef0857d7781' . 
  162. '1f352c073b6108d72d9810a30914dff4' 
  163. ); 
  164. $iv = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); 
  165. $plaintext = Encoding::hexToBin( 
  166. '6bc1bee22e409f96e93d7e117393172a' . 
  167. 'ae2d8a571e03ac9c9eb76fac45af8e51' . 
  168. '30c81c46a35ce411e5fbc1191a0a52ef' . 
  169. 'f69f2445df4f9b17ad2b417be66c3710' 
  170. ); 
  171. $ciphertext = Encoding::hexToBin( 
  172. '601ec313775789a5b7a7f504bbf3d228' . 
  173. 'f443e3ca4d62b59aca84e990cacaf5c5' . 
  174. '2b0930daa23de94ce87017ba2d84988d' . 
  175. 'dfc9c58db67aada613c2dd08457941a6' 
  176. ); 
  177.  
  178. $computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv); 
  179. if ($computed_ciphertext !== $ciphertext) { 
  180. echo \str_repeat("\n", 30); 
  181. echo \bin2hex($computed_ciphertext); 
  182. echo "\n---\n"; 
  183. echo \bin2hex($ciphertext); 
  184. echo \str_repeat("\n", 30); 
  185. throw new Ex\EnvironmentIsBrokenException(); 
  186.  
  187. $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD); 
  188. if ($computed_plaintext !== $plaintext) { 
  189. throw new Ex\EnvironmentIsBrokenException();