c - 使用原始 rijndael 构建 PHP 扩展,正确加密/解密,但尾随额外字节

标签 c encryption cryptography php-extension

所以我刚刚开始使用原始 Rijndael 代码(现在正式称为 AES)编写 PHP 扩展。

但是代码中的某个地方似乎有一个错误,我知道它正确地加密/解密,但在输出上它向字符串添加了额外的 6 个字节,我认为这与 uint8_t 数组的转换有关到字符数组。

我没有在这里发布代码,因为它会占用一半页面,所以我将其发布到github这里:

https://github.com/Hect0rius/PHPEXT-Rijndael

我所指的主要代码如下在php_rijndael.c中(2个函数:

    /* {{{ proto resource rijndael_encrypt(string inData, string key)

使用 rijndael 加密字符串 / PHP_FUNCTION(rijndael_加密) { / 输入 */ 字符 *inData;//数据指针。 size_t inDataLen;//数据长度。 字符*键;//关键指针。 size_t keyLen;// key 长度。 zend_ulong keyBits;//位,介于 128/192/256 之间。

        /* Get Parameters from Zend */
        if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s|l", &inData, &inDataLen, &key, &keyLen, &keyBits) == FAILURE) {
        return;
        }

        /* Since rijndael takes what it needs via key bits, then we just allow the overflow of the key. */
        switch(keyBits) {
            case 128:
                if(keyLen < 16) { php_error_docref(NULL, E_WARNING, "Key length must be 16 characters long."); RETURN_FALSE; }
                break;
            case 192:
                if(keyLen < 24) { php_error_docref(NULL, E_WARNING, "Key length must be 24 characters long."); RETURN_FALSE; }
                break;
            case 256:
                if(keyLen < 32) { php_error_docref(NULL, E_WARNING, "Key length must be 32 characters long."); RETURN_FALSE; }
                break;
        }

        /* Convert from original pointers to uin8_t arrays */
        uint8_t dataU8[16];
        uint8_t keyU8[16];
        uint8_t output[16],  i = 0;
        do {
            dataU8[i] = (uint8_t)inData[i];
            keyU8[i] = (uint8_t)key[i];
            i++;
        }
        while(i < 16);

        /* Setup Rijndael stack */
        uint32_t rk[4 * (MAXNR + 1)];
        int32_t Nr = rijndaelKeySetupEnc(rk, keyU8, keyBits);

        /* Decrypt Buffer. */
        rijndaelEncrypt(rk, Nr, dataU8, output);

        /* Now return data back into a char array*/
        char outChar[16], *ptr = outChar;
        i = 0;
        do {
            ptr[i] = (char)output[i];
            i++;
        }
        while(i < 16);
        RETURN_STRING(outChar);
    }
    /* }}} */

    /* {{{ proto resource rijndael_decrypt(string inData, string key)

使用 rijndael 解密字符串 / PHP_FUNCTION(rijndael_decrypt) { / 输入 */ 字符 *inData;//数据指针。 size_t inDataLen;//数据长度。 字符*键;//关键指针。 size_t keyLen;// key 长度。 zend_ulong keyBits;//位,介于 128/192/256 之间。

        /* Get Parameters from Zend */
        if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s|l", &inData, &inDataLen, &key, &keyLen, &keyBits) == FAILURE) {
        return;
        }

        /* Since rijndael takes what it needs via key bits, then we just allow the overflow of the key. */
        switch(keyBits) {
            case 128:
                if(keyLen < 16) { php_error_docref(NULL, E_WARNING, "Key length must be 16 characters long."); RETURN_FALSE; }
                break;
            case 192:
                if(keyLen < 24) { php_error_docref(NULL, E_WARNING, "Key length must be 24 characters long."); RETURN_FALSE; }
                break;
            case 256:
                if(keyLen < 32) { php_error_docref(NULL, E_WARNING, "Key length must be 32 characters long."); RETURN_FALSE; }
                break;
        }

        /* Convert from original pointers to uin8_t arrays */
        uint8_t dataU8[16];
        uint8_t keyU8[16];
        uint8_t output[16],  i = 0;
        do {
            dataU8[i] = (uint8_t)inData[i];
            keyU8[i] = (uint8_t)key[i];
            i++;
        }
        while(i < 16);

        /* Setup Rijndael Stack */
        uint32_t rk[4 * (MAXNR + 1)];
        int32_t Nr = rijndaelKeySetupDec(rk, keyU8, keyBits);

        /* Decrypt input uint8_t array */
        rijndaelDecrypt(rk, Nr, dataU8, output);

        /* Convert data back to a char */
        char outChar[16], *ptr = outChar;
        i = 0;
        do {
            ptr[i] = (char)output[i];
            i++;
        }
        while(i < 16);
        RETURN_STRING(ptr);
    }
    /* }}} */

    #endif /* HAVE_RIJNDAEL */

我只是猜测它正确地解密了加密的缓冲区,因为它输出回全零,这是 test.php 文件:

最佳答案

您正在看到填充。

AES(和 Rijndael)是 block 密码,因此以 block 的形式处理数据,AES 为 16 字节。

如果输入不是 block 大小的精确倍数,则需要将一些填充添加到要加密的数据中,并在解密时删除。最常见的填充是 PKCS#7然而有些实现是脑死亡的,不支持 PKCS#7,有时使用空填充,不支持加密二进制数据。

注意:PHP mcrypt 实现不支持标准 PKCS#7(née PKCS#5)填充,仅支持甚至不能与二进制数据一起使用的非标准空填充。

关于c - 使用原始 rijndael 构建 PHP 扩展,正确加密/解密,但尾随额外字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44591397/

相关文章:

c - 找到网格上两点之间最自然的路线

c - __attribute__((section ("name"))) 用法?

node.js - Node rsa : InvalidAsn1Error: encoding too long

使用 RSA 进行 Java AES key 交换期间抛出 java.security.InvalidKeyException

node.js - Nodejs中字节转十六进制和十六进制转字节

c - 如何将这些数字存储在 C 中?

go - 导入字符串 RSA 公钥以在 Go 中使用 RSA 加密

c++ - 随机排列中第 n 项的高效计算

c - libsodium crypto_stream_salsa20_xor 的相同输入和输出缓冲区

c - glUniformMatrix4fv - 无效操作