Skip to content

Commit 4524c98

Browse files
Backport cryptographic boundary and validation fixes
1 parent 2cbf684 commit 4524c98

14 files changed

Lines changed: 363 additions & 128 deletions

File tree

‎src/Core/ChaCha20.php‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ public static function encryptBytes(
119119

120120
$c = '';
121121
for (;;) {
122+
if ($j12 > 0xffffffff || $j13 > 0xffffffff) {
123+
throw new SodiumException('Overflow');
124+
}
122125
if ($bytes < 64) {
123126
$message .= str_repeat("\x00", 64 - $bytes);
124127
}
@@ -258,9 +261,12 @@ public static function encryptBytes(
258261
j13 = PLUSONE(j13);
259262
}
260263
*/
261-
++$j12;
262-
if ($j12 & 0xf0000000) {
263-
throw new SodiumException('Overflow');
264+
if (
265+
++$j12 > 0xffffffff &&
266+
!($ctx instanceof ParagonIE_Sodium_Core_ChaCha20_IetfCtx)
267+
) {
268+
$j12 = 0;
269+
++$j13;
264270
}
265271

266272
/*

‎src/Core/Ed25519.php‎

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -317,40 +317,47 @@ public static function verify_detached($sig, $message, $pk)
317317
if ($d === 0) {
318318
throw new SodiumException('All zero public key');
319319
}
320+
if (self::small_order($pk)) {
321+
throw new SodiumException('Public key has small order');
322+
}
320323

321324
/** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */
322325
$orig = ParagonIE_Sodium_Compat::$fastMult;
323326

324327
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
325328
ParagonIE_Sodium_Compat::$fastMult = true;
329+
try {
330+
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */
331+
$A = self::ge_frombytes_negate_vartime($pk);
332+
if (!self::is_on_main_subgroup($A)) {
333+
throw new SodiumException('Public key is not on a member of the main subgroup');
334+
}
326335

327-
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */
328-
$A = self::ge_frombytes_negate_vartime($pk);
329-
if (!self::is_on_main_subgroup($A)) {
330-
throw new SodiumException('Public key is not on a member of the main subgroup');
331-
}
332-
333-
/** @var string $hDigest */
334-
$hDigest = hash(
335-
'sha512',
336-
self::substr($sig, 0, 32) .
337-
self::substr($pk, 0, 32) .
338-
$message,
339-
true
340-
);
336+
/** @var string $hDigest */
337+
$hDigest = hash(
338+
'sha512',
339+
self::substr($sig, 0, 32) .
340+
self::substr($pk, 0, 32) .
341+
$message,
342+
true
343+
);
341344

342-
/** @var string $h */
343-
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
345+
/** @var string $h */
346+
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
344347

345-
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */
346-
$R = self::ge_double_scalarmult_vartime(
347-
$h,
348-
$A,
349-
self::substr($sig, 32)
350-
);
348+
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */
349+
$R = self::ge_double_scalarmult_vartime(
350+
$h,
351+
$A,
352+
self::substr($sig, 32)
353+
);
351354

352-
/** @var string $rcheck */
353-
$rcheck = self::ge_tobytes($R);
355+
/** @var string $rcheck */
356+
$rcheck = self::ge_tobytes($R);
357+
} catch (Exception $ex) {
358+
ParagonIE_Sodium_Compat::$fastMult = $orig;
359+
throw $ex;
360+
}
354361

355362
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
356363
ParagonIE_Sodium_Compat::$fastMult = $orig;

‎src/Core/Ristretto255.php‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,9 @@ public static function ristretto255_scalar_complement($s)
584584
*/
585585
public static function ristretto255_scalar_invert($s)
586586
{
587+
if (ParagonIE_Sodium_Compat::is_zero($s)) {
588+
throw new SodiumException('Cannot invert a zero scalar');
589+
}
587590
return self::sc25519_invert($s);
588591
}
589592

‎src/Core/SecretStream/State.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public function incrementCounter()
9696
*/
9797
public function needsRekey()
9898
{
99-
return ($this->counter & 0xffff) === 0;
99+
return ($this->counter & 0xffffffff) === 0;
100100
}
101101

102102
/**

‎src/Core32/ChaCha20.php‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ public static function encryptBytes(
138138

139139
$c = '';
140140
for (;;) {
141+
if ($ctx->isExhausted()) {
142+
throw new SodiumException('Overflow');
143+
}
141144
if ($bytes < 64) {
142145
$message .= str_repeat("\x00", 64 - $bytes);
143146
}
@@ -264,7 +267,14 @@ public static function encryptBytes(
264267
/** @var ParagonIE_Sodium_Core32_Int32 $j12 */
265268
$j12 = $j12->addInt(1);
266269
if ($j12->limbs[0] === 0 && $j12->limbs[1] === 0) {
267-
$j13 = $j13->addInt(1);
270+
if ($ctx instanceof ParagonIE_Sodium_Core32_ChaCha20_IetfCtx) {
271+
$ctx->markExhausted();
272+
} else {
273+
$j13 = $j13->addInt(1);
274+
if ($j13->limbs[0] === 0 && $j13->limbs[1] === 0) {
275+
$ctx->markExhausted();
276+
}
277+
}
268278
}
269279

270280
/*

‎src/Core32/ChaCha20/Ctx.php‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ class ParagonIE_Sodium_Core32_ChaCha20_Ctx extends ParagonIE_Sodium_Core32_Util
1414
*/
1515
protected $container;
1616

17+
/** @var bool */
18+
protected $exhausted = false;
19+
20+
/** @return bool */
21+
public function isExhausted()
22+
{
23+
return $this->exhausted;
24+
}
25+
26+
/** @return void */
27+
public function markExhausted()
28+
{
29+
$this->exhausted = true;
30+
}
31+
1732
/**
1833
* ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
1934
*

‎src/Core32/Ed25519.php‎

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -319,34 +319,38 @@ public static function verify_detached($sig, $message, $pk)
319319

320320
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
321321
ParagonIE_Sodium_Compat::$fastMult = true;
322+
try {
323+
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */
324+
$A = self::ge_frombytes_negate_vartime($pk);
325+
if (!self::is_on_main_subgroup($A)) {
326+
throw new SodiumException('Public key is not on a member of the main subgroup');
327+
}
322328

323-
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */
324-
$A = self::ge_frombytes_negate_vartime($pk);
325-
if (!self::is_on_main_subgroup($A)) {
326-
throw new SodiumException('Public key is not on a member of the main subgroup');
327-
}
328-
329-
/** @var string $hDigest */
330-
$hDigest = hash(
331-
'sha512',
332-
self::substr($sig, 0, 32) .
333-
self::substr($pk, 0, 32) .
334-
$message,
335-
true
336-
);
329+
/** @var string $hDigest */
330+
$hDigest = hash(
331+
'sha512',
332+
self::substr($sig, 0, 32) .
333+
self::substr($pk, 0, 32) .
334+
$message,
335+
true
336+
);
337337

338-
/** @var string $h */
339-
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
338+
/** @var string $h */
339+
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
340340

341-
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */
342-
$R = self::ge_double_scalarmult_vartime(
343-
$h,
344-
$A,
345-
self::substr($sig, 32)
346-
);
341+
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */
342+
$R = self::ge_double_scalarmult_vartime(
343+
$h,
344+
$A,
345+
self::substr($sig, 32)
346+
);
347347

348-
/** @var string $rcheck */
349-
$rcheck = self::ge_tobytes($R);
348+
/** @var string $rcheck */
349+
$rcheck = self::ge_tobytes($R);
350+
} catch (Exception $ex) {
351+
ParagonIE_Sodium_Compat::$fastMult = $orig;
352+
throw $ex;
353+
}
350354

351355
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
352356
ParagonIE_Sodium_Compat::$fastMult = $orig;

‎src/Core32/SecretStream/State.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public function incrementCounter()
9696
*/
9797
public function needsRekey()
9898
{
99-
return ($this->counter & 0xffff) === 0;
99+
return ($this->counter & 0xffffffff) === 0;
100100
}
101101

102102
/**

0 commit comments

Comments
 (0)