Home > Enterprise >  decrypting cipher results in missing letters
decrypting cipher results in missing letters

Time:01-03

I have a python endpoint that encrypts string using AES cbc mode and returns it to the client software written in c (in a hex space separated format ) The link for the c repo


std::vector<unsigned char> cipher_as_chars(std::string cipher) 
{
    std::istringstream strm{cipher};
    strm >> std::hex;
    std::vector<unsigned char> res;
    res.reserve(cipher.size() / 3   1);
    int h;
    while (strm >> h) {
        res.push_back(static_cast<unsigned char>(h));
    }
    return res;
}
namespace client{
    std::string decrypt_cipher(std::string cipher, std::string usr_key)
    {
        std::string original_text  = "";
        const std::vector<unsigned char> key = key_from_string(usr_key);      // 16-char = 128-bit

        const unsigned char iv[16] = {
            0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x56, 0x34, 0x35, 0x36
        };
       
        std::vector<unsigned char> encrypted = cipher_as_chars(cipher);
        unsigned long padded_size = 0;
        std::vector<unsigned char> decrypted(encrypted.size());

        plusaes::decrypt_cbc(&encrypted[0], encrypted.size(), &key[0], key.size(), &iv, &decrypted[0], decrypted.size(), &padded_size);
        


        for (int i =0 ; i < decrypted.size(); i  )
        {
            //cout << decrypted[i] << endl;
            std::stringstream stream;
            stream << decrypted[i];
            original_text = original_text   stream.str();
        }

        return original_text;
    }
}

def encrypt_string(key,text):
    result = ''
    while len(text)% 16 != 0 :
        text = text " "
    string_as_bytes = text.encode('utf8')
    
    obj = AES.new(key.encode("utf8"), AES.MODE_CBC, 'This is an IV456'.encode("utf8"))
    cipher_text = obj.encrypt(string_as_bytes)
    
    for item in bytearray(cipher_text):
        result  = f"{hex(item).replace('0x','')} "
    return result

@api.route('/test')
def test_route():
    return encrypt_string("Encryptionkey123", "Happy new year people")


The server has an encryption and decryption function same with the client software if I encrypt a string using the c code and decrypt it using decryption function written in c it works fine and I get the same string, but when the client reads the response of /test and encrypts it and the c client tries to decrypt it outputs the string missing n letters in the end

The original text in python server Happy new year people

The output in the c client Happy new year p

CodePudding user response:

What's wrong is that the C library uses PKCS#7 padding and the python code uses spaces. The horrid C library doesn't check if the padding is within the block size nor the padding, so it directly unpads given the value of the final character found - for space this is 0x20. So this will unpad 32 bytes instead of any normal padding size (I wonder what it does when the padding is larger than the remaining plaintext size - possibly a buffer underflow?).

You have to implement PKCS#7 padding in the python. This is adding 1 byte valued 0x01 to 16 bytes valued 0x10. You can see an implementation here. Note that the unpadding shown there is as vulnerable as in the C library: instead you 1 check if the last padding byte is in the range 1..<blocksize=16> and then check if all the other padding bytes are correct as well, creating an exception or error code if not.

Also note CBC padding oracles, the use of a static IV etc. Use TLS for transport security.

CodePudding user response:

Look at this example pycrypto does support pkcs#7 padding your take on padding is poor, just use the built-in padding function in that module

Example take from the link

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.Padding import unpad

key=b'1234567890123456'
cipher=AES.new(key,AES.MODE_CBC)

text=b'secret text'
padtext=pad(text,16,style='pkcs7')
cipherText=cipher.encrypt(padtext)
print(padtext)
print(cipherText)

plaintext=cipher.decrypt(cipherText)  #can't use same object to decrypt
print(plaintext)

you might want to add some code to turn the result into a hex separated string

  • Related