1<?php
2
3/**
4 * OpenSSL Modular Exponentiation Engine
5 *
6 * PHP version 5 and 7
7 *
8 * @category  Math
9 * @package   BigInteger
10 * @author    Jim Wigginton <terrafrost@php.net>
11 * @copyright 2017 Jim Wigginton
12 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
13 * @link      http://pear.php.net/package/Math_BigInteger
14 */
15
16namespace phpseclib3\Math\BigInteger\Engines;
17
18use phpseclib3\Crypt\RSA;
19use phpseclib3\Crypt\RSA\Formats\Keys\PKCS8;
20use phpseclib3\Math\BigInteger;
21
22/**
23 * OpenSSL Modular Exponentiation Engine
24 *
25 * @package Engines
26 * @author  Jim Wigginton <terrafrost@php.net>
27 * @access  public
28 */
29abstract class OpenSSL
30{
31    /**
32     * Test for engine validity
33     *
34     * @return bool
35     */
36    public static function isValidEngine()
37    {
38        return extension_loaded('openssl') && static::class != __CLASS__;
39    }
40
41    /**
42     * Performs modular exponentiation.
43     *
44     * @param Engine $x
45     * @param Engine $e
46     * @param Engine $n
47     * @return Engine
48     */
49    public static function powModHelper(Engine $x, Engine $e, Engine $n)
50    {
51        if ($n->getLengthInBytes() < 31 || $n->getLengthInBytes() > 16384) {
52            throw new \OutOfRangeException('Only modulo between 31 and 16384 bits are accepted');
53        }
54
55        $key = PKCS8::savePublicKey(
56            new BigInteger($n),
57            new BigInteger($e)
58        );
59
60        $plaintext = str_pad($x->toBytes(), $n->getLengthInBytes(), "\0", STR_PAD_LEFT);
61
62        // this is easily prone to failure. if the modulo is a multiple of 2 or 3 or whatever it
63        // won't work and you'll get a "failure: error:0906D06C:PEM routines:PEM_read_bio:no start line"
64        // error. i suppose, for even numbers, we could do what PHP\Montgomery.php does, but then what
65        // about odd numbers divisible by 3, by 5, etc?
66        if (!openssl_public_encrypt($plaintext, $result, $key, OPENSSL_NO_PADDING)) {
67            throw new \UnexpectedValueException(openssl_error_string());
68        }
69
70        $class = get_class($x);
71        return new $class($result, 256);
72    }
73}