Мое приложение bb10 отправлено 3DES-ECB
зашифрованные данные в бэкэнд (PHP)
Бэкэнд PHP
public static function encrypt3Des($data, $key)
{
//Generate a key from a hash
$key = md5(utf8_encode($key), true);
//Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
//Pad for PKCS7
$blockSize = mcrypt_get_block_size('tripledes', 'ecb');
$len = strlen($data);
$pad = $blockSize - ($len % $blockSize);
$data = $data.str_repeat(chr($pad), $pad);
//Encrypt data
$encData = mcrypt_encrypt('tripledes', $key, $data, 'ecb');
return base64_encode($encData);
}
public static function decrypt3Des($data, $secret)
{
//Generate a key from a hash
$key = md5(utf8_encode($secret), true);
//Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
$data = base64_decode($data);
$data = mcrypt_decrypt('tripledes', $key, $data, 'ecb');
$block = mcrypt_get_block_size('tripledes', 'ecb');
$len = strlen($data);
$pad = ord($data[$len-1]);
return substr($data, 0, strlen($data) - $pad);
}
Клиент Blackberry 10
/// cipherservice.hpp ///
#pragma once
#include <QObject>
#include <hudes.h>
#include <hugse56.h>
class CipherService : public QObject {
Q_OBJECT
public:
virtual ~CipherService();
CipherService(QString key);
QString encryptTDES(QString message);
QString decryptTDES(QString message);
private:
void initCipher(QString key);
void destroyCipher();
sb_GlobalCtx huGlobalContext;
sb_Context huContext;
sb_Key huKey;
sb_Params huParams;
};
/// cipherservice.cpp ///
#include "cipherservice.hpp"
#include <huctx.h>
#define TO_HEXSTR(code) ("0x" + QString("%1").arg(code, 0, 16).toUpper())
CipherService::CipherService(QString key)
: QObject() {
initCipher(key);
}
CipherService::~CipherService() {
destroyCipher();
}
void CipherService::initCipher(QString key) {
int rc = hu_GlobalCtxCreateDefault(&huGlobalContext);
LOGD << "hu_GlobalCtxCreateDefault return code = " << TO_HEXSTR(rc);
rc = hu_RegisterSbg56DES(huGlobalContext);
LOGD << "hu_RegisterSbg56DES return code = " << TO_HEXSTR(rc);
rc = hu_InitSbg56(huGlobalContext);
LOGD << "hu_InitSbg56 return code = " << TO_HEXSTR(rc) << " (0xF00D means already initialized so ignore it)";
rc = hu_DESParamsCreate(USED_SB_DES, SB_DES_ECB, SB_DES_PARITY_OFF, SB_DES_WEAK_KEY_OFF,
NULL, NULL, &huParams, huGlobalContext);
LOGD << "hu_DESParamsCreate return code = " << TO_HEXSTR(rc);
QByteArray resultKey = QCryptographicHash::hash(key.toUtf8().constData(), QCryptographicHash::Md5);
resultKey.append(resultKey.mid(0, 8));
LOGD << "key=" << resultKey.toBase64();
unsigned char* keyBuf = reinterpret_cast<unsigned char*>(resultKey.data());
size_t keyBufLen = SB_DES_KEY_SIZE;
rc = hu_DESKeySet(huParams, keyBufLen, keyBuf, keyBufLen, keyBuf, keyBufLen, keyBuf, &huKey, huGlobalContext);
LOGD << "hu_DESKeySet return code = " << TO_HEXSTR(rc);
const unsigned char iv[SB_DES_IV_SIZE] = {0};
rc = hu_DESBeginV2(huParams, huKey, SB_DES_ECB, SB_DES_IV_SIZE, iv, &huContext, huGlobalContext);
LOGD << "hu_DESBeginV2 return code = " << TO_HEXSTR(rc);
}
void CipherService::destroyCipher() {
if (&huContext != NULL) {
int rc = hu_DESEnd(&huContext, huGlobalContext);
LOGD << "hu_DESEnd return code = " << TO_HEXSTR(rc);
huContext = NULL;
}
}
QString CipherService::encryptTDES(QString msg) {
size_t pad = SB_DES_BLOCK_SIZE - (msg.length() % SB_DES_BLOCK_SIZE);
for (uint i = 0; i < pad; i += 1) {
msg.append(static_cast<QChar>(pad));
}
QByteArray plainBuf(msg.toUtf8());
char* cipherBuf = new char[plainBuf.length()];
LOGD << "hu_DESEncryptMsg plainBuf = " << plainBuf;
int rc = hu_DESEncrypt(huContext,
plainBuf.length(),
reinterpret_cast<const unsigned char*>(plainBuf.data()),
reinterpret_cast<unsigned char*>(cipherBuf), huGlobalContext);
QByteArray byteData((char*)cipherBuf, plainBuf.length());
QString result(byteData.toBase64());
LOGD << "hu_DESEncryptMsg length = " << plainBuf.length() << " code = " << TO_HEXSTR(rc) << " result = " << result;
return result;
}
QString CipherService::decryptTDES(QString msg) {
QByteArray cipherBuf(QByteArray::fromBase64(msg.toUtf8()));
if (cipherBuf.size() % SB_DES_BLOCK_SIZE) {
cipherBuf.resize((cipherBuf.size() / SB_DES_BLOCK_SIZE) * (SB_DES_BLOCK_SIZE));
}
LOGD << "hu_DESEncryptMsg cipherBuf = " << msg << " length = " << cipherBuf.length();
unsigned char* plainBuf = new unsigned char[cipherBuf.length() + 1](); // +1 to last \0
int rc = hu_DESDecrypt(huContext,
cipherBuf.length(),
reinterpret_cast<const unsigned char*>(cipherBuf.data()),
reinterpret_cast<unsigned char*>(plainBuf), huGlobalContext);
QByteArray byteData((char*)plainBuf, cipherBuf.length());
QString result(byteData);
if (result.length() > 0) {
size_t pad = (size_t) result[result.length() - 1].toAscii();
result = result.remove(result.length() - pad, pad);
}
LOGD << "hu_DESDecryptMsg length = " << cipherBuf.length() << " code = " << TO_HEXSTR(rc) << " result = " << result;
return result;
}
Это решение не работает, во время устранения неполадок я обнаружил 2 основных различия между реализациями PHP и BB10:
IV
и я не знаю почему, потому что ECB
режим не требует, но я не могу пройти NULL
потому что я получу код ошибкиopenssl
представлен на BB10, но его API выглядит очень ограниченным, возможно ли реализовать 3DES-ECB
с openssl
на BB10?Вопрос является ключевым. BB создает 24-байтовый ключ 3DES следующим образом:
QByteArray resultKey = QCryptographicHash::hash(key.toUtf8().constData(), QCryptographicHash::Md5);
resultKey.append(resultKey.mid(0, 8));
Это принимает key
которая является строкой, забавляется через MD%, создавая 16 байтов. Затем он добавляет первые 8 байтов вывода MD5 к нему. Это создает 24-байтовый ключ, который называется 3DES с двумя ключами, это небезопасно и должно использоваться.
Для PHP вам нужно создать ключ таким же образом.
Также обратите внимание на IV и прокладку. Как уже отмечалось, в режиме ECB не используется IV, и я неоднократно видел, как панорамирование IV снабжается режимом ECB = в основном потому, что разработчики не понимали режим ECB.
Возможно, вам лучше использовать OpenSSL в PHP, mcrypt ужасен.
Используйте некоторые шестнадцатеричные отпечатки, чтобы убедиться, что ключ и IV совпадают до шифрования.
Других решений пока нет …