(dev/core#2258) CryptoToken - More defense against malformed input
authorTim Otten <totten@civicrm.org>
Thu, 17 Dec 2020 00:26:15 +0000 (16:26 -0800)
committerTim Otten <totten@civicrm.org>
Sat, 19 Dec 2020 04:54:30 +0000 (20:54 -0800)
Civi/Crypto/CryptoToken.php
tests/phpunit/Civi/Crypto/CryptoTokenTest.php

index 93fe284fc8941948d409f998ea1b1475c67a59cd..e45f962b9fa5cf4243ee219c0b8d41bae54fc722 100644 (file)
@@ -118,9 +118,9 @@ class CryptoToken {
     /** @var CryptoRegistry $registry */
     $registry = \Civi::service('crypto.registry');
 
-    $parts = explode($this->delim, $token);
-    if ($parts[1] !== self::VERSION_1) {
-      throw new CryptoException("Unrecognized encoding");
+    $parts = explode($this->delim, $token, 4);
+    if (count($parts) !== 4 || $parts[1] !== self::VERSION_1) {
+      throw new CryptoException("Cannot decrypt token. Invalid format.");
     }
     $keyId = $parts[2];
     $cipherText = base64_decode($parts[3]);
index 64d3e310a98af857125ad4ef1066a730a945bb33..fa949ca5cddafa901b51fb8d467aec07ef721712 100644 (file)
@@ -11,6 +11,8 @@
 
 namespace Civi\Crypto;
 
+use Civi\Crypto\Exception\CryptoException;
+
 /**
  * Test major use-cases of the 'crypto.token' service.
  */
@@ -35,6 +37,29 @@ class CryptoTokenTest extends \CiviUnitTestCase {
     $this->assertTrue($token->isPlainText("\n"));
   }
 
+  public function testDecryptInvalid() {
+    $cryptoToken = \Civi::service('crypto.token');
+    try {
+      $cryptoToken->decrypt(chr(2) . 'CTK0' . chr(2));
+      $this->fail("Expected CryptoException");
+    }
+    catch (CryptoException $e) {
+      $this->assertRegExp(';Cannot decrypt token. Invalid format.;', $e->getMessage());
+    }
+
+    $goodExample = $cryptoToken->encrypt('mess with me', 'UNIT-TEST');
+    $this->assertEquals('mess with me', $cryptoToken->decrypt($goodExample));
+
+    try {
+      $badExample = preg_replace(';CTK0;', 'ctk9', $goodExample);
+      $cryptoToken->decrypt($badExample);
+      $this->fail("Expected CryptoException");
+    }
+    catch (CryptoException $e) {
+      $this->assertRegExp(';Cannot decrypt token. Invalid format.;', $e->getMessage());
+    }
+  }
+
   public function getExampleTokens() {
     return [
       // [ 'Plain text', 'Encryption Key ID', 'expectTokenRegex', 'expectTokenLen', 'expectPlain' ]