bool Exporter::write(const SecureByteArray &data, const SecureString &pwd) { Q_D(Exporter); Q_ASSERT((data.size() % Crypter::AESBlockSize) == 0); QByteArray salt = Crypter::generateSalt(); SecureByteArray iv; SecureByteArray key; Crypter::makeKeyAndIVFromPassword(pwd.toUtf8(), salt, key, iv); CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption enc; enc.SetKeyWithIV(reinterpret_cast<const byte*>(key.constData()), key.size(), reinterpret_cast<const byte*>(iv.constData())); const int cipherSize = data.size(); QByteArray cipher(cipherSize, static_cast<char>(0)); CryptoPP::ArraySource s( reinterpret_cast<const byte*>(data.constData()), data.size(), true, new CryptoPP::StreamTransformationFilter( enc, new CryptoPP::ArraySink(reinterpret_cast<byte*>(cipher.data()), cipher.size()), CryptoPP::StreamTransformationFilter::NO_PADDING ) ); Q_UNUSED(s); // just to please the compiler QFile file(d->filename); bool opened = file.open(QIODevice::WriteOnly); if (!opened) return false; QByteArray block = salt + cipher; file.write(PemPreamble.toUtf8()); file.write("\n"); const SecureByteArray &b64 = block.toBase64(); for (int i = 0; i < b64.size(); i += 64) { file.write(b64.mid(i, qMin(64, b64.size() - i))); file.write("\n"); } file.write(PemEpilog.toUtf8()); file.write("\n"); file.close(); return true; }
SecureByteArray Exporter::read(const SecureString &pwd) { Q_D(Exporter); SecureByteArray plain; QFile file(d->filename); bool opened = file.open(QIODevice::ReadOnly); if (opened) { static const int MaxLineSize = 64 + 2; int state = 0; QByteArray b64; while (!file.atEnd()) { char buf[MaxLineSize]; const qint64 bytesRead = file.readLine(buf, MaxLineSize); const QString line = QByteArray(buf, bytesRead).trimmed(); switch (state) { case 0: if (line == PemPreamble) { state = 1; } else { qWarning() << "bad format"; } break; case 1: if (line != PemEpilog) { b64.append(line.toUtf8()); } else { state = 2; } break; case 2: // ignore trailing lines break; default: qWarning() << "Oops! Should never have gotten here."; break; } } file.close(); SecureByteArray iv; SecureByteArray key; QByteArray imported = QByteArray::fromBase64(b64); QByteArray salt = imported.mid(0, Crypter::SaltSize); QByteArray cipher = imported.mid(Crypter::SaltSize); Crypter::makeKeyAndIVFromPassword(pwd.toUtf8(), salt, key, iv); CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec; dec.SetKeyWithIV(reinterpret_cast<const byte*>(key.constData()), key.size(), reinterpret_cast<const byte*>(iv.constData())); plain = SecureByteArray(cipher.size(), static_cast<char>(0)); CryptoPP::ArraySource s( reinterpret_cast<const byte*>(cipher.constData()), cipher.size(), true, new CryptoPP::StreamTransformationFilter( dec, new CryptoPP::ArraySink(reinterpret_cast<byte*>(plain.data()), plain.size()), CryptoPP::StreamTransformationFilter::NO_PADDING ) ); Q_UNUSED(s); // just to please the compiler } return plain; }