@@ -114,6 +114,25 @@ private function decryptWithoutSecret(string $authenticatedCiphertext, string $p
114114 throw new Exception ('Authenticated ciphertext could not be decoded. ' );
115115 }
116116
117+ /*
118+ * Rearrange arguments for legacy ownCloud migrations
119+ *
120+ * The original scheme consistent of three parts. Nextcloud added a
121+ * fourth at the end as "2" or later "3", ownCloud added "v2" at the
122+ * beginning.
123+ */
124+ $ originalParts = $ parts ;
125+ $ isOwnCloudV2Migration = $ partCount === 4 && $ originalParts [0 ] === 'v2 ' ;
126+ if ($ isOwnCloudV2Migration ) {
127+ $ parts = [
128+ $ parts [1 ],
129+ $ parts [2 ],
130+ $ parts [3 ],
131+ '2 '
132+ ];
133+ }
134+
135+ // Convert hex-encoded values to binary
117136 $ ciphertext = $ this ->hex2bin ($ parts [0 ]);
118137 $ iv = $ parts [1 ];
119138 $ hmac = $ this ->hex2bin ($ parts [2 ]);
@@ -124,7 +143,7 @@ private function decryptWithoutSecret(string $authenticatedCiphertext, string $p
124143 $ iv = $ this ->hex2bin ($ iv );
125144 }
126145
127- if ($ version === '3 ' ) {
146+ if ($ version === '3 ' || $ isOwnCloudV2Migration ) {
128147 $ keyMaterial = hash_hkdf ('sha512 ' , $ password );
129148 $ encryptionKey = substr ($ keyMaterial , 0 , 32 );
130149 $ hmacKey = substr ($ keyMaterial , 32 );
@@ -133,8 +152,15 @@ private function decryptWithoutSecret(string $authenticatedCiphertext, string $p
133152 $ this ->cipher ->setPassword ($ encryptionKey );
134153 $ this ->cipher ->setIV ($ iv );
135154
136- if (!hash_equals ($ this ->calculateHMAC ($ parts [0 ] . $ parts [1 ], $ hmacKey ), $ hmac )) {
137- throw new Exception ('HMAC does not match. ' );
155+ if ($ isOwnCloudV2Migration ) {
156+ // ownCloud uses the binary IV for HMAC calculation
157+ if (!hash_equals ($ this ->calculateHMAC ($ parts [0 ] . $ iv , $ hmacKey ), $ hmac )) {
158+ throw new Exception ('HMAC does not match. ' );
159+ }
160+ } else {
161+ if (!hash_equals ($ this ->calculateHMAC ($ parts [0 ] . $ parts [1 ], $ hmacKey ), $ hmac )) {
162+ throw new Exception ('HMAC does not match. ' );
163+ }
138164 }
139165
140166 $ result = $ this ->cipher ->decrypt ($ ciphertext );
0 commit comments