将加密密码序列化为XML

时间:2016-10-22 14:42:02

标签: c++ xml qt encryption

我有一个包含userbase的应用程序,该用户库存储在xml文件中并在程序开头加载。我为此目的使用QXmlStreamWriter / Reader。当我尝试序列化加密(哈希?)形式的密码时会出现问题(使用QCryptographicHash和Sha256)。

QCryptographicHash返回QByteArray,可以转换为QString(使用QXmlStreamWriter / Reader时必需)。相关代码如下。在序列化之前一切正常(我可以登录),但是当我从xml读取数据时,在找到散列密码之后,该函数的行为类似于找到EOF,并且QXmlStreamReader只将大约2个字符加载到QString。

在代码中请忽略预订等(它是电影院面板),相关片段是密码,我提供全部功能以防万一。

我希望我解释了问题所在,这里是我的代码片段(注意:在添加散列之前一切正常)

寄存器功能(散列,传递是QString):

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

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

写作功能:

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();

}

阅读功能:

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();
}

2 个答案:

答案 0 :(得分:2)

哈希值不是字符串,它是一系列任意字节值,其中一些可能在将其解释为字符串时可能会出现问题。

您有从QByteArrayQString的隐式转换,文档说明了这一点:

  

使用fromUtf8()函数将字节数组转换为Unicode。   此函数在找到的第一个NUL字符处停止转换,或   ba字节数组的结尾。

例如,您可以使用指定长度的显式转换:

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

正如Frank Osterfeld在评论中指出的那样,使用UTF8并不是一个好主意,我已经对我正在研究的项目进行了大量的测试,并且二进制数据是相同的,但在文本中看起来“时髦”表单,可能不适合XML读写,toHex()将通过将字符集限制为0-F来解决这个问题:

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

答案 1 :(得分:0)

您的问题是XML是文本格式,但加密密码是二进制格式。两者不兼容。您需要有一些方法以文本友好的格式对二进制数据进行编码。

正如@ddriver所提到的,一种方法是使用QByteArray::toHex(),因为它会将所有字节转换为人类可读的文本字符。但是,成本是大小增加了100%(密码哈希的每个字节返回2个字符)

以文本形式传输二进制数据的另一种更普遍,更有效的方法是使用QByteArray::toBase64()。虽然它也以文本形式返回二进制数据,但是大小仅增加了13/3%(每3个字节的密码哈希返回4个字节)。

(您可能会认识到这种编码,因为它的无意义文本通常以一个或两个=字符结尾,并且是用于在电子邮件中传输二进制数据的常用编码)