尝试解密 2 密钥三重 DES 的无效块填充

Posted

技术标签:

【中文标题】尝试解密 2 密钥三重 DES 的无效块填充【英文标题】:Invalid block padding trying to decrypt 2-key triple DES 【发布时间】:2012-11-06 06:11:18 【问题描述】:

我正在尝试在 C++ 中使用 crypto++ 实现 2 键三重 DES。

我的实现基于位于 here 的 crypto++ wiki 中的代码。

wiki 上的代码正确构建;运行示例程序,我可以看到它正在正确加密和解​​密。

对于我的实现,我正在尝试执行以下操作:

    用户可以运行“desimp.exe encrypt test.txt”。该程序将对 test.txt 进行加密,然后输出一个名为 test.txt.des 的加密文件。这似乎工作正常。

    用户可以运行“desimp.exe decrypt test.txt.des”,程序将解密test.txt.des并将解密后的文本输出到文件“decrypted.txt”我无法得到这个去工作。我得到的错误是“StreamTransformationFilter: invalid PKCS #7 block padding found

我相信我可能还需要在加密时将 iv 中的数据保存到文件中。它是否正确?我已经尝试过这样做,并且我认为我能够将 iv 正确保存到文件中 - 但我认为为了读取 iv 以用于解密,它需要作为数组读取8 个字节。当我尝试保存 iv 时 test.txt.iv 的文件大小为 21 个字节。如果这是正确的方法,我不确定如何进行。如果这是错误的方法,我想知道我需要做些什么不同的事情。代码如下:

#ifndef CRYPTOPP_DLL_ONLY
#define CRYPTOPP_DEFAULT_NO_DLL
#endif

#include "dll.h"
#include "rc6.h"
#include <stdio.h>  
#include <string.h>
#include <fstream>
#include <stdlib.h>
#include <string>
#include <streambuf>

USING_NAMESPACE(CryptoPP)
USING_NAMESPACE(std)

#ifdef CRYPTOPP_IMPORTS
static PNew s_pNew = NULL;
static PDelete s_pDelete = NULL;
#endif
#ifdef CRYPTOPP_DLL_ONLY

int __cdecl main(int argc, char *argv[])


    AutoSeededRandomPool prng;
    SecByteBlock key(DES_EDE2::DEFAULT_KEYLENGTH);
    prng.GenerateBlock(key, key.size());
    byte iv[DES_EDE2::BLOCKSIZE];
    prng.GenerateBlock(iv, sizeof(iv));
    string plain = "CBC Mode Test";
    string cipher, encoded, recovered;


    char *fileName = argv[1];
    char *runMode = argv[2];
    char *ivFile = argv[3];

    cout << "ARGUMENT 1: " << fileName << endl;
    cout << "ARGUMENT 2: " << runMode << endl;

    string fileNameString(fileName);
    string encryptedFileNameString = fileNameString + ".des";//add .des to the filename of the encrypted file once it's generated
    string ivString = fileNameString + ".iv";//iv file
    string runModeString(runMode);

    if (runModeString == "encrypt")
    
        ifstream t(fileName);
        string str((std::istreambuf_iterator<char>(t)),
        istreambuf_iterator<char>());
        try
        
            cout << "plain text: " << str << endl;

            CBC_Mode< DES_EDE2 >::Encryption e;
            e.SetKeyWithIV(key, key.size(), iv);

            // The StreamTransformationFilter adds padding
            //  as required. ECB and CBC Mode must be padded
            //  to the block size of the cipher.
            StringSource ss1(str, true, 
                new StreamTransformationFilter(e,
                    new StringSink(cipher)
                ) // StreamTransformationFilter      
            ); // StringSource
        
        catch(const CryptoPP::Exception& e)
        
            cerr << e.what() << endl;
            exit(1);
        
        // Pretty print
        StringSource ss2(cipher, true,
            new HexEncoder(
                new StringSink(encoded)
            ) // HexEncoder
        ); // StringSource

        cout << "cipher text: " << encoded << endl;//"encoded" is just the pretty print version of the ciphertext.
        ofstream fout(encryptedFileNameString); 
        fout << cipher; 
        fout.close();//outputs/saves the encrypted file
        cout << "Encrypted file was saved to local path as " << encryptedFileNameString << endl;

        ofstream fout2(ivString); 
        fout2 << iv; 
        fout2.close();
        cout << "iv was saved to local path as " << ivString << endl;
    

    if (runModeString == "decrypt")// USER WANTS TO DECRYPT A FILE
                   
            ifstream t2(fileName);
            string str2((istreambuf_iterator<char>(t2)),istreambuf_iterator<char>());
            cipher = str2;

        try
        
            CBC_Mode< DES_EDE2 >::Decryption d;
            d.SetKeyWithIV(key, key.size(), iv);
            // The StreamTransformationFilter removes
            //  padding as required.
            StringSource ss3(cipher, true, 
                new StreamTransformationFilter(d,
                    new StringSink(recovered)
                ) // StreamTransformationFilter
            ); // StringSource

            cout << "recovered text: " << recovered << endl;
        
        catch(const CryptoPP::Exception& e)
            
                cerr << e.what() << endl;
                exit(1);
            
        
        return 0;
    //end main

    extern "C" __declspec(dllexport) void __cdecl SetNewAndDeleteFromCryptoPP(PNew pNew, PDelete pDelete, PSetNewHandler pSetNewHandler)
    
        s_pNew = pNew;
        s_pDelete = pDelete;
    

    void * __cdecl operator new (size_t size)
    
        return s_pNew(size);
    

    void __cdecl operator delete (void * p)
    
        s_pDelete(p);
    

    #endif

【问题讨论】:

我最终实现了 Botan 加密库 - 所以我不再需要解决这个问题。 【参考方案1】:

我认为您需要在模式下使用std::ios_base::binary打开您的加密文件(用于读取和写入);否则,I/O 库将破坏看起来像行尾的序列。

【讨论】:

以上是关于尝试解密 2 密钥三重 DES 的无效块填充的主要内容,如果未能解决你的问题,请参考以下文章

具有 2 个不同密钥的 Java 三重 DES 加密

OpenSSL之3DES用法

加密算法

DES解密,ECB模式,PKCS7填充标准

基于FPGA的DES加解密系统开发(5000字详细介绍欢迎订阅)

加密解密相关内容