ocf-linux,将大缓冲区拆分成块< MAX_DATA_LEN

时间:2016-07-24 21:36:12

标签: encryption

我在openwrt应用程序中使用ocf-linux,并且在CRYPTO_AES_CBC模式下遇到OCF CRYPTO_MAX_DATA_LEN(64K-1)和E2BIG错误。

因此,我需要将输入缓冲区拆分为块< MAX_DATA_LEN并单独处理块并将生成的明文/密文块组合成一个大输出缓冲区。

Google的搜索结果很少,而且没有关于此问题的代码。维基百科表明,通过将之前的iv提供给下一个块操作,可以实现这一点:

https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29

问题/ POINT:

  1. 这可以使用ocf-linux吗?

  2. 有没有人遇到/解决了这个问题并且有(伪)代码=(最佳实践)要分享以保存我重新发明=轮子? 3 - 任何人都可以在下面看到我的代码有任何问题吗?

  3. 我当前的解密函数(适用于大小< MAX_DATA_LEN)如下:

    我观察到的是除了第一个具有初始iv的块以外的所有解密数据。尽管使用维基百科的算法,我怀疑前一个块的后续iv在某种程度上是不正确的。

    #define       AES_CHUNK_SIZE    0xFFE0
    #define       IV_SIZE           128 // bits
    
    int aes_decrypt(struct cryptodev_ctx* ctx, const void* iv, const void* ciphertext, void* plaintext, size_t size)
    {
        struct crypt_op cryp;
        void* p;
    
        /* check plaintext and ciphertext alignment */
        if (ctx->alignmask) {
                p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
                if (plaintext != p) {
                  DebugPrintf( DEBUG_ERR, "%s: plaintext is not aligned\n", __func__);
                  return ERROR;
                }
    
                p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
                if (ciphertext != p) {
                  DebugPrintf( DEBUG_ERR, "%s: ciphertext is not aligned\n", __func__);
                  return ERROR;
                }
        }
    
        memset(&cryp, 0, sizeof(cryp));
    
        /* Decrypt ciphertext to plaintext */
        cryp.ses = ctx->sess.ses;
        cryp.len = size;
        cryp.src = (void*)ciphertext;
        cryp.dst = plaintext;
        cryp.iv = (void*)iv;
        cryp.op = COP_DECRYPT;
        if ( size <= CRYPTO_MAX_DATA_LEN ) {
                if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
                  DebugPrintf( DEBUG_ERR, "%s: ioctl(CIOCCRYPT)\n", __func__);
                  return ERROR;
                }
        } else {
                unsigned int i, remainder;
                cryp.len = AES_CHUNK_SIZE;
                remainder = size % AES_CHUNK_SIZE;
                char byte;
                DebugPrintf( DEBUG_ERR, "%s: Decrypting large block AES_CHUNK_SIZE: %x size: %x remainder: %x\n",
                        __func__,
                        (unsigned int) AES_CHUNK_SIZE,
                        (unsigned int) size,
                        remainder );
                for (i = 0; i < (size / AES_CHUNK_SIZE); i++) {
                        DebugPrintf( DEBUG_ERR, "%s: Decrypting chunk: %x\n", __func__, i );
                        if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
                          DebugPrintf( DEBUG_ERR, "%s: ioctl(CIOCCRYPT)\n", __func__);
                          return ERROR;
                        }
                        // Print first 32 bytes of decrypted chunk data
                        DebugPrintf( DEBUG_ERROR, "Decrypted data, Section offset: %x\n", (unsigned int) (AES_CHUNK_SIZE * i) );
                        for (int j = 0; j < 32 ; j++) {
                                byte = cryp.dst[AES_CHUNK_SIZE * i + j];
                                DebugPrintf( DEBUG_ERROR, "%x ", byte);
                        }
                        DebugPrintf( DEBUG_ERROR, "\n" );
                        cryp.src += AES_CHUNK_SIZE;
                        cryp.dst += AES_CHUNK_SIZE;
                        cryp.iv = cryp.src - (IV_SIZE / 8);
                }
                if ( remainder ) {
                        DebugPrintf( DEBUG_ERR, "%s: Decrypting last chunk: %x\n", __func__, i );
                        cryp.len = remainder;
                        if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
                          DebugPrintf( DEBUG_ERR, "%s: ioctl(CIOCCRYPT)\n", __func__);
                          return ERROR;
                        }
                        DebugPrintf( DEBUG_ERROR, "Decrypted data, Section offset: %x\n", (unsigned int) (AES_CHUNK_SIZE * i) );
                        for (int j = 0; j < 32 ; j++) {
                                byte = cryp.dst[AES_CHUNK_SIZE * i + j];
                                DebugPrintf( DEBUG_ERROR, "%x ", byte);
                        }
                        DebugPrintf( DEBUG_ERROR, "\n" );
                }
                }
        }
    return OK;
    }
    

2 个答案:

答案 0 :(得分:1)

解决:问题是密文和明文缓冲区是相同的,并且明文块n覆盖了密文n,包括解密块n + 1所需的IV。工作代码如下:

我很感激如何消除第二份IV副本的反馈。

int aes_decrypt(struct cryptodev_ctx* ctx, const void* iv, const void* ciphertext, void* plaintext, size_t size)
{
    struct crypt_op cryp;
    void* p;

    /* check plaintext and ciphertext alignment */
    if (ctx->alignmask) {
            p = (void*)(((unsigned long)plaintext + ctx->alignmask) & ~ctx->alignmask);
            if (plaintext != p) {
              return ERROR;
            }

            p = (void*)(((unsigned long)ciphertext + ctx->alignmask) & ~ctx->alignmask);
            if (ciphertext != p) {
              return ERROR;
            }
    }

    memset(&cryp, 0, sizeof(cryp));

    /* Decrypt ciphertext to plaintext */
    cryp.ses = ctx->sess.ses;
    cryp.len = size;
    cryp.src = (void*)ciphertext;
    cryp.dst = plaintext;
    cryp.iv = (void*)iv;
    cryp.op = COP_DECRYPT;
    if ( size <= CRYPTO_MAX_DATA_LEN ) {
            if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
              return ERROR;
            }
    } else {
            unsigned int i, remainder;
            cryp.len = AES_CHUNK_SIZE;
            remainder = size % AES_CHUNK_SIZE;
            char this_iv[IV_SIZE / 8];
            char next_iv[IV_SIZE / 8];

            for (i = 0; i < (size / AES_CHUNK_SIZE); i++) {
                    // For case where ciphertext and plaintext use same buffer (ciphertext overwritten by plaintext)
                    //   need to copy the last block of ciphertext from CHUNK n
                    //   to use as IV for chunk n + 1
                    memcpy( next_iv, cryp.src + AES_CHUNK_SIZE - (IV_SIZE / 8), IV_SIZE / 8);
                    if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
                      return ERROR;
                    }

                    cryp.src += AES_CHUNK_SIZE;
                    cryp.dst += AES_CHUNK_SIZE;
                    memcpy( this_iv, next_iv, IV_SIZE / 8);
                    cryp.iv = (void*) &this_iv;
            }
            if ( remainder ) {
                    cryp.len = remainder;
                    if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
                      return ERROR;
                    }
            }
    }
    return OK;
}

的问候; 比尔罗斯

答案 1 :(得分:0)

在ECB以外的任何模式下,对于每次不同的加密调用,IV应始终保持新鲜。否则,IV可以从密文中猜出,并且加密的安全性受到损害。

如果在加密时,当前块的IV与另一个块的IV一致,则安全性将减弱,因此长度限制。