/** * Setup the performance-optimized function for de/encrypt() * * @see Crypt_Base::_setupInlineCrypt() * @access private */ function _setupInlineCrypt() { $lambda_functions =& Crypt_Twofish::_getLambdaFunctions(); // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one. // (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit) $gen_hi_opt_code = (bool) (count($lambda_functions) < 10); // Generation of a uniqe hash for our generated code $code_hash = "Crypt_Twofish, {$this->mode}"; if ($gen_hi_opt_code) { $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); } if (!isset($lambda_functions[$code_hash])) { switch (true) { case $gen_hi_opt_code: $K = $this->K; $init_crypt = ' static $S0, $S1, $S2, $S3; if (!$S0) { for ($i = 0; $i < 256; ++$i) { $S0[] = (int)$self->S0[$i]; $S1[] = (int)$self->S1[$i]; $S2[] = (int)$self->S2[$i]; $S3[] = (int)$self->S3[$i]; } } '; break; default: $K = array(); for ($i = 0; $i < 40; ++$i) { $K[] = '$K_' . $i; } $init_crypt = ' $S0 = $self->S0; $S1 = $self->S1; $S2 = $self->S2; $S3 = $self->S3; list(' . implode(',', $K) . ') = $self->K; '; } // Generating encrypt code: $encrypt_block = ' $in = unpack("V4", $in); $R0 = ' . $K[0] . ' ^ $in[1]; $R1 = ' . $K[1] . ' ^ $in[2]; $R2 = ' . $K[2] . ' ^ $in[3]; $R3 = ' . $K[3] . ' ^ $in[4]; '; for ($ki = 7, $i = 0; $i < 8; ++$i) { $encrypt_block .= ' $t0 = $S0[ $R0 & 0xff] ^ $S1[($R0 >> 8) & 0xff] ^ $S2[($R0 >> 16) & 0xff] ^ $S3[($R0 >> 24) & 0xff]; $t1 = $S0[($R1 >> 24) & 0xff] ^ $S1[ $R1 & 0xff] ^ $S2[($R1 >> 8) & 0xff] ^ $S3[($R1 >> 16) & 0xff]; $R2^= ($t0 + $t1 + ' . $K[++$ki] . '); $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + ' . $K[++$ki] . '); $t0 = $S0[ $R2 & 0xff] ^ $S1[($R2 >> 8) & 0xff] ^ $S2[($R2 >> 16) & 0xff] ^ $S3[($R2 >> 24) & 0xff]; $t1 = $S0[($R3 >> 24) & 0xff] ^ $S1[ $R3 & 0xff] ^ $S2[($R3 >> 8) & 0xff] ^ $S3[($R3 >> 16) & 0xff]; $R0^= ($t0 + $t1 + ' . $K[++$ki] . '); $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + ' . $K[++$ki] . '); '; } $encrypt_block .= ' $in = pack("V4", ' . $K[4] . ' ^ $R2, ' . $K[5] . ' ^ $R3, ' . $K[6] . ' ^ $R0, ' . $K[7] . ' ^ $R1); '; // Generating decrypt code: $decrypt_block = ' $in = unpack("V4", $in); $R0 = ' . $K[4] . ' ^ $in[1]; $R1 = ' . $K[5] . ' ^ $in[2]; $R2 = ' . $K[6] . ' ^ $in[3]; $R3 = ' . $K[7] . ' ^ $in[4]; '; for ($ki = 40, $i = 0; $i < 8; ++$i) { $decrypt_block .= ' $t0 = $S0[$R0 & 0xff] ^ $S1[$R0 >> 8 & 0xff] ^ $S2[$R0 >> 16 & 0xff] ^ $S3[$R0 >> 24 & 0xff]; $t1 = $S0[$R1 >> 24 & 0xff] ^ $S1[$R1 & 0xff] ^ $S2[$R1 >> 8 & 0xff] ^ $S3[$R1 >> 16 & 0xff]; $R3^= $t0 + ($t1 << 1) + ' . $K[--$ki] . '; $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + ' . $K[--$ki] . '); $t0 = $S0[$R2 & 0xff] ^ $S1[$R2 >> 8 & 0xff] ^ $S2[$R2 >> 16 & 0xff] ^ $S3[$R2 >> 24 & 0xff]; $t1 = $S0[$R3 >> 24 & 0xff] ^ $S1[$R3 & 0xff] ^ $S2[$R3 >> 8 & 0xff] ^ $S3[$R3 >> 16 & 0xff]; $R1^= $t0 + ($t1 << 1) + ' . $K[--$ki] . '; $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + ' . $K[--$ki] . '); '; } $decrypt_block .= ' $in = pack("V4", ' . $K[0] . ' ^ $R2, ' . $K[1] . ' ^ $R3, ' . $K[2] . ' ^ $R0, ' . $K[3] . ' ^ $R1); '; $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(array('init_crypt' => $init_crypt, 'init_encrypt' => '', 'init_decrypt' => '', 'encrypt_block' => $encrypt_block, 'decrypt_block' => $decrypt_block)); } $this->inline_crypt = $lambda_functions[$code_hash]; }
/** * Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt * * @access private */ function inline_crypt_setup() { $lambda_functions =& Crypt_Twofish::get_lambda_functions(); $block_size = 16; $mode = $this->mode; $code_hash = "{$mode}"; if (!isset($lambda_functions[$code_hash])) { $init_cryptBlock = ' $S0 = $self->S0; $S1 = $self->S1; $S2 = $self->S2; $S3 = $self->S3; extract($self->K, EXTR_PREFIX_ALL, "K"); '; // Generating encrypt code: $_encryptBlock = ' $in = unpack("V4", $in); $R0 = $K_0 ^ $in[1]; $R1 = $K_1 ^ $in[2]; $R2 = $K_2 ^ $in[3]; $R3 = $K_3 ^ $in[4]; '; for ($ki = 7, $i = 0; $i < 8; ++$i) { $_encryptBlock .= ' $t0 = $S0[ $R0 & 0xff] ^ $S1[($R0 >> 8) & 0xff] ^ $S2[($R0 >> 16) & 0xff] ^ $S3[($R0 >> 24) & 0xff]; $t1 = $S0[($R1 >> 24) & 0xff] ^ $S1[ $R1 & 0xff] ^ $S2[($R1 >> 8) & 0xff] ^ $S3[($R1 >> 16) & 0xff]; $R2^= ($t0 + $t1 + $K_' . ++$ki . '); $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31); $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K_' . ++$ki . '); $t0 = $S0[ $R2 & 0xff] ^ $S1[($R2 >> 8) & 0xff] ^ $S2[($R2 >> 16) & 0xff] ^ $S3[($R2 >> 24) & 0xff]; $t1 = $S0[($R3 >> 24) & 0xff] ^ $S1[ $R3 & 0xff] ^ $S2[($R3 >> 8) & 0xff] ^ $S3[($R3 >> 16) & 0xff]; $R0^= ($t0 + $t1 + $K_' . ++$ki . '); $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31); $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K_' . ++$ki . '); '; } $_encryptBlock .= ' $in = pack("V4", $K_4 ^ $R2, $K_5 ^ $R3, $K_6 ^ $R0, $K_7 ^ $R1); '; // Generating decrypt code: $_decryptBlock = ' $in = unpack("V4", $in); $R0 = $K_4 ^ $in[1]; $R1 = $K_5 ^ $in[2]; $R2 = $K_6 ^ $in[3]; $R3 = $K_7 ^ $in[4]; '; for ($ki = 40, $i = 0; $i < 8; ++$i) { $_decryptBlock .= ' $t0 = $S0[$R0 & 0xff] ^ $S1[$R0 >> 8 & 0xff] ^ $S2[$R0 >> 16 & 0xff] ^ $S3[$R0 >> 24 & 0xff]; $t1 = $S0[$R1 >> 24 & 0xff] ^ $S1[$R1 & 0xff] ^ $S2[$R1 >> 8 & 0xff] ^ $S3[$R1 >> 16 & 0xff]; $R3^= $t0 + ($t1 << 1) + $K_' . --$ki . '; $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31; $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K_' . --$ki . '); $t0 = $S0[$R2 & 0xff] ^ $S1[$R2 >> 8 & 0xff] ^ $S2[$R2 >> 16 & 0xff] ^ $S3[$R2 >> 24 & 0xff]; $t1 = $S0[$R3 >> 24 & 0xff] ^ $S1[$R3 & 0xff] ^ $S2[$R3 >> 8 & 0xff] ^ $S3[$R3 >> 16 & 0xff]; $R1^= $t0 + ($t1 << 1) + $K_' . --$ki . '; $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31; $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K_' . --$ki . '); '; } $_decryptBlock .= ' $in = pack("V4", $K_0 ^ $R2, $K_1 ^ $R3, $K_2 ^ $R0, $K_3 ^ $R1); '; // Generating mode of operation code: switch ($mode) { case CRYPT_TWOFISH_MODE_ECB: $encrypt = ' $ciphertext = ""; $text = $self->_pad($text); $plaintext_len = strlen($text); for ($i = 0; $i < $plaintext_len; $i+= ' . $block_size . ') { $in = substr($text, $i, ' . $block_size . '); ' . $_encryptBlock . ' $ciphertext.= $in; } return $ciphertext; '; $decrypt = ' $plaintext = ""; $text = str_pad($text, strlen($text) + (' . $block_size . ' - strlen($text) % ' . $block_size . ') % ' . $block_size . ', chr(0)); $ciphertext_len = strlen($text); for ($i = 0; $i < $ciphertext_len; $i+= ' . $block_size . ') { $in = substr($text, $i, ' . $block_size . '); ' . $_decryptBlock . ' $plaintext.= $in; } return $self->_unpad($plaintext); '; break; case CRYPT_TWOFISH_MODE_CBC: $encrypt = ' $ciphertext = ""; $text = $self->_pad($text); $plaintext_len = strlen($text); $in = $self->encryptIV; for ($i = 0; $i < $plaintext_len; $i+= ' . $block_size . ') { $in = substr($text, $i, ' . $block_size . ') ^ $in; ' . $_encryptBlock . ' $ciphertext.= $in; } if ($self->continuousBuffer) { $self->encryptIV = $in; } return $ciphertext; '; $decrypt = ' $plaintext = ""; $text = str_pad($text, strlen($text) + (' . $block_size . ' - strlen($text) % ' . $block_size . ') % ' . $block_size . ', chr(0)); $ciphertext_len = strlen($text); $iv = $self->decryptIV; for ($i = 0; $i < $ciphertext_len; $i+= ' . $block_size . ') { $in = $block = substr($text, $i, ' . $block_size . '); ' . $_decryptBlock . ' $plaintext.= $in ^ $iv; $iv = $block; } if ($self->continuousBuffer) { $self->decryptIV = $iv; } return $self->_unpad($plaintext); '; break; case CRYPT_TWOFISH_MODE_CTR: $encrypt = ' $ciphertext = ""; $plaintext_len = strlen($text); $xor = $self->encryptIV; $buffer = &$self->enbuffer; if (strlen($buffer["encrypted"])) { for ($i = 0; $i < $plaintext_len; $i+= ' . $block_size . ') { $block = substr($text, $i, ' . $block_size . '); if (strlen($block) > strlen($buffer["encrypted"])) { $in = $self->_generate_xor($xor); ' . $_encryptBlock . ' $buffer["encrypted"].= $in; } $key = $self->_string_shift($buffer["encrypted"]); $ciphertext.= $block ^ $key; } } else { for ($i = 0; $i < $plaintext_len; $i+= ' . $block_size . ') { $block = substr($text, $i, ' . $block_size . '); $in = $self->_generate_xor($xor); ' . $_encryptBlock . ' $key = $in; $ciphertext.= $block ^ $key; } } if ($self->continuousBuffer) { $self->encryptIV = $xor; if ($start = $plaintext_len % ' . $block_size . ') { $buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"]; } } return $ciphertext; '; $decrypt = ' $plaintext = ""; $ciphertext_len = strlen($text); $xor = $self->decryptIV; $buffer = &$self->debuffer; if (strlen($buffer["ciphertext"])) { for ($i = 0; $i < $ciphertext_len; $i+= ' . $block_size . ') { $block = substr($text, $i, ' . $block_size . '); if (strlen($block) > strlen($buffer["ciphertext"])) { $in = $self->_generate_xor($xor); ' . $_encryptBlock . ' $buffer["ciphertext"].= $in; } $key = $self->_string_shift($buffer["ciphertext"]); $plaintext.= $block ^ $key; } } else { for ($i = 0; $i < $ciphertext_len; $i+= ' . $block_size . ') { $block = substr($text, $i, ' . $block_size . '); $in = $self->_generate_xor($xor); ' . $_encryptBlock . ' $key = $in; $plaintext.= $block ^ $key; } } if ($self->continuousBuffer) { $self->decryptIV = $xor; if ($start = $ciphertext_len % ' . $block_size . ') { $buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"]; } } return $plaintext; '; break; case CRYPT_TWOFISH_MODE_CFB: $encrypt = ' $ciphertext = ""; $buffer = &$self->enbuffer; if ($self->continuousBuffer) { $iv = &$self->encryptIV; $pos = &$buffer["pos"]; } else { $iv = $self->encryptIV; $pos = 0; } $len = strlen($text); $i = 0; if ($pos) { $orig_pos = $pos; $max = ' . $block_size . ' - $pos; if ($len >= $max) { $i = $max; $len-= $max; $pos = 0; } else { $i = $len; $pos+= $len; $len = 0; } $ciphertext = substr($iv, $orig_pos) ^ $text; $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); } while ($len >= ' . $block_size . ') { $in = $iv; ' . $_encryptBlock . '; $iv = $in ^ substr($text, $i, ' . $block_size . '); $ciphertext.= $iv; $len-= ' . $block_size . '; $i+= ' . $block_size . '; } if ($len) { $in = $iv; ' . $_encryptBlock . ' $iv = $in; $block = $iv ^ substr($text, $i); $iv = substr_replace($iv, $block, 0, $len); $ciphertext.= $block; $pos = $len; } return $ciphertext; '; $decrypt = ' $plaintext = ""; $buffer = &$self->debuffer; if ($self->continuousBuffer) { $iv = &$self->decryptIV; $pos = &$buffer["pos"]; } else { $iv = $self->decryptIV; $pos = 0; } $len = strlen($text); $i = 0; if ($pos) { $orig_pos = $pos; $max = ' . $block_size . ' - $pos; if ($len >= $max) { $i = $max; $len-= $max; $pos = 0; } else { $i = $len; $pos+= $len; $len = 0; } $plaintext = substr($iv, $orig_pos) ^ $text; $iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i); } while ($len >= ' . $block_size . ') { $in = $iv; ' . $_encryptBlock . ' $iv = $in; $cb = substr($text, $i, ' . $block_size . '); $plaintext.= $iv ^ $cb; $iv = $cb; $len-= ' . $block_size . '; $i+= ' . $block_size . '; } if ($len) { $in = $iv; ' . $_encryptBlock . ' $iv = $in; $plaintext.= $iv ^ substr($text, $i); $iv = substr_replace($iv, substr($text, $i), 0, $len); $pos = $len; } return $plaintext; '; break; case CRYPT_TWOFISH_MODE_OFB: $encrypt = ' $ciphertext = ""; $plaintext_len = strlen($text); $xor = $self->encryptIV; $buffer = &$self->enbuffer; if (strlen($buffer["xor"])) { for ($i = 0; $i < $plaintext_len; $i+= ' . $block_size . ') { $block = substr($text, $i, ' . $block_size . '); if (strlen($block) > strlen($buffer["xor"])) { $in = $xor; ' . $_encryptBlock . ' $xor = $in; $buffer["xor"].= $xor; } $key = $self->_string_shift($buffer["xor"]); $ciphertext.= $block ^ $key; } } else { for ($i = 0; $i < $plaintext_len; $i+= ' . $block_size . ') { $in = $xor; ' . $_encryptBlock . ' $xor = $in; $ciphertext.= substr($text, $i, ' . $block_size . ') ^ $xor; } $key = $xor; } if ($self->continuousBuffer) { $self->encryptIV = $xor; if ($start = $plaintext_len % ' . $block_size . ') { $buffer["xor"] = substr($key, $start) . $buffer["xor"]; } } return $ciphertext; '; $decrypt = ' $plaintext = ""; $ciphertext_len = strlen($text); $xor = $self->decryptIV; $buffer = &$self->debuffer; if (strlen($buffer["xor"])) { for ($i = 0; $i < $ciphertext_len; $i+= ' . $block_size . ') { $block = substr($text, $i, ' . $block_size . '); if (strlen($block) > strlen($buffer["xor"])) { $in = $xor; ' . $_encryptBlock . ' $xor = $in; $buffer["xor"].= $xor; } $key = $self->_string_shift($buffer["xor"]); $plaintext.= $block ^ $key; } } else { for ($i = 0; $i < $ciphertext_len; $i+= ' . $block_size . ') { $in = $xor; ' . $_encryptBlock . ' $xor = $in; $plaintext.= substr($text, $i, ' . $block_size . ') ^ $xor; } $key = $xor; } if ($self->continuousBuffer) { $self->decryptIV = $xor; if ($start = $ciphertext_len % ' . $block_size . ') { $buffer["xor"] = substr($key, $start) . $buffer["xor"]; } } return $plaintext; '; break; } $fnc_head = '$action, &$self, $text'; $fnc_body = $init_cryptBlock . 'if ($action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }'; if (function_exists('create_function') && is_callable('create_function')) { $lambda_functions[$code_hash] = create_function($fnc_head, $fnc_body); } else { eval('function ' . ($lambda_functions[$code_hash] = 'f' . md5(microtime())) . '(' . $fnc_head . ') { ' . $fnc_body . ' }'); } } $this->inline_crypt = $lambda_functions[$code_hash]; }