diff --git a/src/Cipher/TagAwareCipher.php b/src/Cipher/TagAwareCipher.php new file mode 100644 index 0000000..5ecd9ea --- /dev/null +++ b/src/Cipher/TagAwareCipher.php @@ -0,0 +1,48 @@ +encoder = new Base64Encoder(); + } else { + $this->encoder = $encoder; + } + } + + public function encrypt(#[SensitiveParameter] string $string): string + { + $encryptedString = $this->cipher->encrypt($string); + + return $this->encoder->encode('' . $encryptedString . ''); + } + + public function decrypt(#[SensitiveParameter] string $string): string + { + $data = $this->encoder->decode($string); + + if (!$this->shouldDecrypt($data)) { + return $string; + } + + preg_match('/^(.*)<\/ENC>$/', $data, $matches); + + return $this->cipher->decrypt($matches[1]); + } + + private function shouldDecrypt(string $string): bool + { + return preg_match('/^(.*)<\/ENC>$/', $string) === 1; + } +} diff --git a/tests/Cipher/TagAwareCipherTest.php b/tests/Cipher/TagAwareCipherTest.php new file mode 100644 index 0000000..5ee0e1c --- /dev/null +++ b/tests/Cipher/TagAwareCipherTest.php @@ -0,0 +1,128 @@ +decoratedCipher = $this->createMock(Cipher::class); + $this->encoder = $this->createMock(Encoder::class); + + $this->cipher = new TagAwareCipher($this->decoratedCipher); + $this->cipherWithCustomEncoder = new TagAwareCipher($this->decoratedCipher, $this->encoder); + } + + /** + * @throws CipherException + */ + public function testEncrypt(): void + { + $this->decoratedCipher->expects($this->once()) + ->method('encrypt') + ->with('plainText') + ->willReturn('encryptedText'); + + $result = $this->cipher->encrypt('plainText'); + + $this->assertEquals(base64_encode('encryptedText'), $result); + } + + /** + * @throws CipherException + */ + public function testEncryptWithCustomEncoder(): void + { + $encryptedText = 'encryptedText'; + $encodedText = 'encodedText'; + + $this->decoratedCipher->expects($this->once()) + ->method('encrypt') + ->with('plainText') + ->willReturn($encryptedText); + + $this->encoder->expects($this->once()) + ->method('encode') + ->with($this->stringContains('' . $encryptedText . '')) + ->willReturn($encodedText); + + + $result = $this->cipherWithCustomEncoder->encrypt('plainText'); + + $this->assertEquals($encodedText, $result); + } + + /** + * @throws CipherException + */ + public function testDecryptWithEncryptedTag(): void + { + $encodedTextWithEncTags = base64_encode('encodedTextWithTags'); + $decryptedText = 'plainText'; + + $this->decoratedCipher->expects($this->once()) + ->method('decrypt') + ->with($this->equalTo('encodedTextWithTags')) + ->willReturn($decryptedText); + + $result = $this->cipher->decrypt($encodedTextWithEncTags); + + var_dump($result); + + $this->assertEquals($decryptedText, $result); + } + + /** + * @throws CipherException + */ + public function testDecryptWithCustomEncoderAndEncryptedTag(): void + { + $encodedTextWithEncTags = 'encodedTextWithTags'; + $decryptedText = 'plainText'; + + $this->encoder->expects($this->once()) + ->method('decode') + ->with($encodedTextWithEncTags) + ->willReturn('encryptedText'); + + $this->decoratedCipher->expects($this->once()) + ->method('decrypt') + ->with($this->equalTo('encryptedText')) + ->willReturn($decryptedText); + + $result = $this->cipherWithCustomEncoder->decrypt($encodedTextWithEncTags); + + $this->assertEquals($decryptedText, $result); + } + + /** + * @throws CipherException + */ + public function testDecryptWithCustomEncoderAndWithoutEncryptedTag(): void + { + $this->encoder->expects($this->once())->method('decode'); + $this->decoratedCipher->expects($this->never())->method('decrypt'); + + $result = $this->cipherWithCustomEncoder->decrypt('plainText'); + + $this->assertEquals('plainText', $result); + } +}