Kuba Kuba - 1 month ago 11
C++ Question

Serialize encrypted password to XML (QT)

So I have an application that contains userbase which is stored in xml file and loaded at the start of the program. I use QXmlStreamWriter/Reader for this purpose. The problem occurs when I try to serialize encrypted (hashed?) form of password (using QCryptographicHash and Sha256 for this).
QCryptographicHash return QByteArray, which can be converted to QString (necessary for use of QXmlStreamWriter/Reader). Relevant code below. Everything works fine before the serialization (I can log in), but when I read data from xml, after finding hashed password the function behaves like it found the EOF, and only about 2 chars are loaded to the QString by QXmlStreamReader.

In the code please ignore reservations etc (it's a cinema panel), relevant fragments are passwords, I supply full function just in case.

I hope I explained what the issue is, here are fragments of my code (note: before adding the hashing everything worked fine)

register function (the hashing, pass is a QString):

QString hash = QCryptographicHash::hash(pass.toUtf8(), QCryptographicHash::Sha256);

User* user_pointer;
user_pointer = new User(name, hash, admin);


writing function:

QFile file("users/users.xml");
if(!file.open(QIODevice::WriteOnly))
throw "Error podczas otwierania bazy użytkowników!";


QXmlStreamWriter writer (&file);

writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeStartElement("USERS");
int list_size = userList.size();

for(int i = 0; i < list_size; i++)
{
writer.writeStartElement("USER");
writer.writeTextElement("name", userList.at(i)->name);
writer.writeTextElement("pass", userList.at(i)->password);
writer.writeTextElement("admin", QString::number(userList.at(i)->is_admin));
writer.writeStartElement("RESERVATIONS");
for(int m = 0; m < userList.at(i)->reservList.size(); m++)
{
writer.writeStartElement("reservation");
writer.writeTextElement("moviename", userList.at(i)->reservList.at(m)->movie_name);
writer.writeTextElement("date", userList.at(i)->reservList.at(m)->date.toString("dd.MM.yyyy"));
writer.writeTextElement("hour", (userList.at(i)->reservList.at(m)->hour).toString("hhmm"));
writer.writeTextElement("paid", QString::number(userList.at(i)->reservList.at(m)->paid));
for(int n = 0; n < userList.at(i)->reservList.at(m)->placeList.size(); n++)
writer.writeTextElement("place", QString::number(userList.at(i)->reservList.at(m)->placeList.at(n)));
writer.writeEndElement();
}
writer.writeEndElement();
writer.writeEndElement();
}
writer.writeEndDocument();


file.close();

}


reading function:

QFile file("users/users.xml");
if(!file.open(QIODevice::ReadOnly))
throw "Brak bazy danych użytkowników lub błąd jej otworzenia!";

QXmlStreamReader reader;

reader.setDevice(&file);
reader.readNext();

QString user_name;
QString user_pass;
bool admin;
QString movie_name;
QTime hour;
QDate date;
bool paid;

User* user_pointer = NULL;
int user_counter = -1;
Reservation* reserv_pointer = NULL;
int reserv_counter = -1;

while(!reader.atEnd())
{
if(reader.isStartElement())
{
if(reader.name() == "USER")
{
reserv_counter = -1;

}

if(reader.name() == "name")
user_name = reader.readElementText();
if(reader.name() == "pass")
user_pass = reader.readElementText();
if(reader.name() == "admin")
{
admin = reader.readElementText().toInt();
user_pointer = new User(user_name, user_pass, admin);
userList.append(user_pointer);

user_counter++;
}
if(reader.name() == "reservation")
{
reserv_counter++;
}
if(reader.name() == "moviename")
movie_name = reader.readElementText();
if(reader.name() == "hour")
hour = QTime::fromString(reader.readElementText(), "hhmm");
if(reader.name() == "date")
date = QDate::fromString(reader.readElementText(), "dd.MM.yyyy");
if(reader.name() == "paid")
{
paid = reader.readElementText().toInt();
reserv_pointer = new Reservation(movie_name, date, hour, paid);
userList.at(user_counter)->reservList.append(reserv_pointer);
}
if(reader.name() == "place")
{
userList.at(user_counter)->reservList.at(reserv_counter)->placeList.append(reader.readElementText().toInt());

}

reader.readNextStartElement();
}
else
reader.readNext();
}

file.close();
}


Any help will be appreciated.

Answer

The hash value is not a string, it is a sequence of arbitrary byte values, some of those might happen to be problematic when interpreting it as a string.

You have an implicit conversion from QByteArray to QString, for which the documentation says that:

The byte array is converted to Unicode using the fromUtf8() function. This function stops conversion at the first NUL character found, or the end of the ba byte array.

You could for example use explicit conversion which specifies the length:

QString::fromUtf8(byteArray.data(), length);

As Frank Osterfeld noted in the comments, using UTF8 is not a good idea, I have tested from and to Latin1 extensively for a project I was working on, and the binary data is identical, however in looks "funky" in textual form, which may not play well with the XML reading and writing, toHex() will fix that by limiting the character set to 0-F:

QByteArray b; // hash
QString ss = QString::fromLatin1(b.toHex()); // to QString
b = QByteArray::fromHex(ss.toLatin1()); // back to QByteArray
Comments