QByteArray EncryptioNgSimliteDecryptor::decrypt(const QByteArray &data, bool *ok) { if (ok) *ok = false; if (!Valid) return data; //check if the message has at least the length of the shortest possible encrypted message if (data.length() < 192) return data; //decode the message from the Base64 encoding QCA::Base64 decoder(QCA::Decode); QCA::SecureArray decodedMessage = decoder.stringToArray(data); if (!decoder.ok()) return data; //extract the Blowfish key (first 128 characters) QCA::SecureArray encryptedBlowfishKey(decodedMessage.toByteArray().left(128)); //and the encrypted message (the rest) QCA::SecureArray encryptedMessage(decodedMessage.toByteArray().mid(128)); QCA::SymmetricKey blowfishKey; if (!DecodingKey.decrypt(encryptedBlowfishKey, &blowfishKey, QCA::EME_PKCS1_OAEP)) return data; //recreate the initialization vector (should be the same as the one used for ciphering) char ivec[8] = {0, 0, 0, 0, 0, 0, 0, 0}; QCA::InitializationVector iv(QByteArray(ivec, 8)); //now that we have the symmetric Blowfish key, we can decrypt the message; //create a 128 bit Blowfish cipher object using Cipher Block Chaining (CBC) mode, //with default padding and for decoding QCA::Cipher cipher(QString("blowfish"), QCA::Cipher::CBC, QCA::Cipher::DefaultPadding, QCA::Decode, blowfishKey, iv); //decipher the message (put the message into the decoding cipher object) QCA::SecureArray plainText = cipher.process(encryptedMessage); if (!cipher.ok()) return data; //check whether the decrypted data length is at least the size of the header - //if not, then we have an invalid message if (plainText.size() < (int)sizeof(sim_message_header)) return data; //extract the header from the decrypted data and check if the magic number is //correct sim_message_header head; memcpy(&head, plainText.data(), sizeof(sim_message_header)); if (head.magicFirstPart != SIM_MAGIC_V1_1 || head.magicSecondPart != SIM_MAGIC_V1_2) return data; if (ok) *ok = true; //the message has been decrypted! :D //put it into the input/output byte array return cp2unicode(&plainText.data()[sizeof(sim_message_header)]).toUtf8(); }
QString Security::encrypt(QString input) { //This uses QCA to encrypt passwords for FPT/SFTP before saving them with QSettings //This should probably have more randomness to be completely secure, but it's a bit better than plaintext. QCA::Initializer init = QCA::Initializer(); QCA::SymmetricKey key = QCA::SymmetricKey(QCA::SecureArray(ENC_KEY)); QCA::InitializationVector iv = QCA::InitializationVector(QCA::SecureArray(ENC_INIT_VECTOR)); QCA::Cipher cipher = QCA::Cipher(QString("aes128"), QCA::Cipher::CBC, QCA::Cipher::DefaultPadding, QCA::Encode, key, iv); //check if aes128 is available if (!QCA::isSupported("aes128-cbc-pkcs7")) { qDebug() << "AES128 CBC PKCS7 not supported - " "please check if qca-ossl plugin is" "installed correctly !"; return ""; } QCA::SecureArray secureData = input.toAscii(); QCA::SecureArray encryptedData = cipher.process(secureData); //check if encryption succeded if (!cipher.ok()) { return ""; } return QString(qPrintable(QCA::arrayToHex(encryptedData.toByteArray()))); }
void HatchetSipPlugin::webSocketConnected() { tLog() << Q_FUNC_INFO << "WebSocket connected"; if ( m_token.isEmpty() || !m_account->credentials().contains( "username" ) ) { tLog() << Q_FUNC_INFO << "access token or username is empty, aborting"; disconnectPlugin(); return; } hatchetAccount()->setConnectionState( Tomahawk::Accounts::Account::Connected ); m_sipState = AcquiringVersion; m_uuid = QUuid::createUuid().toString(); QCA::SecureArray sa( m_uuid.toLatin1() ); QCA::SecureArray result = m_publicKey->encrypt( sa, QCA::EME_PKCS1_OAEP ); tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "uuid:" << m_uuid << ", size of uuid:" << m_uuid.size() << ", size of sa:" << sa.size() << ", size of result:" << result.size(); QVariantMap nonceVerMap; nonceVerMap[ "version" ] = VERSION; nonceVerMap[ "nonce" ] = QString( result.toByteArray().toBase64() ); sendBytes( nonceVerMap ); }
/** * @paragraph This method encrypts a data string and returns a map of the key, hash and vector * @brief ServerPanel::EncryptEntity * @param QString sData * @return QVariantMap */ QVariantMap ServerPanel::EncryptEntity(QString sData) { // Initialize the cryptographer QCA::Initializer qiInitialization = QCA::Initializer(); // Generate the key QCA::SymmetricKey qskKey = QCA::SymmetricKey(2048); // Generate the vector QCA::InitializationVector qivInitialization = QCA::InitializationVector(2048); // Create the cipher QCA::Cipher qcrCipher = QCA::Cipher("aes128", QCA::Cipher::CBC, QCA::Cipher::DefaultPadding, QCA::Encode, qskKey, qivInitialization); // Make sure AES128 is supported if (!QCA::isSupported("aes128-cbc-pkcs7")) { qDebug("AES128 CBC PKCS7 not supported - please check if qca-ossl plugin installed correctly !"); } // Encrypt the data QCA::SecureArray qsaHash = qcrCipher.process(QCA::SecureArray(sData.toAscii())); // Setup the map to resturn QVariantMap qvmReturn; // Add the key qvmReturn.insert("qbaKey", qskKey.toByteArray()); // Add the vector qvmReturn.insert("qbaVector", qivInitialization.toByteArray()); // Add the hash qvmReturn.insert("qbaHash", qsaHash.toByteArray()); // Return the map return qvmReturn; }
QByteArray MessageContainerEncypted::bytes() { QByteArray buf = MessageContainerWrapper::bytes(); if(!this->isEncryptionSupported()) { return buf; } //buf.prepend(this->version); QCA::Cipher* cipher = this->createCipher(QCA::Encode); //qDebug("MessageContainerEncyptor::bytes: message raw '%s'", qPrintable(QCA::arrayToHex(buf))); QCA::SecureArray secretText = cipher->process(buf); //qDebug("MessageContainerEncyptor::bytes: message encryped '%s'", qPrintable(QCA::arrayToHex(secretText.toByteArray()))); return secretText.toByteArray(); }
bool MessageContainerEncypted::isValidFormat(const QByteArray& bytes) { if(!this->isEncryptionSupported()) { return MessageContainerWrapper::isValidFormat(bytes); } QByteArray myBytes = bytes; //if (bytes.length() && (byte)bytes[0] == this->version) { // int len = bytes.length() - 1; // myBytes = bytes.right(len); // //} QCA::Cipher* cipher = this->createCipher(QCA::Decode); //qDebug("SteganoCore::decryptData: message raw '%s'", qPrintable(QCA::arrayToHex(buf))); QCA::SecureArray clearText = cipher->process(myBytes); //qDebug("SteganoCore::decryptData: message decryped '%s'", qPrintable(QCA::arrayToHex(clearText.toByteArray()))); return MessageContainerWrapper::isValidFormat(clearText.toByteArray()); }
bool EncryptedStore::closeWrite() { Q_D(KOdfStore); bool passWasAsked = false; if (d->fileName == MANIFEST_FILE) { m_manifestBuffer = static_cast<QBuffer*>(d->stream)->buffer(); return true; } // Find a password // Do not accept empty passwords for compatibility with OOo if (m_password.isEmpty()) { findPasswordInKWallet(); } while (m_password.isEmpty()) { QPointer<KNewPasswordDialog> dlg = new KNewPasswordDialog(d->window); dlg->setPrompt(i18n("Please enter the password to encrypt the document with.")); if (! dlg->exec()) { // Without the first password, prevent asking again by deadsimply refusing to continue functioning // TODO: This feels rather hackish. There should be a better way to do this. delete m_pZip; m_pZip = 0; d->good = false; delete dlg; return false; } if (dlg){ m_password = QCA::SecureArray(dlg->password().toUtf8()); passWasAsked = true; } delete dlg; } // Ask the user to save the password if (passWasAsked && KMessageBox::questionYesNo(d->window, i18n("Do you want to save the password?")) == KMessageBox::Yes) { savePasswordInKWallet(); } QByteArray resultData; if (d->fileName == THUMBNAIL_FILE) { // TODO: Replace with a generic 'encrypted'-thumbnail resultData = static_cast<QBuffer*>(d->stream)->buffer(); } else if (!isToBeEncrypted(d->fileName)) { resultData = static_cast<QBuffer*>(d->stream)->buffer(); } else { m_bPasswordUsed = true; // Build all cryptographic data QCA::SecureArray passwordHash = QCA::Hash("sha1").hash(m_password); QCA::Random random; KoEncryptedStore_EncryptionData encData; encData.initVector = random.randomArray(8); encData.salt = random.randomArray(16); encData.iterationCount = 1024; QCA::SymmetricKey key = QCA::PBKDF2("sha1").makeKey(passwordHash, QCA::InitializationVector(encData.salt), 16, encData.iterationCount); QCA::Cipher encrypter("blowfish", QCA::Cipher::CFB, QCA::Cipher::DefaultPadding, QCA::Encode, key, QCA::InitializationVector(encData.initVector)); // Get the written data QByteArray data = static_cast<QBuffer*>(d->stream)->buffer(); encData.filesize = data.size(); // Compress the data QBuffer compressedData; QIODevice *compressDevice = KFilterDev::device(&compressedData, "application/x-gzip", false); if (!compressDevice) { return false; } static_cast<KFilterDev*>(compressDevice)->setSkipHeaders(); if (!compressDevice->open(QIODevice::WriteOnly)) { delete compressDevice; return false; } if (compressDevice->write(data) != data.size()) { delete compressDevice; return false; } compressDevice->close(); delete compressDevice; encData.checksum = QCA::Hash("sha1").hash(QCA::SecureArray(compressedData.buffer())); encData.checksumShort = false; // Encrypt the data QCA::SecureArray result = encrypter.update(QCA::SecureArray(compressedData.buffer())); result += encrypter.final(); resultData = result.toByteArray(); m_encryptionData.insert(d->fileName, encData); } if (!m_pZip->writeData(resultData.data(), resultData.size())) { m_pZip->finishWriting(resultData.size()); return false; } return m_pZip->finishWriting(resultData.size()); }
bool EncryptedStore::openRead(const QString& name) { Q_D(KOdfStore); if (bad()) return false; const KArchiveEntry* fileArchiveEntry = m_pZip->directory()->entry(name); if (!fileArchiveEntry) { return false; } if (fileArchiveEntry->isDirectory()) { kWarning(30002) << name << " is a directory!"; return false; } const KZipFileEntry* fileZipEntry = static_cast<const KZipFileEntry*>(fileArchiveEntry); delete d->stream; d->stream = fileZipEntry->createDevice(); d->size = fileZipEntry->size(); if (m_encryptionData.contains(name)) { // This file is encrypted, do some decryption first if (m_bPasswordDeclined) { // The user has already declined to give a password // Open the file as empty d->stream->close(); delete d->stream; d->stream = new QBuffer(); d->stream->open(QIODevice::ReadOnly); d->size = 0; return true; } QCA::SecureArray encryptedFile(d->stream->readAll()); if (encryptedFile.size() != d->size) { // Read error detected d->stream->close(); delete d->stream; d->stream = NULL; kWarning(30002) << "read error"; return false; } d->stream->close(); delete d->stream; d->stream = NULL; KoEncryptedStore_EncryptionData encData = m_encryptionData.value(name); QCA::SecureArray decrypted; // If we don't have a password yet, try and find one if (m_password.isEmpty()) { findPasswordInKWallet(); } while (true) { QByteArray pass; QCA::SecureArray password; bool keepPass = false; // I already have a password! Let's test it. If it's not good, we can dump it, anyway. if (!m_password.isEmpty()) { password = m_password; m_password = QCA::SecureArray(); } else { if (!m_filename.isNull()) keepPass = false; QPointer<KPasswordDialog> dlg = new KPasswordDialog(d->window , keepPass ? KPasswordDialog::ShowKeepPassword : static_cast<KPasswordDialog::KPasswordDialogFlags>(0)); dlg->setPrompt(i18n("Please enter the password to open this file.")); if (! dlg->exec()) { m_bPasswordDeclined = true; d->stream = new QBuffer(); d->stream->open(QIODevice::ReadOnly); d->size = 0; delete dlg; return true; } if (dlg) { password = QCA::SecureArray(dlg->password().toUtf8()); if (keepPass) keepPass = dlg->keepPassword(); if (password.isEmpty()) { delete dlg; continue; } } delete dlg; } decrypted = decryptFile(encryptedFile, encData, password); if (decrypted.isEmpty()) { kError(30002) << "empty decrypted file" << endl; return false; } if (!encData.checksum.isEmpty()) { QCA::SecureArray checksum; if (encData.checksumShort && decrypted.size() > 1024) { // TODO: Eww!!!! I don't want to convert via insecure arrays to get the first 1K characters of a secure array <- fix QCA? checksum = QCA::Hash("sha1").hash(QCA::SecureArray(decrypted.toByteArray().left(1024))); } else { checksum = QCA::Hash("sha1").hash(decrypted); } if (checksum != encData.checksum) { continue; } } // The password passed all possible tests, so let's accept it m_password = password; m_bPasswordUsed = true; if (keepPass) { savePasswordInKWallet(); } break; } QByteArray *resultArray = new QByteArray(decrypted.toByteArray()); QIODevice *resultDevice = KFilterDev::device(new QBuffer(resultArray, NULL), "application/x-gzip"); if (!resultDevice) { delete resultArray; return false; } static_cast<KFilterDev*>(resultDevice)->setSkipHeaders(); d->stream = resultDevice; d->size = encData.filesize; } d->stream->open(QIODevice::ReadOnly); return true; }
bool EncryptedStore::doFinalize() { Q_D(KOdfStore); if (d->good) { if (isOpen()) { close(); } if (d->mode == Write) { // First change the manifest file and write it // We'll use the QDom classes here, since KXmlReader and KXmlWriter have no way of copying a complete xml-file // other than parsing it completely and rebuilding it. // Errorhandling here is done to prevent data from being lost whatever happens // TODO: Convert this to KoXML when KoXML is extended enough // Note: right now this is impossible due to lack of possibilities to copy an element as-is QDomDocument document; if (m_manifestBuffer.isEmpty()) { // No manifest? Better create one document = QDomDocument(); QDomElement rootElement = document.createElement("manifest:manifest"); rootElement.setAttribute("xmlns:manifest", "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"); document.appendChild(rootElement); } if (!m_manifestBuffer.isEmpty() && !document.setContent(m_manifestBuffer)) { // Oi! That's fresh XML we should have here! // This is the only case we can't fix KMessage::message(KMessage::Error, i18n("The manifest file seems to be corrupted. It cannot be modified and the document will remain unreadable. Please try and save the document again to prevent losing your work.")); m_pZip->close(); return false; } QDomElement documentElement = document.documentElement(); QDomNodeList fileElements = documentElement.elementsByTagName("manifest:file-entry"); // Search all files in the manifest QStringList foundFiles; for (int i = 0; i < fileElements.size(); i++) { QDomElement fileElement = fileElements.item(i).toElement(); QString fullpath = fileElement.toElement().attribute("manifest:full-path"); // See if it's encrypted if (fullpath.isEmpty() || !m_encryptionData.contains(fullpath)) { continue; } foundFiles += fullpath; KoEncryptedStore_EncryptionData encData = m_encryptionData.value(fullpath); // Set the unencrypted size of the file fileElement.setAttribute("manifest:size", encData.filesize); // See if the user of this store has already provided (old) encryption data QDomNodeList childElements = fileElement.elementsByTagName("manifest:encryption-data"); QDomElement encryptionElement; QDomElement algorithmElement; QDomElement keyDerivationElement; if (childElements.isEmpty()) { encryptionElement = document.createElement("manifest:encryption-data"); fileElement.appendChild(encryptionElement); } else { encryptionElement = childElements.item(0).toElement(); } childElements = encryptionElement.elementsByTagName("manifest:algorithm"); if (childElements.isEmpty()) { algorithmElement = document.createElement("manifest:algorithm"); encryptionElement.appendChild(algorithmElement); } else { algorithmElement = childElements.item(0).toElement(); } childElements = encryptionElement.elementsByTagName("manifest:key-derivation"); if (childElements.isEmpty()) { keyDerivationElement = document.createElement("manifest:key-derivation"); encryptionElement.appendChild(keyDerivationElement); } else { keyDerivationElement = childElements.item(0).toElement(); } // Set the right encryption data QCA::Base64 encoder; QCA::SecureArray checksum = encoder.encode(encData.checksum); if (encData.checksumShort) { encryptionElement.setAttribute("manifest:checksum-type", "SHA1/1K"); } else { encryptionElement.setAttribute("manifest:checksum-type", "SHA1"); } encryptionElement.setAttribute("manifest:checksum", QString(checksum.toByteArray())); QCA::SecureArray initVector = encoder.encode(encData.initVector); algorithmElement.setAttribute("manifest:algorithm-name", "Blowfish CFB"); algorithmElement.setAttribute("manifest:initialisation-vector", QString(initVector.toByteArray())); QCA::SecureArray salt = encoder.encode(encData.salt); keyDerivationElement.setAttribute("manifest:key-derivation-name", "PBKDF2"); keyDerivationElement.setAttribute("manifest:iteration-count", QString::number(encData.iterationCount)); keyDerivationElement.setAttribute("manifest:salt", QString(salt.toByteArray())); } if (foundFiles.size() < m_encryptionData.size()) { QList<QString> keys = m_encryptionData.keys(); for (int i = 0; i < keys.size(); i++) { if (!foundFiles.contains(keys.value(i))) { KoEncryptedStore_EncryptionData encData = m_encryptionData.value(keys.value(i)); QDomElement fileElement = document.createElement("manifest:file-entry"); fileElement.setAttribute("manifest:full-path", keys.value(i)); fileElement.setAttribute("manifest:size", encData.filesize); fileElement.setAttribute("manifest:media-type", ""); documentElement.appendChild(fileElement); QDomElement encryptionElement = document.createElement("manifest:encryption-data"); QCA::Base64 encoder; QCA::SecureArray checksum = encoder.encode(encData.checksum); QCA::SecureArray initVector = encoder.encode(encData.initVector); QCA::SecureArray salt = encoder.encode(encData.salt); if (encData.checksumShort) { encryptionElement.setAttribute("manifest:checksum-type", "SHA1/1K"); } else { encryptionElement.setAttribute("manifest:checksum-type", "SHA1"); } encryptionElement.setAttribute("manifest:checksum", QString(checksum.toByteArray())); fileElement.appendChild(encryptionElement); QDomElement algorithmElement = document.createElement("manifest:algorithm"); algorithmElement.setAttribute("manifest:algorithm-name", "Blowfish CFB"); algorithmElement.setAttribute("manifest:initialisation-vector", QString(initVector.toByteArray())); encryptionElement.appendChild(algorithmElement); QDomElement keyDerivationElement = document.createElement("manifest:key-derivation"); keyDerivationElement.setAttribute("manifest:key-derivation-name", "PBKDF2"); keyDerivationElement.setAttribute("manifest:iteration-count", QString::number(encData.iterationCount)); keyDerivationElement.setAttribute("manifest:salt", QString(salt.toByteArray())); encryptionElement.appendChild(keyDerivationElement); } } } m_manifestBuffer = document.toByteArray(); m_pZip->setCompression(KZip::DeflateCompression); if (!m_pZip->writeFile(MANIFEST_FILE, "", "", m_manifestBuffer.data(), m_manifestBuffer.size())) { KMessage::message(KMessage::Error, i18n("The manifest file cannot be written. The document will remain unreadable. Please try and save the document again to prevent losing your work.")); m_pZip->close(); return false; } } } if (m_pZip) return m_pZip->close(); else return true; }