3DES CB Шифрование Динамический Ключ

Парень сказал мне зашифровать данные с помощью динамического ключа, сгенерированного по следующему алгоритму

timestamp  = '080717032817'
static_key =  A270AE59FF7782A2EDFE1A781BAB888D0B749D265865C288
k1 = first 5 bytes of the static key
k2 = first 3 bytes of the integer value of the timestamp
k3 = last  5 bytes of the static key
k4 = last  5 bytes of the timestamp
dynamic_key = k1k2k3k4

Он сказал, что данные должны быть дополнены:

pad to reach a multiple of the blocksize (8byte for 3DES CBC),

или же

 pad with 8 null bytes if the length of the data is already multiple of 8.

В его примере с iv='0123456789ABCDEF' он получает:

<DATA>       <TIMESTAMP>    <BASE64 CRYPTED DATA>
3408682266,080717032817,hkUIYwssDQCq0GLx/5MiZg==

Чтобы реализовать алгоритм, я написал этот класс функций

private function __encrypt($data,$parameters,$time,$convert = false)
{

$staticKey  =
$mode       = MCRYPT_MODE_CBC;
$ivi        = '0123456789ABCDEF';
$cipher     = MCRYPT_3DES;
$this->log[] = "Encrypt params: mode => {$mode}, cipher => {$cipher}, iv =>{$ivi}";
$dynamicKey =
$iv         = pack('H*', $ivi);
$this->log[] = 'Initial Vector '. var_dump($iv);
$data = $this->__padder($data,mcrypt_get_block_size($cipher, $mode),$convert);

$this->log[] = ('Data After padding: ' . $data .", length (bytes):" . strlen($data)/2);

try {
$output = mcrypt_encrypt($cipher, $dynamicKey, $data, $mode,$iv);

} catch (Exception $ex) {
debug($ex->getMessage());
throw new Exception($ex->getMessage());

}

return $output;
}

/**
* Generate a dynamic key based on a timestamp and a static key
* @param type $static_key
*/
private function __generateDynamicKey($static_key = '', $time)
{

$dateObj = DateTime::createFromFormat("ymdHis", $time);$k[1]    = substr($static_key,0,  10);

$k[2]    = substr($time,0,6);debug($k[2]);

$k[3]    = substr($static_key,strlen($static_key) - 10,  10);

$k[4]    = substr($time,strlen($time)-6,6);debug($k[4]); //last 3 bytes
$this->log[] = ("Dynamic key =>".join("",$k). ', length in bytes=>'. strlen(pack('H*', join("",$k))));

return  pack('H*', join("",$k));

}
/**
*
* @param type $data
* @param type $blockSize
* @param type $convert
* @return string
*/
private function __padder($data,$blockSize = 8,$convert = false)
{

if ($convert)
$data = Generic::strToHex($data); // hex representation of the data

$this->log[] = 'Block size of cipher: ' .$blockSize;
$this->log[] = ("Hex value before padding=>".($data) );
//Chek if the data is padded to 16 bytes
$dataBytes   = strlen($data) / 2 ; //  1 byte = 2 Hex digits
$this->log[] = "Data num. of bytes " . $dataBytes;
$rest      = $dataBytes % $blockSize;    // The num of bytes is a multiple of blockSize ?
$nearest   = ceil($dataBytes/$blockSize ) * $blockSize;
$output    = $data;
if ($rest != 0)
{
$delta       = ($nearest - $dataBytes); // in bytes
$deltaValue  = Generic::zeropad($delta, 2);
$this->log[] = ('padding value '.$deltaValue);

}
else
{
$this->log[] = ('Add 8 bytes of padding!');
$delta       = 8;
$deltaValue  = '00';

}

$output = $data . str_repeat($deltaValue, $delta);
$this->log[] = ('Hex  value after padding '. $output . ', length in bytes =>' . strlen($output)/2);

return $output;
}

public function test($clearUserCode)
{
$userCode = $this->__encrypt($clearUserCode,$provider,$time,true); //UserCode is given as string, mut be converted in hex
$this->log[] = ('UserCode Clear : ' . $clearUserCode . ', in hex: ' . Generic::strToHex($clearUserCode));
$this->log[] = ('UserCode Crypt : ' . bin2hex($userCode));
$this->log[] = ('UserCode Crypt and base64: ' . base64_encode(($userCode)));

$this->log[] = ('----------------------End encrypt UserCode part----------------------') ;
}

И, наконец, где-то

$this->test('3408682266');

которые дают мне другой результат:

UserCode Clear : 3408682266, in hex: 33343038363832323636
UserCode Crypt : 9d7e195a8d85aa7d051362dfae0042c2
UserCode Crypt and base64: nX4ZWo2Fqn0FE2LfrgBCwg==

Любой намек?

0

Решение

После поисков где-то я обнаружил, что 3DES хочет 192-битный ключ, и в некотором роде php«s mcrypt не делает это волшебным образом: вы должны дополнить ключ самостоятельно! Вот две функции, которые работают для примеров вопроса:

 /**
* Make ciphering (3DES) in pkc7 (padding with 0 or a filling value)
* key must bey 24 bytes (192 bits)
* @param type $key
* @param type $iv
* @param type $text
* @return type
*/
public static function encryptNET3DES($key,$iv,$text)

{
$td = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');

// Complete the key

$key_add = 24-strlen($key);
$key     .= substr($key,0,$key_add);// Padding the text

$block   = mcrypt_get_block_size("tripledes", "cbc");
$len     = strlen($text);
$padding = $block - ($len % $block);

$text    .= str_repeat(chr($padding),$padding);
mcrypt_generic_init ($td, $key, $iv);
$encrypt_text = mcrypt_generic ($td, $text);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $encrypt_text;

}
/**
* Decrypt 3DES encrypted data with 24-bit key
* @param type $key
* @param type $iv
* @param type $text
* @return type
*/
public static function decryptNET3DES($key,$iv,$text)

{

$td = mcrypt_module_open (MCRYPT_3DES, "", MCRYPT_MODE_CBC, "");
// Complete the key
$key_add  = 24-strlen($key);
$key      .= substr($key,0,$key_add);
mcrypt_generic_init ($td, $key, $iv);
$decrypt_text = mdecrypt_generic ($td, $text);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
//remove the padding text

$block   = mcrypt_get_block_size("tripledes", "cbc");
$packing = ord($decrypt_text{strlen($decrypt_text) - 1});
if($packing && ($packing < $block))
// Get rid of padded data
{
for($P = strlen($decrypt_text) - 1; $P >= strlen($decrypt_text) - $packing; $P--)          {
if(ord($decrypt_text{$P}) != $packing)
{
$packing = 0;
}
}
}

$decrypt_text = substr($decrypt_text,0,strlen($decrypt_text) - $packing);

return $decrypt_text;

}
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]