黑莓 10、3DES-ECB 实施
Posted
技术标签:
【中文标题】黑莓 10、3DES-ECB 实施【英文标题】:BlackBerry 10, 3DES-ECB implementation 【发布时间】:2017-11-19 09:01:15 【问题描述】:简介
我的 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);
黑莓 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;
问题
此解决方案不起作用,在故障排除过程中,我发现 PHP 和 BB10 实现之间的两个主要区别:
BB10 仅使用 8 字节密钥,PHP 使用 24 字节密钥SB_DES_KEY_SIZE == 8
mcrypt_get_key_size('tripledes', 'ecb') == 24
BB10 需要IV
,我不知道为什么,因为ECB
模式不需要它,但我无法通过NULL
,因为我会得到错误代码
问题
是否可以在 BlackBerry10 Cascades 上使用不同的密钥长度? 那里使用的 crypt 库是什么?是 QNX 的吗? 我看到BB10上有openssl
,但是它的API看起来很有限,是否可以在BB10上实现3DES-ECB
和openssl
?
链接
PHP 游乐场 http://sandbox.onlinephpfunctions.com/code/8b33cdf24983af8e1f506a62b69c4504e05176d9 BB10 文档https://developer.blackberry.com/native/reference/core/com.qnx.doc.crypto.lib_ref/topic/manual/intro.html【问题讨论】:
最好不要使用 PHP mcrypt,它是废弃软件,多年未更新,不支持标准 PKCS#7(née PKCS#5)填充,仅支持非标准空填充甚至不能用于二进制数据。 mcrypt 有许多出色的 bugs 可以追溯到 2003 年。不推荐使用的 mcrypt-extension 将在 PHP 7.2 中删除。 【参考方案1】:问题是关键。 BB 像这样创建 24 字节的 3DES 密钥:
QByteArray resultKey = QCryptographicHash::hash(key.toUtf8().constData(), QCryptographicHash::Md5);
resultKey.append(resultKey.mid(0, 8));
它采用key
,它是一个字符串,通过 MD% 创建 16 字节来玩弄它。然后它将 MD5 输出的前 8 个字节附加到它。这会创建一个 24 字节的密钥,即所谓的双密钥 3DES,这是不安全的,应该使用。
对于 PHP,您需要以相同的方式创建密钥。
还要注意IV和padding。如前所述,ECB 模式不使用 IV,而且我一次又一次地看到泛 IV 被提供给 ECB 模式,=通常是因为开发人员不了解 ECB 模式。
在 PHP 中使用 OpenSSL 可能会更好,mcrypt 太可怕了。
在加密之前使用一些十六进制打印来验证密钥和 IV 是否相同。
【讨论】:
感谢您的回答,一般来说: 1. 重要的一点是我无法更改 PHP 后端,因为我没有控制它(我只是使用沙箱逐步比较实现)。 2. 关于安全性的好点,但这里是一样的,我不能改变它。 技术上: 1. 我不能将NULL
作为IV
传递到BB10 端,因为在hu_DESBeginV2
调用时会出错。 2. 我尝试将24
字节密钥传递给hu_DESKeySet
,并且还返回了错误代码(它只接受 8 字节密钥) 3. 我在加密之前比较了密钥和数据,它们在 PHP 和BB10
1.当使用 ECB 模式时,不要传递 IV。 2. 将它们添加到十六进制的问题以及示例输入和输出中。简而言之,如果您使用 ECB 模式为两个 3DES 实现提供相同的密钥和数据,并使用相同的填充方法,则加密结果将是相同的。
如果我不通过 IV,我会得到错误代码SB_ERR_NULL_IV
,根据bb10 doc ECB 的 IV 被忽略。顺便说一句,same padding method
是什么意思?
有不同的padding methods。需要填充,因为要加密的输入必须是块大小的倍数(DES:8 字节,AES:16 字节)。如果输入不是总是的倍数,则必须在加密之前填充输入,并在解密后移除填充。有些模式不需要填充,但 ECB 和 CBC 需要。以上是关于黑莓 10、3DES-ECB 实施的主要内容,如果未能解决你的问题,请参考以下文章