【问题标题】:AES/GCM with GunZip, cannot decompress correctly带有 GunZip 的 AES/GCM,无法正确解压缩
【发布时间】:2015-07-12 09:57:29
【问题描述】:

编辑我再次改写了这个问题,并提供了一个可以重现错误的最小工作示例。

我正在尝试使用 GCM 进行文件加密。我的下划线框架是 Qt。想法是这样的:

  1. 加载源文件,例如一个.jpg
  2. 在 GCM 模式下将文件加密为 PDATA
  3. 到威刚存储单字节(目前,在实际应用中,这将更多地包含 IV、原始文件名等信息)
  4. 将 ADATA 附加到加密文件

  5. 加载加密文件并提取 ADATA/PDATA/MAC

  6. 以正确的顺序将此数据提供给 AuthenticatedDecryptionFilter 并期望将解密的文件存储到 FileSink 中

我需要一个循环来遍历未加密的文件并将文件泵入 AuthenticatedEncryptionFilter,因为我需要检查 isAlive 以在实际应用程序中进行线程处理。因此我不能使用简单的流水线,必须在循环中手动遍历数据。

现在解决问题

哈希验证在下面的代码上失败(在 derypt 上抛出异常)

#include <qdebug.h>
#include <CryptoPP/cryptlib.h>
#include <CryptoPP/gcm.h>
#include <CryptoPP/aes.h>
#include <CryptoPP/filters.h>
#include <CryptoPP/files.h>
#include <CryptoPP/gzip.h>
#include <qfile.h>
#include <qfileinfo.h>


using namespace CryptoPP;
using namespace std;
int main(int argc, char *argv[])
{

    byte * key = new byte[16];
    byte * iv = new byte[16];

    memset(key, 0, 16);
    memset(iv, 0, 16);

    const int TAG_SIZE = 16;
    const int BUFFER_SIZE = 4096;

    byte keyLength = 16;
    byte blockSize = 16;

    const char * sourceFileName = "C:\\Users\\Tomas\\Documents\\Visual Studio 2013\\Projects\\testgcm\\Win32\\Debug\\source.jpg";
    const char * sourceFileName2 = "C:\\Users\\Tomas\\Documents\\Visual Studio 2013\\Projects\\testgcm\\Win32\\Debug\\source2.jpg";
    const char * destFileName = "C:\\Users\\Tomas\\Documents\\Visual Studio 2013\\Projects\\testgcm\\Win32\\Debug\\source.jpg.enc";


    try
    {

        GCM< AES >::Encryption e;
        e.SetKeyWithIV(key, keyLength, iv, blockSize);

        AuthenticatedEncryptionFilter ef(e,
            new FileSink(destFileName), false, TAG_SIZE
            ); 

        // AuthenticatedEncryptionFilter::ChannelPut
        //  defines two channels: "" (empty) and "AAD"
        //   channel "" is encrypted and authenticated
        //   channel "AAD" is authenticated


        // this is the block for ADATA
        QByteArray adata;
        adata.append((char)1);

        ef.ChannelPut("AAD", (const byte *)adata.data(), adata.size());
        ef.ChannelMessageEnd("AAD");

        FileStore fs(sourceFileName);

        int mr = 0;

        while (mr = fs.MaxRetrievable()){
            fs.TransferTo(ef, BUFFER_SIZE,"");
        }

        ef.ChannelMessageEnd("");

        // append ADATA to encrypted file

        QFile file(QString::fromStdString(destFileName));
        file.open(QIODevice::Append);

        file.write(adata);

        file.close();

        // HELP: is the encrypted file in this format now? ENC_TEXT||MAC(TAG_SIZE)||HEADER(1)


    }
    catch (CryptoPP::BufferedTransformation::NoChannelSupport& e)
    {
        // The tag must go in to the default channel:
        //  "unknown: this object doesn't support multiple channels"
        cerr << "Caught NoChannelSupport..." << endl;
        cerr << e.what() << endl;
        cerr << endl;
    }
    catch (CryptoPP::AuthenticatedSymmetricCipher::BadState& e)
    {
        // Pushing PDATA before ADATA results in:
        //  "GMC/AES: Update was called before State_IVSet"
        cerr << "Caught BadState..." << endl;
        cerr << e.what() << endl;
        cerr << endl;
    }
    catch (CryptoPP::InvalidArgument& e)
    {
        cerr << "Caught InvalidArgument..." << endl;
        cerr << e.what() << endl;
        cerr << endl;
    }

    // DECRYPTION


    try
    {

        // now extract ADATA and MAC from enc file
        QFile file(QString::fromStdString(destFileName));
        file.open(QIODevice::ReadOnly);
        file.seek(file.size() - 1);

        // ADATA
        QByteArray adata = file.read(1);

        // exract MAC

        file.seek(file.size() - 1 - TAG_SIZE);
        QByteArray mac = file.read(TAG_SIZE);

        GCM< AES >::Decryption d;
        d.SetKeyWithIV(key, keyLength, iv);


        // Object will not throw an exception
        //  during decryption\verification _if_
        //  verification fails.

        AuthenticatedDecryptionFilter df(d, new FileSink(sourceFileName2),
            AuthenticatedDecryptionFilter::MAC_AT_BEGIN |
            AuthenticatedDecryptionFilter::THROW_EXCEPTION, TAG_SIZE);


        df.ChannelPut("", (const byte*)mac.data(), mac.size());

        // The order of the following calls are important
        df.ChannelPut("AAD", (const byte*)adata.data(), adata.size());

        // open enc file
        FileStore fs(destFileName);


        // when we read the file, we dont care for the ADATA and TAG, so we omit it
        int omitSize = (adata.size() + mac.size());

        // max retrievable (for FileStore this is how many bytes are not read yet)
        int mr = 0;

        // get part without tag and footer
        while (((mr = fs.MaxRetrievable()) > omitSize)){
            mr = ((mr - omitSize) < BUFFER_SIZE) ? (mr - omitSize) : BUFFER_SIZE;
            fs.TransferTo(df, mr, "");
        }

        // we pumped teh whole filestore into df. it was supposed to be pumping it to GUnzip and then to FileSink

        // and signal this is all
        df.ChannelMessageEnd("AAD");
        df.ChannelMessageEnd("");


    }
    catch (CryptoPP::InvalidArgument& e)
    {
        cerr << "Caught InvalidArgument..." << endl;
        cerr << e.what() << endl;
        cerr << endl;
    }
    catch (CryptoPP::AuthenticatedSymmetricCipher::BadState& e)
    {
        // Pushing PDATA before ADATA results in:
        //  "GMC/AES: Update was called before State_IVSet"
        cerr << "Caught BadState..." << endl;
        cerr << e.what() << endl;
        cerr << endl;
    }
    catch (CryptoPP::HashVerificationFilter::HashVerificationFailed& e)
    {
        cerr << "Caught HashVerificationFailed..." << endl;
        cerr << e.what() << endl;
        cerr << endl;
    }




}

我怀疑我以错误的方式将信息输入解密器,但我正在关注official CryptoPP example

请帮忙, 谢谢

【问题讨论】:

  • 该模式记录在 Crypto++ wiki GCM Mode。此外,GunZip 有一个补丁,允许您在GunZip wiki 页面嵌入文件名、文件时间和 cmets。否则,您实际上没有最低限度的工作示例或任何输入或输出,因此很难帮助您解决问题。
  • 我已经为您提供了测试程序。请看一下,谢谢
  • 感谢 jww 的链接,我已阅读并提供了最小的示例。请看一下
  • 重要提示:IV 必须填写为安全随机值。重复其值将导致 GCM 安全性崩溃。

标签: c++ qt encryption crypto++ aes-gcm


【解决方案1】:

这最终是微不足道的。始终确保将 ivSize 传递给

GCM< AES >::Decryption d;
d.SetKeyWithIV(key, keyLength, iv, blockSize);

 GCM< AES >::Encryption e;
 e.SetKeyWithIV(key, keyLength, iv, blockSize);

即使它们是可选的。否则会导致解密错误

【讨论】:

  • 我也有同样的问题。你当初不是这样做的吗?
  • 不,我没有。我只通过了 3 个参数。确保这样做:e.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
  • 哦,我知道解密了。我在加密方面抛出了同样的异常,将一个指针和 iv 以及两个用于长度的整数传递给执行此操作的函数。嗯
  • 调试时变量值是否正确?也许你为某些大小或无效指针传递 0
  • 我使用了经过身份验证的加密过滤器,其中包含错误的值。我应该对其中一个参数使用十六进制编码器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-13
  • 2021-05-16
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
相关资源
最近更新 更多