代码之家  ›  专栏  ›  技术社区  ›  Brendan Long

我的AES加密/解密函数不适用于随机IVEC

  •  1
  • Brendan Long  · 技术社区  · 15 年前

    我很无聊,写了一个围绕openSSL的包装器,用更少的工作完成AES加密。如果我这样做: http://pastebin.com/V1eqz4jp (ivec=0)

    事实上,它几乎奏效了。它似乎解密了字符串的中间部分,但不是开头 或结束 :

    String is: 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
    Encrypting..
    ���l%%1u���B!
    �����`pN)�ɶ���[l�ӏ��{�Q�?�2�/�HԵ�y"�=Z�Cu����l%%1u���B!
    
    Decrypting..
    String is: �%���G*�5J�0��0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
    

    /*!
     * Simple AES
     * Brendan Long
     * March 29, 2010
     * 
     * Simplified encryption and decryption using OpenSSL's AES library.
     * Remember to compile with -lcrypto and link against the library
     * g++ (your stuff) -lcrypto simpleAes.cpp (or simpleAes.o)
     *
     * Implementation note: Using the default ivec (0) is not secure. For
     *                      the full security that AES offers, use a different
     *                      ivec each time (it does not need to be secret,
     *                      just different.
     *
     * This code is released into the public domain. Yada yada..
     * Read this for details: http://creativecommons.org/licenses/publicdomain/
     *
     * If for some reason public domain isn't good enough, you may use, alter,
     * distribute or do anything else you want with this code with no restrictions.
     */
    
    #include <openssl/aes.h>
    #include <iostream>
    #include <stdlib.h>
    #include <time.h>
    
    bool seed = true;
    
    /*!
     * Encrypts a string using AES with a 256 bit key
     * Note: If the key is less than 32 bytes, it will be null padded.
     *       If the key is greater than 32 bytes, it will be truncated
     * \param in The string to encrypt
     * \param key The key to encrypt with
     * \return The encrypted data
     */
    std::string aes_encrypt(std::string in, std::string key){
    
        // Seed the random number generator once
        if(seed){
            srand( (unsigned int) time(NULL));
            seed = false;
        }
    
        // Generate a random ivec
        unsigned char ivec[16];
        for(int i=0; i<16; i++){
            ivec[i] = (unsigned char) rand();
        }
    
         // Round up to AES_BLOCK_SIZE
        size_t textLength = ((in.length() / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
    
        // Always pad the key to 32 bits.. because we can
        if(key.length() < 32){
            key.append(32 - key.length(), '\0');
        }
    
        // Get some space ready for the output
        unsigned char *output = new unsigned char[textLength];
    
        // Generate a key
        AES_KEY *aesKey = new AES_KEY;
        AES_set_encrypt_key((unsigned char*)key.c_str(), 256, aesKey);
    
        // Encrypt the data
        AES_cbc_encrypt((unsigned char*)in.c_str(), output, in.length() + 1, aesKey, ivec, AES_ENCRYPT);
    
        // Make the data into a string
        std::string ret((char*) output, textLength);
    
        // Add the ivec to the front
        ret = std::string((char*)ivec, 16) + ret;
    
        // Clean up
        delete output;
        delete aesKey;
    
        return ret;
    }
    
    /*!
     * Decrypts a string using AES with a 256 bit key
     * Note: If the key is less than 32 bytes, it will be null padded.
     *       If the key is greater than 32 bytes, it will be truncated
     * \param in The string to decrypt
     * \param key The key to decrypt with
     * \return The decrypted data
     */
    std::string aes_decrypt(std::string in, std::string key){
    
        // Get the ivec from the front
        unsigned char ivec[16];
        for(int i=0;i<16; i++){
            ivec[i] = in[i];
        }
    
        in = in.substr(16);
    
        // Always pad the key to 32 bits.. because we can
        if(key.length() < 32){
            key.append(32 - key.length(), '\0');
        }
    
        // Create some space for output
        unsigned char *output = new unsigned char[in.length()]; 
    
        // Generate a key
        AES_KEY *aesKey = new AES_KEY;
        AES_set_decrypt_key((unsigned char*)key.c_str(), 256, aesKey); // key length is in bits, so 32 * 8 = 256
    
        // Decrypt the data
        AES_cbc_encrypt((unsigned char*)in.c_str(), output, in.length(), aesKey, ivec, AES_DECRYPT);
    
        // Make the output into a string
        std::string ret((char*) output);
    
        // Clean up
        delete output;
        delete aesKey;
    
        return ret;
    }
    
    4 回复  |  直到 15 年前
        1
  •  3
  •   Peter O. Manuel Pinto    13 年前

    在加密之前,您应该将ivec[16]保存到“output”中。 就这样。。。

        2
  •  2
  •   Steve Jessop    15 年前

    这行错了:

    std::string ret((char*) output);
    

    解密的数据没有nul终止符,因为你加密了 in.length() 字节。这就解释了最后的垃圾,而不是开始的垃圾。可能还有其他问题。

        3
  •  1
  •   Brendan Long    15 年前

    我的一个朋友发现了这个问题。我是这样做的:

    1. 生成随机数并存储在 ivec
    2. 依维柯

    问题是步骤2改变了ivec的内容。我基本上是在字符串的开头存储随机数。解决方案是添加以下内容:

    unsigned char ivec[16];
    // set ivec to random numbers
    std::string ivecString((char*) ivec, 16);
    // encrypt data
    return ivecString + encryptedData;
    
        4
  •  0
  •   Damien_The_Unbeliever    15 年前