Skip to content

Commit 505c21d

Browse files
committed
New abstract class that makes some of the DES key
processing logic shareable across implementations
1 parent 10e4c1e commit 505c21d

1 file changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
/**
3+
* Robin NTLM
4+
*
5+
* @copyright 2015 Robin Powered, Inc.
6+
* @link https://robinpowered.com/
7+
*/
8+
9+
namespace Robin\Ntlm\Crypt\Des;
10+
11+
use SplFixedArray;
12+
13+
/**
14+
* {@inheritDoc}
15+
*
16+
* Provides an abstraction for common NTLM required operations, such as key
17+
* expansion and normalization.
18+
*/
19+
abstract class AbstractDesEncrypter implements DesEncrypterInterface
20+
{
21+
22+
/**
23+
* Properties
24+
*/
25+
26+
/**
27+
* Whether or not to expand and normalize the key before encrypting.
28+
*
29+
* @type bool
30+
*/
31+
private $expand_and_normalize_keys;
32+
33+
34+
/**
35+
* Methods
36+
*/
37+
38+
/**
39+
* Constructor
40+
*
41+
* @param bool $expand_and_normalize_keys Whether or not to expand and
42+
* normalize the key before encrypting.
43+
*/
44+
public function __construct($expand_and_normalize_keys = true)
45+
{
46+
$this->expand_and_normalize_keys = $expand_and_normalize_keys;
47+
}
48+
49+
/**
50+
* Process a key for DES encryption.
51+
*
52+
* Optionally performs an expansion and normalization process to the key.
53+
*
54+
* @param string $raw_key The raw key.
55+
* @return string The processed key.
56+
*/
57+
protected function processKey($raw_key)
58+
{
59+
$key = $raw_key;
60+
61+
if ($this->expand_and_normalize_keys) {
62+
$key = self::expand56BitKeyTo64BitKey($key, true);
63+
}
64+
65+
return $key;
66+
}
67+
68+
/**
69+
* Expands a 56-bit key to a full 64-bit key for DES encryption.
70+
*
71+
* @link http://php.net/manual/en/ref.hash.php#84587 Implementation basis.
72+
* @link https://github.com/jclulow/node-smbhash/blob/edc48e2b/lib/common.js
73+
* Inspired by Joshua Clulow's work.
74+
* @param string $string_key The 56-bit key to expand.
75+
* @param bool $set_parity Whether or not to set parity for each byte.
76+
* @return string The expanded key.
77+
*/
78+
private static function expand56BitKeyTo64BitKey($string_key, $set_parity = true)
79+
{
80+
$byte_array_56 = new SplFixedArray(7);
81+
$byte_array_64 = new SplFixedArray(8);
82+
$key_64bit = '';
83+
84+
// Get the byte value of each ASCII character in the string
85+
for ($i = 0; $i < $byte_array_56->getSize(); $i++) {
86+
$byte_array_56[$i] = isset($string_key[$i]) ? ord($string_key[$i]) : 0;
87+
}
88+
89+
$byte_array_64[0] = $byte_array_56[0] & 254;
90+
$byte_array_64[1] = ($byte_array_56[0] << 7) | ($byte_array_56[1] >> 1);
91+
$byte_array_64[2] = ($byte_array_56[1] << 6) | ($byte_array_56[2] >> 2);
92+
$byte_array_64[3] = ($byte_array_56[2] << 5) | ($byte_array_56[3] >> 3);
93+
$byte_array_64[4] = ($byte_array_56[3] << 4) | ($byte_array_56[4] >> 4);
94+
$byte_array_64[5] = ($byte_array_56[4] << 3) | ($byte_array_56[5] >> 5);
95+
$byte_array_64[6] = ($byte_array_56[5] << 2) | ($byte_array_56[6] >> 6);
96+
$byte_array_64[7] = $byte_array_56[6] << 1;
97+
98+
foreach ($byte_array_64 as $byte_val) {
99+
// Optionally set parity for each byte
100+
$byte_val = $set_parity ? self::setParityBit($byte_val) : $byte_val;
101+
102+
$key_64bit .= chr($byte_val);
103+
}
104+
105+
return $key_64bit;
106+
}
107+
108+
/**
109+
* Set an odd parity bit for a given byte, in least-significant position.
110+
*
111+
* @param int $byte An 8-bit byte value.
112+
* @return int An 8-bit byte value.
113+
*/
114+
private static function setParityBit($byte)
115+
{
116+
$parity = 1;
117+
118+
for ($i = 1; $i < 8; $i++) {
119+
$parity = ($parity + (($byte >> $i) & 1)) %2;
120+
}
121+
122+
$byte = $byte | ($parity & 1);
123+
124+
return $byte;
125+
}
126+
}

0 commit comments

Comments
 (0)