SecurityTest.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <?php
  2. /**
  3. * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  12. * @since 1.2.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Utility;
  16. use Cake\Core\Configure;
  17. use Cake\TestSuite\TestCase;
  18. use Cake\Utility\Security;
  19. /**
  20. * SecurityTest class
  21. *
  22. */
  23. class SecurityTest extends TestCase {
  24. /**
  25. * testGenerateAuthkey method
  26. *
  27. * @return void
  28. */
  29. public function testGenerateAuthkey() {
  30. $this->assertEquals(strlen(Security::generateAuthKey()), 40);
  31. }
  32. /**
  33. * testValidateAuthKey method
  34. *
  35. * @return void
  36. */
  37. public function testValidateAuthKey() {
  38. $authKey = Security::generateAuthKey();
  39. $this->assertTrue(Security::validateAuthKey($authKey));
  40. }
  41. /**
  42. * testHashInvalidSalt method
  43. *
  44. * @expectedException \Cake\Error\Exception
  45. * @return void
  46. */
  47. public function testHashInvalidSalt() {
  48. Security::hash('someKey', 'blowfish', true);
  49. }
  50. /**
  51. * testHashAnotherInvalidSalt
  52. *
  53. * @expectedException \Cake\Error\Exception
  54. * @return void
  55. */
  56. public function testHashAnotherInvalidSalt() {
  57. Security::hash('someKey', 'blowfish', '$1$lksdjoijfaoijs');
  58. }
  59. /**
  60. * testHashYetAnotherInvalidSalt
  61. *
  62. * @expectedException \Cake\Error\Exception
  63. * @return void
  64. */
  65. public function testHashYetAnotherInvalidSalt() {
  66. Security::hash('someKey', 'blowfish', '$2a$10$123');
  67. }
  68. /**
  69. * testHashInvalidCost method
  70. *
  71. * @expectedException \Cake\Error\Exception
  72. * @return void
  73. */
  74. public function testHashInvalidCost() {
  75. Security::setCost(1000);
  76. }
  77. /**
  78. * testHash method
  79. *
  80. * @return void
  81. */
  82. public function testHash() {
  83. $_hashType = Security::$hashType;
  84. $key = 'someKey';
  85. $hash = 'someHash';
  86. $this->assertSame(strlen(Security::hash($key, null, false)), 40);
  87. $this->assertSame(strlen(Security::hash($key, 'sha1', false)), 40);
  88. $this->assertSame(strlen(Security::hash($key, null, true)), 40);
  89. $this->assertSame(strlen(Security::hash($key, 'sha1', true)), 40);
  90. $result = Security::hash($key, null, $hash);
  91. $this->assertSame($result, 'e38fcb877dccb6a94729a81523851c931a46efb1');
  92. $result = Security::hash($key, 'sha1', $hash);
  93. $this->assertSame($result, 'e38fcb877dccb6a94729a81523851c931a46efb1');
  94. $hashType = 'sha1';
  95. Security::setHash($hashType);
  96. $this->assertSame(Security::$hashType, $hashType);
  97. $this->assertSame(strlen(Security::hash($key, null, true)), 40);
  98. $this->assertSame(strlen(Security::hash($key, null, false)), 40);
  99. $this->assertSame(strlen(Security::hash($key, 'md5', false)), 32);
  100. $this->assertSame(strlen(Security::hash($key, 'md5', true)), 32);
  101. $hashType = 'md5';
  102. Security::setHash($hashType);
  103. $this->assertSame(Security::$hashType, $hashType);
  104. $this->assertSame(strlen(Security::hash($key, null, false)), 32);
  105. $this->assertSame(strlen(Security::hash($key, null, true)), 32);
  106. if (!function_exists('hash') && !function_exists('mhash')) {
  107. $this->assertSame(strlen(Security::hash($key, 'sha256', false)), 32);
  108. $this->assertSame(strlen(Security::hash($key, 'sha256', true)), 32);
  109. } else {
  110. $this->assertSame(strlen(Security::hash($key, 'sha256', false)), 64);
  111. $this->assertSame(strlen(Security::hash($key, 'sha256', true)), 64);
  112. }
  113. Security::setHash($_hashType);
  114. }
  115. /**
  116. * Test that hash() works with blowfish.
  117. *
  118. * @return void
  119. */
  120. public function testHashBlowfish() {
  121. Security::setCost(10);
  122. $test = Security::hash('password', 'blowfish');
  123. $_hashType = Security::$hashType;
  124. $key = 'someKey';
  125. $hashType = 'blowfish';
  126. Security::setHash($hashType);
  127. $this->assertSame(Security::$hashType, $hashType);
  128. $this->assertSame(strlen(Security::hash($key, null, false)), 60);
  129. $password = $submittedPassword = $key;
  130. $storedPassword = Security::hash($password);
  131. $hashedPassword = Security::hash($submittedPassword, null, $storedPassword);
  132. $this->assertSame($storedPassword, $hashedPassword);
  133. $submittedPassword = 'someOtherKey';
  134. $hashedPassword = Security::hash($submittedPassword, null, $storedPassword);
  135. $this->assertNotSame($storedPassword, $hashedPassword);
  136. $expected = sha1('customsaltsomevalue');
  137. $result = Security::hash('somevalue', 'sha1', 'customsalt');
  138. $this->assertSame($expected, $result);
  139. $oldSalt = Configure::read('Security.salt');
  140. Configure::write('Security.salt', 'customsalt');
  141. $expected = sha1('customsaltsomevalue');
  142. $result = Security::hash('somevalue', 'sha1', true);
  143. $this->assertSame($expected, $result);
  144. Configure::write('Security.salt', $oldSalt);
  145. Security::setHash($_hashType);
  146. }
  147. /**
  148. * testRijndael method
  149. *
  150. * @return void
  151. */
  152. public function testRijndael() {
  153. $this->skipIf(!function_exists('mcrypt_encrypt'));
  154. $txt = 'The quick brown fox jumped over the lazy dog.';
  155. $key = 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi';
  156. $result = Security::rijndael($txt, $key, 'encrypt');
  157. $this->assertEquals($txt, Security::rijndael($result, $key, 'decrypt'));
  158. $result = Security::rijndael($key, $txt, 'encrypt');
  159. $this->assertEquals($key, Security::rijndael($result, $txt, 'decrypt'));
  160. $result = Security::rijndael('', $key, 'encrypt');
  161. $this->assertEquals('', Security::rijndael($result, $key, 'decrypt'));
  162. $key = 'this is my key of over 32 chars, yes it is';
  163. $result = Security::rijndael($txt, $key, 'encrypt');
  164. $this->assertEquals($txt, Security::rijndael($result, $key, 'decrypt'));
  165. }
  166. /**
  167. * testRijndaelInvalidOperation method
  168. *
  169. * @expectedException \Cake\Error\Exception
  170. * @return void
  171. */
  172. public function testRijndaelInvalidOperation() {
  173. $txt = 'The quick brown fox jumped over the lazy dog.';
  174. $key = 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi';
  175. Security::rijndael($txt, $key, 'foo');
  176. }
  177. /**
  178. * testRijndaelInvalidKey method
  179. *
  180. * @expectedException \Cake\Error\Exception
  181. * @return void
  182. */
  183. public function testRijndaelInvalidKey() {
  184. $txt = 'The quick brown fox jumped over the lazy dog.';
  185. $key = 'too small';
  186. Security::rijndael($txt, $key, 'encrypt');
  187. }
  188. /**
  189. * Test encrypt/decrypt.
  190. *
  191. * @return void
  192. */
  193. public function testEncryptDecrypt() {
  194. $txt = 'The quick brown fox';
  195. $key = 'This key is longer than 32 bytes long.';
  196. $result = Security::encrypt($txt, $key);
  197. $this->assertNotEquals($txt, $result, 'Should be encrypted.');
  198. $this->assertNotEquals($result, Security::encrypt($txt, $key), 'Each result is unique.');
  199. $this->assertEquals($txt, Security::decrypt($result, $key));
  200. }
  201. /**
  202. * Test that changing the key causes decryption to fail.
  203. *
  204. * @return void
  205. */
  206. public function testDecryptKeyFailure() {
  207. $txt = 'The quick brown fox';
  208. $key = 'This key is longer than 32 bytes long.';
  209. $result = Security::encrypt($txt, $key);
  210. $key = 'Not the same key. This one will fail';
  211. $this->assertFalse(Security::decrypt($txt, $key), 'Modified key will fail.');
  212. }
  213. /**
  214. * Test that decrypt fails when there is an hmac error.
  215. *
  216. * @return void
  217. */
  218. public function testDecryptHmacFailure() {
  219. $txt = 'The quick brown fox';
  220. $key = 'This key is quite long and works well.';
  221. $salt = 'this is a delicious salt!';
  222. $result = Security::encrypt($txt, $key, $salt);
  223. // Change one of the bytes in the hmac.
  224. $result[10] = 'x';
  225. $this->assertFalse(Security::decrypt($result, $key, $salt), 'Modified hmac causes failure.');
  226. }
  227. /**
  228. * Test that changing the hmac salt will cause failures.
  229. *
  230. * @return void
  231. */
  232. public function testDecryptHmacSaltFailure() {
  233. $txt = 'The quick brown fox';
  234. $key = 'This key is quite long and works well.';
  235. $salt = 'this is a delicious salt!';
  236. $result = Security::encrypt($txt, $key, $salt);
  237. $salt = 'humpty dumpty had a great fall.';
  238. $this->assertFalse(Security::decrypt($result, $key, $salt), 'Modified salt causes failure.');
  239. }
  240. /**
  241. * Test that short keys cause errors
  242. *
  243. * @expectedException \Cake\Error\Exception
  244. * @expectedExceptionMessage Invalid key for encrypt(), key must be at least 256 bits (32 bytes) long.
  245. * @return void
  246. */
  247. public function testEncryptInvalidKey() {
  248. $txt = 'The quick brown fox jumped over the lazy dog.';
  249. $key = 'this is too short';
  250. Security::encrypt($txt, $key);
  251. }
  252. /**
  253. * Test encrypting falsey data
  254. *
  255. * @return void
  256. */
  257. public function testEncryptDecryptFalseyData() {
  258. $key = 'This is a key that is long enough to be ok.';
  259. $result = Security::encrypt('', $key);
  260. $this->assertSame('', Security::decrypt($result, $key));
  261. $result = Security::encrypt(false, $key);
  262. $this->assertSame('', Security::decrypt($result, $key));
  263. $result = Security::encrypt(null, $key);
  264. $this->assertSame('', Security::decrypt($result, $key));
  265. $result = Security::encrypt(0, $key);
  266. $this->assertSame('0', Security::decrypt($result, $key));
  267. $result = Security::encrypt('0', $key);
  268. $this->assertSame('0', Security::decrypt($result, $key));
  269. }
  270. /**
  271. * Test that short keys cause errors
  272. *
  273. * @expectedException \Cake\Error\Exception
  274. * @expectedExceptionMessage Invalid key for decrypt(), key must be at least 256 bits (32 bytes) long.
  275. * @return void
  276. */
  277. public function testDecryptInvalidKey() {
  278. $txt = 'The quick brown fox jumped over the lazy dog.';
  279. $key = 'this is too short';
  280. Security::decrypt($txt, $key);
  281. }
  282. /**
  283. * Test that empty data cause errors
  284. *
  285. * @expectedException \Cake\Error\Exception
  286. * @expectedExceptionMessage The data to decrypt cannot be empty.
  287. * @return void
  288. */
  289. public function testDecryptInvalidData() {
  290. $txt = '';
  291. $key = 'This is a key that is long enough to be ok.';
  292. Security::decrypt($txt, $key);
  293. }
  294. }