CryptTest.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. /**
  7. * Test case for \Magento\Framework\Encryption\Crypt
  8. */
  9. namespace Magento\Framework\Encryption\Test\Unit;
  10. class CryptTest extends \PHPUnit\Framework\TestCase
  11. {
  12. private $_key;
  13. private static $_cipherInfo;
  14. private const SUPPORTED_CIPHER_MODE_COMBINATIONS = [
  15. MCRYPT_BLOWFISH => [MCRYPT_MODE_ECB],
  16. MCRYPT_RIJNDAEL_128 => [MCRYPT_MODE_ECB],
  17. MCRYPT_RIJNDAEL_256 => [MCRYPT_MODE_CBC],
  18. ];
  19. protected function setUp()
  20. {
  21. $this->_key = substr(__CLASS__, -32, 32);
  22. }
  23. /**
  24. * @param $length
  25. * @return bool|string
  26. */
  27. protected function _getRandomString($length)
  28. {
  29. $result = '';
  30. do {
  31. $result .= sha1(microtime());
  32. } while (strlen($result) < $length);
  33. return substr($result, -$length);
  34. }
  35. protected function _requireCipherInfo()
  36. {
  37. $filename = __DIR__ . '/Crypt/_files/_cipher_info.php';
  38. if (!self::$_cipherInfo) {
  39. self::$_cipherInfo = include $filename;
  40. }
  41. }
  42. /**
  43. * @param $cipherName
  44. * @param $modeName
  45. * @return mixed
  46. */
  47. protected function _getKeySize($cipherName, $modeName)
  48. {
  49. $this->_requireCipherInfo();
  50. return self::$_cipherInfo[$cipherName][$modeName]['key_size'];
  51. }
  52. /**
  53. * @param $cipherName
  54. * @param $modeName
  55. * @return mixed
  56. */
  57. protected function _getInitVectorSize($cipherName, $modeName)
  58. {
  59. $this->_requireCipherInfo();
  60. return self::$_cipherInfo[$cipherName][$modeName]['iv_size'];
  61. }
  62. /**
  63. * @return array
  64. */
  65. public function getCipherModeCombinations(): array
  66. {
  67. $result = [];
  68. foreach (self::SUPPORTED_CIPHER_MODE_COMBINATIONS as $cipher => $modes) {
  69. /** @var array $modes */
  70. foreach ($modes as $mode) {
  71. $result[$cipher . '-' . $mode] = [$cipher, $mode];
  72. }
  73. }
  74. return $result;
  75. }
  76. /**
  77. * @dataProvider getCipherModeCombinations
  78. */
  79. public function testConstructor($cipher, $mode)
  80. {
  81. /* Generate random init vector */
  82. $initVector = $this->_getRandomString($this->_getInitVectorSize($cipher, $mode));
  83. $crypt = new \Magento\Framework\Encryption\Crypt($this->_key, $cipher, $mode, $initVector);
  84. $this->assertEquals($cipher, $crypt->getCipher());
  85. $this->assertEquals($mode, $crypt->getMode());
  86. $this->assertEquals($initVector, $crypt->getInitVector());
  87. }
  88. /**
  89. * @return array
  90. */
  91. public function getConstructorExceptionData()
  92. {
  93. $key = substr(__CLASS__, -32, 32);
  94. $result = [];
  95. foreach (self::SUPPORTED_CIPHER_MODE_COMBINATIONS as $cipher => $modes) {
  96. /** @var array $modes */
  97. foreach ($modes as $mode) {
  98. $tooLongKey = str_repeat('-', $this->_getKeySize($cipher, $mode) + 1);
  99. $tooShortInitVector = str_repeat('-', $this->_getInitVectorSize($cipher, $mode) - 1);
  100. $tooLongInitVector = str_repeat('-', $this->_getInitVectorSize($cipher, $mode) + 1);
  101. $result['tooLongKey-' . $cipher . '-' . $mode . '-false'] = [$tooLongKey, $cipher, $mode, false];
  102. $keyPrefix = 'key-' . $cipher . '-' . $mode;
  103. $result[$keyPrefix . '-tooShortInitVector'] = [$key, $cipher, $mode, $tooShortInitVector];
  104. $result[$keyPrefix . '-tooLongInitVector'] = [$key, $cipher, $mode, $tooLongInitVector];
  105. }
  106. }
  107. return $result;
  108. }
  109. /**
  110. * @dataProvider getConstructorExceptionData
  111. * @expectedException \Magento\Framework\Exception\LocalizedException
  112. */
  113. public function testConstructorException($key, $cipher, $mode, $initVector)
  114. {
  115. new \Magento\Framework\Encryption\Crypt($key, $cipher, $mode, $initVector);
  116. }
  117. public function testConstructorDefaults()
  118. {
  119. $cryptExpected = new \Magento\Framework\Encryption\Crypt($this->_key, MCRYPT_BLOWFISH, MCRYPT_MODE_ECB, false);
  120. $cryptActual = new \Magento\Framework\Encryption\Crypt($this->_key);
  121. $this->assertEquals($cryptExpected->getCipher(), $cryptActual->getCipher());
  122. $this->assertEquals($cryptExpected->getMode(), $cryptActual->getMode());
  123. $this->assertEquals($cryptExpected->getInitVector(), $cryptActual->getInitVector());
  124. }
  125. /**
  126. * @return mixed
  127. */
  128. public function getCryptData()
  129. {
  130. $fixturesFilename = __DIR__ . '/Crypt/_files/_crypt_fixtures.php';
  131. $result = include $fixturesFilename;
  132. /* Restore encoded string back to binary */
  133. foreach ($result as &$cryptParams) {
  134. $cryptParams[5] = base64_decode($cryptParams[5]);
  135. }
  136. unset($cryptParams);
  137. return $result;
  138. }
  139. /**
  140. * @dataProvider getCryptData
  141. */
  142. public function testEncrypt($key, $cipher, $mode, $initVector, $inputData, $expectedData)
  143. {
  144. $crypt = new \Magento\Framework\Encryption\Crypt($key, $cipher, $mode, $initVector);
  145. $actualData = $crypt->encrypt($inputData);
  146. $this->assertEquals($expectedData, $actualData);
  147. }
  148. /**
  149. * @dataProvider getCryptData
  150. */
  151. public function testDecrypt($key, $cipher, $mode, $initVector, $expectedData, $inputData)
  152. {
  153. $crypt = new \Magento\Framework\Encryption\Crypt($key, $cipher, $mode, $initVector);
  154. $actualData = $crypt->decrypt($inputData);
  155. $this->assertEquals($expectedData, $actualData);
  156. }
  157. /**
  158. * @dataProvider getCipherModeCombinations
  159. */
  160. public function testInitVectorRandom($cipher, $mode)
  161. {
  162. $crypt1 = new \Magento\Framework\Encryption\Crypt($this->_key, $cipher, $mode, true);
  163. $initVector1 = $crypt1->getInitVector();
  164. $crypt2 = new \Magento\Framework\Encryption\Crypt($this->_key, $cipher, $mode, true);
  165. $initVector2 = $crypt2->getInitVector();
  166. $expectedSize = $this->_getInitVectorSize($cipher, $mode);
  167. $this->assertEquals($expectedSize, strlen($initVector1));
  168. $this->assertEquals($expectedSize, strlen($initVector2));
  169. $this->assertNotEquals($initVector2, $initVector1);
  170. }
  171. /**
  172. * @dataProvider getCipherModeCombinations
  173. */
  174. public function testInitVectorNone($cipher, $mode)
  175. {
  176. $crypt = new \Magento\Framework\Encryption\Crypt($this->_key, $cipher, $mode, false);
  177. $actualInitVector = $crypt->getInitVector();
  178. $expectedInitVector = str_repeat("\0", $this->_getInitVectorSize($cipher, $mode));
  179. $this->assertEquals($expectedInitVector, $actualInitVector);
  180. }
  181. }