bricke / Qt-AES

Native Qt AES encryption class
The Unlicense
508 stars 187 forks source link

Qt-AES 256 CFB decode message from Java #6

Closed ricox78 closed 6 years ago

ricox78 commented 6 years ago

I have an issue, I'm developing an android app that comunicate with a Qt develop application through an UDP socket.

Just to study, I tried to encrypt comunication using AES CFB NoPadding:

Java side:

public final String key = "123456789123";
public final byte initVector[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,             0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
byte [] hashKey = null;
Cipher m_encChiper;
Cipher m_decChiper;

//Init 
MessageDigest digest = MessageDigest.getInstance("SHA-256");
hashKey = digest.digest(msgTools.key.getBytes("UTF-8"));

IvParameterSpec iv = new IvParameterSpec(msgTools.initVector);
SecretKeySpec skeySpec = new SecretKeySpec(hashKey, "AES");

m_encChiper = Cipher.getInstance("AES/CFB/NoPadding");
m_encChiper.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

m_decChiper = Cipher.getInstance("AES/CFB/NoPadding");
m_decChiper.init(Cipher.DECRYPT_MODE, skeySpec, iv);

//Enc and Dec function

   public byte[] encrypt(String value) {
        try {

            byte[] encrypted = m_encChiper.doFinal(value.getBytes());
            return encrypted;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public String decrypt(byte [] encrypted) {
        try {

            byte[] original = m_decChiper.doFinal(encrypted);

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

Qt Side:

QAESEncryption *encryption = NULL;
QString key = "123456789123";
QByteArray hashKey = QCryptographicHash::hash(key.toLocal8Bit(),             QCryptographicHash::Sha256);
QByteArray iv;

encryption = new QAESEncryption(QAESEncryption::AES_256,     QAESEncryption::CFB);
quint8 iv_16[16]     = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
    for (int i=0; i<16; i++)
        iv.append(iv_16[i]);

QByteArray SenderThread::encryptData(QString msg)
{
    return encryption->encode(msg.toLocal8Bit(), hashKey, iv);
}

QString SenderThread::decodeData(QByteArray xMsg)
{
    return QString(encryption->decode(xMsg, hashKey, iv));
}

The problem is that, sending a string that encoded in java result in a 17 byte buffer, will be decoded in Qt correctly for the first 16 byte than QAESEncryption::decode at:

...
case CFB:
            if (i+m_blocklen < rawText.size()){
                ret.append(byteXor(rawText.mid(i+m_blocklen, m_blocklen),
                                   cipher(expandedKey, rawText.mid(i, m_blocklen))));
...

with i = 0 m_blocklen = 16, append other 16 bytes, the first is the correct 17th others 15 are non sense...

The same sended string has been encoded locally in Qt resulting in a 32 byte buffer that are corretly decoded. The same sended string has been encoded locally in Java resulting in a 17 byte buffer that are corretly decoded.

any idea on what's wrong when I pass from a platform to another??

Thanks a lot for all

bricke commented 6 years ago

The encrypted block has to be a multiple of 16, in your case being 17 bytes it adds 15 bytes of padding to make it 32 (16*2).

I'll look into a solution asap.

ricox78 commented 6 years ago

I could add 2 info: 1- If I use PKCS5Padding in Java, after 17 corrects bytes, 15 bytes @ 0xff are added at the byte array 2- the problem is present also when I send from qt to Java ... Thank’s again for all

bricke commented 6 years ago

Let me understand, AES says that the lenght of the block to decipher has to be a multiple of 16, you can handle the padding yourself by adding something to match this requirement or let the software do it (if you are using a string with termination char let the class handle it works well).

I don't use Java since a while, if you cipher the string in java, how many bytes in total you end up with? 32 or 17?

ricox78 commented 6 years ago

I try to explain better:

in Java I could init Chiper in this way:

m_encChiper = Cipher.getInstance("AES/CFB/NoPadding"); so no padding is managed and if I crypt something that out of the encrypt function result an array of 17 bytes, this is my result. If I pass this array to java decrypt function I obtain the original String. If I pass this array to your encryption->decode(xMsg, hashKey, iv) where xMsg is the 17 lenght byte array, I have my original string followed by 15bytes of non sense added as I indicated in the initial post.

So I could not find a way to manage padding in your library so I try to init my java Chiper to: m_encChiper = Cipher.getInstance("AES/CFB/PKCS5PADDING"); I'm not sure CFB with padding have sense.. but I tried and when I decode in Qt the result is my original String followed bt 15 bytes all at 0x00ff.

I don't handle padding by myself, Java api did it for me .. but in NoPadding mode, the result of encrypt is not an array with a lenght multiple of 16 bytes. Is there a way to set your library to NoPadding?? Thank's again.

bricke commented 6 years ago

Can't you tell Java to use a zero-filled padding?

I think I can add PKCS5PADDING and other form of padding.

ricox78 commented 6 years ago

Thank's very much, very nice suggestion, initializing Chiper as following:

m_encChiper = Cipher.getInstance("AES/CFB/ZeroBytePadding");

java pad the coded string in the way in witch your library works! Thank's againg, probably padd management could be added to your wonderful work! Bye

bricke commented 6 years ago

Happy that it worked.

Please remember that my AES code is not audited or tested.

ricox78 commented 6 years ago

Yes for sure, I’ve used it to study a server simulator that works behind my app... first tests works, If can my experience with it contribute to test I’m happy..

bricke commented 6 years ago

I added PKCS7 and ISO padding, can you check them against Java?