Skip to content

Commit 103a663

Browse files
committed
Add hardening for ISO 10126 padding
1 parent 631d321 commit 103a663

1 file changed

Lines changed: 28 additions & 3 deletions

File tree

src/Backend/OpenSSL.php

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use function openssl_verify;
2424
use function ord;
2525
use function str_repeat;
26+
use function strlen;
2627
use function substr;
2728

2829
/**
@@ -176,6 +177,7 @@ public function decrypt(
176177
if ($plaintext === false) {
177178
throw new OpenSSLException('Cannot decrypt data');
178179
}
180+
179181
return $this->useAuthTag ? $plaintext : $this->unpad($plaintext);
180182
}
181183

@@ -299,11 +301,16 @@ public function setDigestAlg(string $digest): void
299301
* Pad a plaintext using ISO 10126 padding.
300302
*
301303
* @param string $plaintext The plaintext to pad.
302-
*
303304
* @return string The padded plaintext.
305+
*
306+
* @throws \OpenSSLException in case padding failed
304307
*/
305308
public function pad(string $plaintext): string
306309
{
310+
if ($this->blocksize > 256) {
311+
throw new OpenSSLException('Block size higher than 256 not allowed');
312+
}
313+
307314
$padchr = $this->blocksize - (mb_strlen($plaintext) % $this->blocksize);
308315
$pattern = chr($padchr);
309316
return $plaintext . str_repeat($pattern, $padchr);
@@ -314,11 +321,29 @@ public function pad(string $plaintext): string
314321
* Remove an existing ISO 10126 padding from a given plaintext.
315322
*
316323
* @param string $plaintext The padded plaintext.
317-
*
318324
* @return string The plaintext without the padding.
325+
*
326+
* @throws \OpenSSLException in case unpadding failed
319327
*/
320328
public function unpad(string $plaintext): string
321329
{
322-
return substr($plaintext, 0, -ord(substr($plaintext, -1)));
330+
$len = mb_strlen($plaintext);
331+
if ($len === 0) {
332+
/*
333+
* Use a single, generic error for every decryption failure. Do not
334+
* reveal whether the padding (as opposed to the ciphertext) was the
335+
* cause: distinguishable padding errors turn unauthenticated CBC
336+
* decryption into a padding oracle (plaintext recovery).
337+
*/
338+
throw new OpenSSLException('Cannot decrypt data');
339+
}
340+
341+
$padLen = ord($plaintext[$len - 1]);
342+
$blocksize = $this->blocksize ?? 16;
343+
if ($padLen < 1 || $padLen > $blocksize || $padLen > $len) {
344+
throw new OpenSSLException('Cannot decrypt data');
345+
}
346+
347+
return substr($plaintext, 0, -$padLen);
323348
}
324349
}

0 commit comments

Comments
 (0)