所以,我正在尝试将一段C ++代码翻译成php。 C ++来自外部资源,至少可以说我缺乏对C ++和解密的了解。
源C ++是:
void parser_t::decrypt(buffer_t &replay_data, const unsigned char *key_data) {
/*\
|*| Performs an in place decryption of the replay using the given key.
|*| The decryption is a (broken) variant of CBC decryption and is performed as follows:
|*| -# Set the variable previous_block (with size of 16 bytes) to 0
|*| -# Decrypt a block with the given key
|*| -# XOR the block with the previous (decrypted) block
|*| -# Go back to step 2, until there are no more blocks.
\*/
BF_KEY key = {{0}};
BF_set_key(&key, 16, key_data);
const int block_size = 8;
size_t padding_size = (block_size - (replay_data.size() % block_size));
if (padding_size != 0) {
size_t required_size = replay_data.size() + padding_size;
replay_data.resize(required_size, 0);
}
unsigned char previous[block_size] = {0};
for (auto it = replay_data.begin(); it != replay_data.end(); it += block_size) {
unsigned char decrypted[block_size] = { 0 };
BF_ecb_encrypt(reinterpret_cast<unsigned char*>(&(*it)), decrypted, &key, BF_DECRYPT);
std::transform(previous, previous + block_size, decrypted, decrypted, std::bit_xor<unsigned char>());
std::copy_n(decrypted, block_size, previous);
std::copy_n(decrypted, block_size, reinterpret_cast<unsigned char*>(&(*it)));
}
if (padding_size != 0) {
size_t original_size = replay_data.size() - padding_size;
replay_data.resize(original_size, 0);
}
}
到目前为止我得到了什么:
function decrypt($data){ // $data is a encrypted string
$key = array(0xDE, <.....>, 0xEF); // (16 entries in the array)
//BF_KEY key = {{0}}; // ?
//BF_set_key(&key, 16, key_data); // ?
$block_size = 8;
$padding_size = ($block_size - (strlen($data) % $block_size));
if ($padding_size != 0) {
$required_size = strlen($data) + $padding_size;
//replay_data.resize(required_size, 0);
// Seems unnecessary in php? string lengths are pretty dynamic.
}
$keyString = '';
for($i = 0; $i < count($key); $i++){
$keyString .= chr($key[$i]);
}
$output = '';
for ($i = 0; $i < stlen($data); $i += $block_size) {
$char = array(0, 0, 0, 0, 0, 0, 0, 0); // ?
$decrypted_piece = mcrypt_decrypt(MCRYPT_BLOWFISH, $keyString, $data, "cbc"); // ??
// And this is where I completely get lost.
$output = transform($in, $start, $end, $in2);
}
}
function transform($in, $start, $end, $in2){
$out = ''; // Yea, that won't work...
for($x = $start; $x < $end; $x++){
$out[$x] = $in[$x] ^ $in2[$x];
}
return $output
}
我意识到我基本上要求你们为我做点什么,但我真的被那个for (auto it...
的内容所困扰。
真正帮助我的提示/解释将是:
BF_ecb_encrypt
做什么? (在伪代码甚至是PHP?)(用手指拍打自己。“不要求成品”)transform
?{{0}}
,BF_set_key(&key, 16, key_data);
?reinterpret_cast<unsigned char*>(&(*it))
?我确实看过这些文档页面,但无济于事:
full source is available on github。
此特定代码来自src/parser.cpp
答案 0 :(得分:2)
原始代码正在进行的“CBC解密的破坏变体”可以等同地描述为ECB解密,然后(累积地)将每个明文块与前一个明文块进行异或。
对于XOR,您不需要任何花哨的东西:PHP bitwise XOR operator可以对字符串进行操作。
因此,您的C ++代码的简单PHP版本可能如下所示(警告:未经测试的代码):
function decrypt( $ciphertext, $key ) {
$plaintext = mcrypt_decrypt( MCRYPT_BLOWFISH, $key, $ciphertext, "ecb" );
$block_size = 8; // Blowfish block size = 64 bits = 8 bytes
$blocks = str_split( $plaintext, $block_size );
$previous = str_repeat( "\0", $block_size );
foreach ( $blocks as &$block ) {
$block ^= $previous;
$previous = $block;
}
return implode( $blocks );
}
请注意,我没有为截断的最后一个块实现任何填充;关于原始代码中的填充处理,有一些非常,并且我看不出它如何能够正确解密长度不能被8字节整除的消息。 (实际上是吗?)我只是选择忽略所有内容并假设消息长度可以被块大小整除,而不是试图猜测它到底发生了什么以及如何将其转换为PHP。
答案 1 :(得分:2)
在这种情况下BF_ecb_encrypt做了什么?
BF_ecb_encrypt()是使用河豚加密的功能。 PHP等价物(如之前由Ilmari Karonen提到的)是$plaintext = mcrypt_decrypt( MCRYPT_BLOWFISH, $key, $ciphertext, "ecb" );
什么是reinterpret_cast(&amp;(* it))?
BF_ecb_encrypt()期望它的第一个参数是unsigned char *。 reinterpret_cast<unsigned char*>(&(*it))
是一个类型转换,将'it'转换为unsigned char *。 'it'是未指定类型的迭代器(至少在提供的代码中),关键字'auto'用于自动将'it'初始化为正确的类型。然后使用reinterpret_cast<unsigned char*>(&(*it))
自动将其转换为unsigned char *。
什么是{{0}},BF_set_key(&amp; key,16,key_data);?
这用于初始化BF_KEY'key',然后使用key_data的值设置密钥。这没有PHP等价物,mcrypt将在内部设置密钥。
我是否正确转换了转换?
从外观上看,C ++版本以奇怪的方式处理填充。这可能是故意将破解尝试。除非您完全理解原始C ++的算法 - 不仅仅是加密算法,而且还包括正在使用的完整过程,包括加密前后加密,否则转换为PHP是不可能的。
您是否考虑使用现有的C / C ++代码而不是转换为PHP来进行简单的PHP扩展?这应该是非常直接的,比将更复杂的算法从C ++转换为PHP要容易得多。现有代码可以或多或少地被复制粘贴到扩展中,buffer_t &replay_data
可能被注册为PHP资源。
答案 2 :(得分:0)
这会有用吗,使用php-cpp库(参见http://www.php-cpp.com):
/**
* Decrypt function made accessible from PHP
*/
/**
* Dependencies
*/
#include <phpcpp.h>
#include <openssl/blowfish.h>
#include <algorithm>
/**
* Define buffer_t to be a vector
*/
typedef std::vector<uint8_t> buffer_t;
/**
* Function that should be ported to PHP
* @param data
* @param key_data
*/
static void decrypt(std::string &replay_data, const unsigned char *key_data) {
/*\
|*| Performs an in place decryption of the replay using the given key.
|*| The decryption is a (broken) variant of CBC decryption and is performed as follows:
|*| -# Set the variable previous_block (with size of 16 bytes) to 0
|*| -# Decrypt a block with the given key
|*| -# XOR the block with the previous (decrypted) block
|*| -# Go back to step 2, until there are no more blocks.
\*/
BF_KEY key = {{0}};
BF_set_key(&key, 16, key_data);
const int block_size = 8;
size_t padding_size = (block_size - (replay_data.size() % block_size));
if (padding_size != 0) {
size_t required_size = replay_data.size() + padding_size;
replay_data.resize(required_size, 0);
}
unsigned char previous[block_size] = {0};
for (auto it = replay_data.begin(); it != replay_data.end(); it += block_size) {
unsigned char decrypted[block_size] = { 0 };
BF_ecb_encrypt(reinterpret_cast<unsigned char*>(&(*it)), decrypted, &key, BF_DECRYPT);
std::transform(previous, previous + block_size, decrypted, decrypted, std::bit_xor<unsigned char>());
std::copy_n(decrypted, block_size, previous);
std::copy_n(decrypted, block_size, reinterpret_cast<unsigned char*>(&(*it)));
}
if (padding_size != 0) {
size_t original_size = replay_data.size() - padding_size;
replay_data.resize(original_size, 0);
}
}
/**
* The PHP function that will take care of this
* @param parameters
* @return Value
*/
static Php::Value php_decrypt(Php::Parameters ¶ms)
{
// check number of parameters
if (params.size() != 2) throw Php::Exception("2 parameters expected");
// read in the parameters
std::string replay_data = params[0];
std::string key_data = params[1];
// decrypt it
decrypt(replay_data, (const unsigned char *)key_data.c_str());
// return the result
return replay_data;
}
/**
* Symbols are exported according to the "C" language
*/
extern "C"
{
// export the "get_module" function that will be called by the Zend engine
PHPCPP_EXPORT void *get_module()
{
// create extension
static Php::Extension extension("my_decrypt","1.0");
// add custom function
extension.add("my_decrypt", php_decrypt);
// return the extension module
return extension.module();
}
}
您可以使用以下命令编译代码:
g ++ -std = c ++ 11 -fic -shared my_decrypt.cpp -o my_decrypt.so -lphpcpp
my_descript.so应该复制到PHP扩展目录,并且应该在你的php.ini中添加“extension = my_decrypt.so”行。