1<?php
2
3/*
4 * The RandomLib library for securely generating random numbers and strings in PHP
5 *
6 * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
7 * @copyright  2011 The Authors
8 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
9 * @version    Build @@version@@
10 */
11
12/**
13 * The Mcrypt abstract mixer class
14 *
15 * PHP version 5.3
16 *
17 * @category   PHPCryptLib
18 * @package    Random
19 * @subpackage Mixer
20 *
21 * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
22 * @copyright  2013 The Authors
23 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
24 *
25 * @version    Build @@version@@
26 */
27namespace RandomLib;
28
29/**
30 * The mcrypt abstract mixer class
31 *
32 * @category   PHPCryptLib
33 * @package    Random
34 * @subpackage Mixer
35 *
36 * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
37 * @author     Chris Smith <chris@cs278.org>
38 */
39abstract class AbstractMcryptMixer extends AbstractMixer
40{
41    /**
42     * mcrypt module resource
43     *
44     * @var resource
45     */
46    private $mcrypt;
47
48    /**
49     * Block size of cipher
50     *
51     * @var int
52     */
53    private $blockSize;
54
55    /**
56     * Cipher initialization vector
57     *
58     * @var string
59     */
60    private $initv;
61
62    /**
63     * {@inheritdoc}
64     */
65    public static function test()
66    {
67        return extension_loaded('mcrypt');
68    }
69
70    /**
71     * Construct mcrypt mixer
72     */
73    public function __construct()
74    {
75        $this->mcrypt    = mcrypt_module_open($this->getCipher(), '', MCRYPT_MODE_ECB, '');
76        $this->blockSize = mcrypt_enc_get_block_size($this->mcrypt);
77        $this->initv     = str_repeat(chr(0), mcrypt_enc_get_iv_size($this->mcrypt));
78    }
79
80    /**
81     * Performs cleanup
82     */
83    public function __destruct()
84    {
85        if ($this->mcrypt) {
86            mcrypt_module_close($this->mcrypt);
87        }
88    }
89
90    /**
91     * Fetch the cipher for mcrypt.
92     *
93     * @return string
94     */
95    abstract protected function getCipher();
96
97    /**
98     * {@inheritdoc}
99     */
100    protected function getPartSize()
101    {
102        return $this->blockSize;
103    }
104
105    /**
106     * {@inheritdoc}
107     */
108    protected function mixParts1($part1, $part2)
109    {
110        return $this->encryptBlock($part1, $part2);
111    }
112
113    /**
114     * {@inheritdoc}
115     */
116    protected function mixParts2($part1, $part2)
117    {
118        return $this->decryptBlock($part2, $part1);
119    }
120
121    /**
122     * Encrypts a block using the suppied key
123     *
124     * @param string $input Plaintext to encrypt
125     * @param string $key   Encryption key
126     *
127     * @return string Resulting ciphertext
128     */
129    private function encryptBlock($input, $key)
130    {
131        if (!$input && !$key) {
132            return '';
133        }
134
135        $this->prepareCipher($key);
136        $result = mcrypt_generic($this->mcrypt, $input);
137        mcrypt_generic_deinit($this->mcrypt);
138
139        return $result;
140    }
141
142    /**
143     * Derypts a block using the suppied key
144     *
145     * @param string $input Ciphertext to decrypt
146     * @param string $key   Encryption key
147     *
148     * @return string Resulting plaintext
149     */
150    private function decryptBlock($input, $key)
151    {
152        if (!$input && !$key) {
153            return '';
154        }
155
156        $this->prepareCipher($key);
157        $result = mdecrypt_generic($this->mcrypt, $input);
158        mcrypt_generic_deinit($this->mcrypt);
159
160        return $result;
161    }
162
163    /**
164     * Sets up the mcrypt module
165     *
166     * @param string $key
167     *
168     * @return void
169     */
170    private function prepareCipher($key)
171    {
172        if (0 !== mcrypt_generic_init($this->mcrypt, $key, $this->initv)) {
173            throw new \RuntimeException('Failed to prepare mcrypt module');
174        }
175    }
176}
177