55namespace Patchlevel \Hydrator \Extension \Cryptography ;
66
77use Patchlevel \Hydrator \Extension \Cryptography \Cipher \Cipher ;
8- use Patchlevel \Hydrator \Extension \Cryptography \Cipher \CipherKey ;
98use Patchlevel \Hydrator \Extension \Cryptography \Cipher \CipherKeyFactory ;
109use Patchlevel \Hydrator \Extension \Cryptography \Cipher \DecryptionFailed ;
10+ use Patchlevel \Hydrator \Extension \Cryptography \Cipher \EncryptedData ;
1111use Patchlevel \Hydrator \Extension \Cryptography \Cipher \EncryptionFailed ;
1212use Patchlevel \Hydrator \Extension \Cryptography \Cipher \OpensslCipher ;
1313use Patchlevel \Hydrator \Extension \Cryptography \Cipher \OpensslCipherKeyFactory ;
1414use Patchlevel \Hydrator \Extension \Cryptography \Store \CipherKeyNotExists ;
1515use Patchlevel \Hydrator \Extension \Cryptography \Store \CipherKeyStore ;
1616
17- use function array_key_exists ;
18- use function base64_decode ;
19- use function base64_encode ;
2017use function is_array ;
2118
2219/**
2320 * @experimental
24- * @phpstan-type EncryptedDataV1 array{
25- * __enc: 'v1',
26- * data: non-empty-string,
27- * method?: non-empty-string,
28- * iv?: non-empty-string,
21+ * @phpstan-type EncryptedDataArray array{
22+ * v: 1,
23+ * a: non-empty-string,
24+ * k: non-empty-string,
25+ * n?: non-empty-string, // base64
26+ * d: non-empty-string, // base64 ciphertext
27+ * t?: non-empty-string, // base64 (for AEAD)
2928 * }
3029 */
3130final class BaseCryptographer implements Cryptographer
@@ -38,50 +37,71 @@ public function __construct(
3837 }
3938
4039 /**
41- * @return EncryptedDataV1
40+ * @return EncryptedDataArray
4241 *
4342 * @throws EncryptionFailed
4443 */
4544 public function encrypt (string $ subjectId , mixed $ value ): array
4645 {
4746 try {
48- $ cipherKey = $ this ->cipherKeyStore ->get ($ subjectId );
47+ $ cipherKey = $ this ->cipherKeyStore ->currentKeyFor ($ subjectId );
4948 } catch (CipherKeyNotExists ) {
50- $ cipherKey = ($ this ->cipherKeyFactory )();
51- $ this ->cipherKeyStore ->store ($ subjectId , $ cipherKey );
49+ $ cipherKey = ($ this ->cipherKeyFactory )($ subjectId );
50+ $ this ->cipherKeyStore ->store ($ cipherKey -> id , $ cipherKey );
5251 }
5352
54- return [
55- '__enc ' => 'v1 ' ,
56- 'data ' => $ this ->cipher ->encrypt ($ cipherKey , $ value ),
57- 'method ' => $ cipherKey ->method ,
58- 'iv ' => base64_encode ($ cipherKey ->iv ),
53+ $ parameter = $ this ->cipher ->encrypt ($ cipherKey , $ value );
54+
55+ $ result = [
56+ 'v ' => 1 ,
57+ 'a ' => $ parameter ->method ,
58+ 'k ' => $ cipherKey ->id ,
59+ 'd ' => $ parameter ->data ,
5960 ];
61+
62+ if ($ parameter ->nonce !== null ) {
63+ $ result ['n ' ] = $ parameter ->nonce ;
64+ }
65+
66+ if ($ parameter ->tag !== null ) {
67+ $ result ['t ' ] = $ parameter ->tag ;
68+ }
69+
70+ return $ result ;
6071 }
6172
6273 /**
63- * @param EncryptedDataV1 $encryptedData
74+ * @param EncryptedDataArray $encryptedData
6475 *
6576 * @throws CipherKeyNotExists
6677 * @throws DecryptionFailed
6778 */
6879 public function decrypt (string $ subjectId , mixed $ encryptedData ): mixed
6980 {
70- $ cipherKey = $ this ->cipherKeyStore ->get ($ subjectId );
81+ $ keyId = $ encryptedData ['k ' ] ?? null ;
82+
83+ if ($ keyId === null ) {
84+ throw DecryptionFailed::missingKeyId ();
85+ }
86+
87+ $ cipherKey = $ this ->cipherKeyStore ->get ($ keyId );
7188
7289 return $ this ->cipher ->decrypt (
73- new CipherKey (
74- $ cipherKey ->key ,
75- $ encryptedData ['method ' ] ?? $ cipherKey ->method ,
76- isset ($ encryptedData ['iv ' ]) ? base64_decode ($ encryptedData ['iv ' ]) : $ cipherKey ->iv ,
90+ $ cipherKey ,
91+ new EncryptedData (
92+ $ encryptedData ['d ' ],
93+ $ encryptedData ['a ' ],
94+ $ encryptedData ['n ' ] ?? null ,
95+ $ encryptedData ['t ' ] ?? null ,
7796 ),
78- $ encryptedData ['data ' ],
7997 );
8098 }
8199
82100 public function supports (mixed $ value ): bool
83101 {
84- return is_array ($ value ) && array_key_exists ('__enc ' , $ value ) && $ value ['__enc ' ] === 'v1 ' ;
102+ return is_array ($ value )
103+ && isset ($ value ['v ' ], $ value ['a ' ], $ value ['k ' ], $ value ['d ' ])
104+ && $ value ['v ' ] === 1 ;
85105 }
86106
87107 /** @param non-empty-string $method */
0 commit comments