黑莓 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-ECBopenssl

链接

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 实施的主要内容,如果未能解决你的问题,请参考以下文章

Oracle云应用版本10实施培训

98份 项目管理实施规划实施计划书实施方案实施细则

DATAGUARD实施文档

项目管理合集丨实施规划丨实施计划书丨实施方案丨实施细则WordPPT,可下载

数据治理的10个实践

数据治理的10个实践