【问题标题】:BlackBerry 10, 3DES-ECB implementation黑莓 10、3DES-ECB 实施
【发布时间】: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 实现之间的两个主要区别:

问题

  • 是否可以在 BlackBerry10 Cascades 上使用不同的密钥长度?
  • 那里使用的 crypt 库是什么?是 QNX 的吗?
  • 我看到BB10上有openssl,但是它的API看起来很有限,是否可以在BB10上实现3DES-ECBopenssl

链接

【问题讨论】:

  • 最好不要使用 PHP mcrypt,它是废弃软件,多年未更新,不支持标准 PKCS#7(née PKCS#5)填充,仅支持非标准空填充甚至不能用于二进制数据。 mcrypt 有许多出色的 bugs 可以追溯到 2003 年。不推荐使用的 mcrypt-extension 将在 PHP 7.2 中删除。

标签: php openssl blackberry-10 blackberry-cascades 3des


【解决方案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 需要。
猜你喜欢
  • 2016-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 2015-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多