Exemple #1
0
bool CEncryption::Decrypt(const unsigned char* pInput, int nLenInput, const char* szPassword,
						 unsigned char*& pOutput, int& nLenOutput)
{
	bool			bResult = false;
	TD_TLHEADER		hdr;
	RD_UINT8		uFinalKey[32];
	sha256_ctx		sha32;


	ASSERT(NULL != pInput);						if(NULL == pInput)					return FALSE;
	ASSERT(0	!= nLenInput);					if(0	== nLenInput)				return FALSE;
	ASSERT(NULL != szPassword);					if(NULL == szPassword)				return FALSE;
	ASSERT(sizeof(TD_TLHEADER) <= nLenInput);	if(sizeof(TD_TLHEADER) > nLenInput) return FALSE; 

	// Extract header structure from memory file
	memcpy(&hdr, pInput, sizeof(TD_TLHEADER));

	// Hash the header
	sha256_begin(&sha32);
	sha256_hash((unsigned char *)&hdr + 32, sizeof(TD_TLHEADER) - 32, &sha32);
	sha256_end((unsigned char *)uFinalKey, &sha32);

	// Check if hash of header is the same as stored hash
	// to verify integrity of header
	if(0 == memcmp(hdr.aHeaderHash, uFinalKey, 32))
	{
		// Check if we can open this
		if((hdr.dwSignature1 == TD_TLSIG_1) && (hdr.dwSignature2 == TD_TLSIG_2))
		{
			// Allocate enough memory
			pOutput = new unsigned char[nLenInput];
			if(NULL != pOutput)
			{
				unsigned long uKeyLen = strlen(szPassword);

				// Create MasterKey by hashing szPassword
				ASSERT(0 != uKeyLen);
				if(0 != uKeyLen)
				{
					sha256_begin(&sha32);
					sha256_hash((unsigned char *)szPassword, uKeyLen, &sha32);
					sha256_end(m_pMasterKey, &sha32);

					m_dwKeyEncRounds = hdr.dwKeyEncRounds;

					// Generate m_pTransformedMasterKey from m_pMasterKey
					if(TRUE == _TransformMasterKey(hdr.aMasterSeed2))
					{
						// Hash the master password with the generated hash salt
						sha256_begin(&sha32);
						sha256_hash(hdr.aMasterSeed, 16, &sha32);
						sha256_hash(m_pTransformedMasterKey, 32, &sha32);
						sha256_end((unsigned char *)uFinalKey, &sha32);

						bResult = true;
					}
				}
			}
		}
	}

	if (bResult)
	{
		bResult = false;

		Rijndael aes;
		// Initialize Rijndael/AES
		if(RIJNDAEL_SUCCESS == aes.init(Rijndael::CBC, Rijndael::Decrypt, uFinalKey,
			Rijndael::Key32Bytes, hdr.aEncryptionIV) )
		{
			nLenOutput = aes.padDecrypt((RD_UINT8 *)pInput + sizeof(TD_TLHEADER), nLenInput - sizeof(TD_TLHEADER), (RD_UINT8 *)pOutput);

			// Check if all went correct
			ASSERT(0 <= nLenOutput);
			if(0 <= nLenOutput)
			{
				// Check contents correct (with high probability)
				sha256_begin(&sha32);
				sha256_hash((unsigned char *)pOutput, nLenOutput, &sha32);
				sha256_end((unsigned char *)uFinalKey, &sha32);
				if(0 == memcmp(hdr.aContentsHash, uFinalKey, 32))
				{
					bResult = true; // data decrypted successfully
				}
			}
		}
	}

	if (!bResult)
	{
		SAFE_DELETE_ARRAY(pOutput);
	}

	return (bResult);
}
Exemple #2
0
bool App::openTree(const QString &file)
{
    NotesFileParser handler;

    connect(&handler, SIGNAL(backupLoaded(bool, const QString &)),
            this,       SLOT(setBackupLocation(bool, const QString &)));
    connect(&handler, SIGNAL(notesShowReminderAtStartUpLoaded(bool)),
            this,       SLOT(setNotesShowReminderAtStartUp(bool)));
//  connect(&handler, SIGNAL(notesWordWrapLoaded(bool)),
//          this,       SLOT(setNotesWordWrap(bool)));
//  connect(&handler, SIGNAL(notesRootNodeDecorationLoaded(bool)),
//          this,       SLOT(setNotesRootNodeDecoration(bool)));
//  connect(&handler, SIGNAL(notesShowScrollBarsLoaded(bool)),
//          this,       SLOT(setNotesShowScrollBars(bool)));
    connect(&handler, SIGNAL(entryLoaded(Entry *)),
            this,       SLOT(addEntry(Entry *)));
    connect(&handler, SIGNAL(noteLoaded(const QString &, QList<QString> *,
                                        const QString &, const QString &,
                                        int, QDateTime, const QString &, QDateTime)),
            notes,      SLOT(addNote(const QString &, QList<QString> *,
                                        const QString &, const QString &,
                                        int, QDateTime, const QString &, QDateTime)));
    connect(&handler, SIGNAL(securityPasswdLoaded(const QString &)),
            this,       SLOT(setSecurityPasswd(const QString &)));
    connect(&handler, SIGNAL(noteLoaded(const QString &, Strokes *,
                                        const QString &, const QString &,
                                        int, QDateTime, const QString &, QDateTime)),
            notes,      SLOT(addNote(const QString &, Strokes *,
                                        const QString &, const QString &,
                                        int, QDateTime, const QString &, QDateTime)));
    connect(&handler, SIGNAL(noNoteChild()),
            notes,      SLOT(noNoteChild()));

    QFile xmlFile(Global::applicationFileName("iqnotes", file + ".xml")),
    xmlRijndaelFile(Global::applicationFileName("iqnotes", file + ".rijn"));
    QXmlInputSource *source;

    // Init xml file
    if (!xmlFile.exists() && !xmlRijndaelFile.exists())
    {
        xmlFile.open(IO_WriteOnly);
        QTextStream ts(&xmlFile);

        ts << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<iqnotes>\n<entries>\n"

        << "<entry name=\"Company\">\n"
        << "<property name=\"Name\" type=\"oneLine\"/>\n"
        << "<property name=\"Address\" type=\"multiLine\"/>\n"
        << "<property name=\"Tels\" type=\"oneLine\"/>\n"
        << "<property name=\"Emails\" type=\"oneLine\"/>\n"
        << "<property name=\"Note\" type=\"multiLine\"/>\n"
        << "</entry>\n"

        << "<entry name=\"Person\">\n"
        << "<property name=\"Name\" type=\"oneLine\"/>\n"
        << "<property name=\"Nick\" type=\"oneLine\"/>\n"
        << "<property name=\"Work Address\" type=\"multiLine\"/>\n"
        << "<property name=\"Work Tel\" type=\"oneLine\"/>\n"
        << "<property name=\"Work Emails\" type=\"oneLine\"/>\n"
        << "<property name=\"Home Address\" type=\"multiLine\"/>\n"
        << "<property name=\"Home Tel\" type=\"oneLine\"/>\n"
        << "<property name=\"Emails\" type=\"oneLine\"/>\n"
        << "<property name=\"Note\" type=\"multiLine\"/>\n"
        << "</entry>\n"

        << "<entry name=\"User account\">\n"
        << "<property name=\"Host\" type=\"oneLine\"/>\n"
        << "<property name=\"Username\" type=\"oneLine\"/>\n"
        << "<property name=\"Password\" type=\"oneLine\"/>\n"
        << "<property name=\"Type\" type=\"oneLine\"/>\n"
        << "<property name=\"Note\" type=\"mutliLine\"/>\n"
        << "</entry>\n"

        << "<entry name=\"Credit card\">\n"
        << "<property name=\"Card type\" type=\"oneLine\"/>\n"
        << "<property name=\"Account #\" type=\"oneLine\"/>\n"
        << "<property name=\"Expire\" type=\"oneLine\"/>\n"
        << "<property name=\"PIN\" type=\"oneLine\"/>\n"
        << "<property name=\"Note\" type=\"mutliLine\"/>\n"
        << "</entry>\n"

        << "<entry name=\"WWW Link\">\n"
        << "<property name=\"Title\" type=\"oneLine\"/>\n"
        << "<property name=\"URL\" type=\"oneLine\"/>\n"
        << "<property name=\"Description\" type=\"multiLine\"/>\n"
        << "</entry>\n"

        << "</entries>\n"
        << "<notes>\n</notes>\n</iqnotes>\n";

        xmlFile.close();
        source = new QXmlInputSource(xmlFile);
    }
    else if (xmlRijndaelFile.exists())
    {
        StartUpPasswdBase passwdD(this, 0, true);
        passwdD.adjustSize();
        if (!passwdD.exec())
        {
            return false;
        }
        
        preferences.setPasswd(passwdD.Passwd->text());

        xmlRijndaelFile.open(IO_ReadOnly);
        uint fileSize = xmlRijndaelFile.size();
        unsigned char *rijnData = (unsigned char *) malloc(fileSize),
            *rijnDataDecrypted = (unsigned char *) malloc(fileSize);
        Rijndael rijndael;

        xmlRijndaelFile.readBlock((char *)rijnData, fileSize);
        rijndael.init(Rijndael::CBC, Rijndael::Decrypt, preferences.passwd16Bin, Rijndael::Key16Bytes);
        rijndael.padDecrypt(rijnData, fileSize, rijnDataDecrypted);

		// yeah, stupid
        if (memcmp((void *)"<iqnotes>", (void *)rijnDataDecrypted, 9) != 0 && memcmp((void *)"<?xml version", (void *)rijnDataDecrypted, 13) != 0)
        {
            free(rijnData);
            free(rijnDataDecrypted);

            QMessageBox::critical(this, "Bad password", "Please,\ntype correct password.");

            return false;
        }

        source = new QXmlInputSource();
        //        source->setData(QString((char *)rijnDataDecrypted));
        source->setData(QString::fromUtf8((char *)rijnDataDecrypted));

        free(rijnData);
        free(rijnDataDecrypted);
    }
    else
    {
        source = new QXmlInputSource(xmlFile);
    }

    QXmlSimpleReader reader;
    reader.setContentHandler(&handler);
    reader.setErrorHandler(new NotesFileParserError);
    if(!reader.parse(*source))
        qWarning(tr("parse error"));

    delete source;

    setCaption("IQNotes :: " + file);
     
    return true;
}
//! \todo Optimize writing section data. Right now it only writes one block at a
//!		time, which is of course quite slow (in relative terms).
//!	\todo Refactor this into several different methods for writing each region
//!		of the image. Use a context structure to keep track of shared data between
//!		each of the methods.
//! \todo Refactor the section and boot tag writing code to only have a single
//!		copy of the block writing and encryption loop.
void EncoreBootImage::writeToStream(std::ostream & stream)
{
	// always generate the session key or DEK even if image is unencrypted
	m_sessionKey.randomize();
	
	// prepare to compute CBC-MACs with each KEK
	unsigned i;
	smart_array_ptr<RijndaelCBCMAC> macs(0);
	if (isEncrypted())
	{
		macs = new RijndaelCBCMAC[m_keys.size()];
		for (i=0; i < m_keys.size(); ++i)
		{
			RijndaelCBCMAC mac(m_keys[i]);
			(macs.get())[i] = mac;
		}
	}
	
	// prepare to compute SHA-1 digest over entire image
	CSHA1 hash;
	hash.Reset();
	
	// count of total blocks written to the file
	unsigned fileBlocksWritten = 0;

	// we need some pieces of the header down below
	boot_image_header_t imageHeader;
	prepareImageHeader(imageHeader);
	
	// write plaintext header
	{
		// write header
		assert(sizeOfPaddingForCipherBlocks(sizeof(boot_image_header_t)) == 0);
		stream.write(reinterpret_cast<char *>(&imageHeader), sizeof(imageHeader));
		fileBlocksWritten += numberOfCipherBlocks(sizeof(imageHeader));
		
		// update CBC-MAC over image header
		if (isEncrypted())
		{
			for (i=0; i < m_keys.size(); ++i)
			{
				(macs.get())[i].update(reinterpret_cast<uint8_t *>(&imageHeader), sizeof(imageHeader));
			}
		}
		
		// update SHA-1
		hash.Update(reinterpret_cast<uint8_t *>(&imageHeader), sizeof(imageHeader));
	}
	
	// write plaintext section table
	{
		section_iterator_t it = beginSection();
		for (; it != endSection(); ++it)
		{
			Section * section = *it;
			
			// write header for this section
			assert(sizeOfPaddingForCipherBlocks(sizeof(section_header_t)) == 0);
			section_header_t sectionHeader;
			section->fillSectionHeader(sectionHeader);
			stream.write(reinterpret_cast<char *>(&sectionHeader), sizeof(sectionHeader));
			fileBlocksWritten += numberOfCipherBlocks(sizeof(sectionHeader));
			
			// update CBC-MAC over this entry
			if (isEncrypted())
			{
				for (i=0; i < m_keys.size(); ++i)
				{
					(macs.get())[i].update(reinterpret_cast<uint8_t *>(&sectionHeader), sizeof(sectionHeader));
				}
			}
			
			// update SHA-1
			hash.Update(reinterpret_cast<uint8_t *>(&sectionHeader), sizeof(sectionHeader));
		}
	}
	
	// finished with the CBC-MAC
	if (isEncrypted())
	{
		for (i=0; i < m_keys.size(); ++i)
		{
			(macs.get())[i].finalize();
		}
	}
	
	// write key dictionary
	if (isEncrypted())
	{
		key_iterator_t it = beginKeys();
		for (i=0; it != endKeys(); ++it, ++i)
		{
			// write CBC-MAC result for this key, then update SHA-1
			RijndaelCBCMAC & mac = (macs.get())[i];
			const RijndaelCBCMAC::block_t & macResult = mac.getMAC();
			stream.write(reinterpret_cast<const char *>(&macResult), sizeof(RijndaelCBCMAC::block_t));
			hash.Update(reinterpret_cast<const uint8_t *>(&macResult), sizeof(RijndaelCBCMAC::block_t));
			fileBlocksWritten++;
			
			// encrypt DEK with this key, write it out, and update image digest
			Rijndael cipher;
			cipher.init(Rijndael::CBC, Rijndael::Encrypt, *it, Rijndael::Key16Bytes, imageHeader.m_iv);
			AESKey<128>::key_t wrappedSessionKey;
			cipher.blockEncrypt(m_sessionKey, sizeof(AESKey<128>::key_t) * 8, wrappedSessionKey);
			stream.write(reinterpret_cast<char *>(&wrappedSessionKey), sizeof(wrappedSessionKey));
			hash.Update(reinterpret_cast<uint8_t *>(&wrappedSessionKey), sizeof(wrappedSessionKey));
			fileBlocksWritten++;
		}
	}
	
	// write sections and boot tags
	{
		section_iterator_t it = beginSection();
		for (; it != endSection(); ++it)
		{
			section_iterator_t itCopy = it;
			bool isLastSection = (++itCopy == endSection());
			
			Section * section = *it;
			cipher_block_t block;
			unsigned blockCount = section->getBlockCount();
			unsigned blocksWritten = 0;
			
			Rijndael cipher;
			cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
			
			// Compute the number of padding blocks needed to align the section. This first
			// call to getPadBlockCountForOffset() passes an offset that excludes
			// the boot tag for this section.
			unsigned paddingBlocks = getPadBlockCountForSection(section, fileBlocksWritten);
			
			// Insert nop commands as padding to align the start of the section, if
			// the section has special alignment requirements.
			NopCommand nop;
			while (paddingBlocks--)
			{
				blockCount = nop.getBlockCount();
				blocksWritten = 0;
				while (blocksWritten < blockCount)
				{
					nop.getBlocks(blocksWritten, 1, &block);
					
					if (isEncrypted())
					{
						// re-init after encrypt to update IV
						cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
						cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
					}
					
					stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
					hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
					
					blocksWritten++;
					fileBlocksWritten++;
				}
			}
			
			// reinit cipher for boot tag
			cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
			
			// write boot tag
			TagCommand tag(*section);
			tag.setLast(isLastSection);
			if (!isLastSection)
			{
				// If this isn't the last section, the tag needs to include any
				// padding for the next section in its length, otherwise the ROM
				// won't be able to find the next section's boot tag.
				unsigned nextSectionOffset = fileBlocksWritten + section->getBlockCount() + 1;
				tag.setSectionLength(section->getBlockCount() + getPadBlockCountForSection(*itCopy, nextSectionOffset));
			}
			blockCount = tag.getBlockCount();
			blocksWritten = 0;
			while (blocksWritten < blockCount)
			{
				tag.getBlocks(blocksWritten, 1, &block);
				
				if (isEncrypted())
				{
					// re-init after encrypt to update IV
					cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
					cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
				}
				
				stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
				hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
				
				blocksWritten++;
				fileBlocksWritten++;
			}
			
			// reinit cipher for section data
			cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
			
			// write section data
			blockCount = section->getBlockCount();
			blocksWritten = 0;
			while (blocksWritten < blockCount)
			{
				section->getBlocks(blocksWritten, 1, &block);
				
				// Only encrypt the section contents if the entire boot image is encrypted
				// and the section doesn't have the "leave unencrypted" flag set. Even if the
				// section is unencrypted the boot tag will remain encrypted.
				if (isEncrypted() && !section->getLeaveUnencrypted())
				{
					// re-init after encrypt to update IV
					cipher.blockEncrypt(block, sizeof(cipher_block_t) * 8, block);
					cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, block);
				}
				
				stream.write(reinterpret_cast<char *>(&block), sizeof(cipher_block_t));
				hash.Update(reinterpret_cast<uint8_t *>(&block), sizeof(cipher_block_t));
				
				blocksWritten++;
				fileBlocksWritten++;
			}
		}
	}
	
	// write SHA-1 digest over entire image
	{
		// allocate enough room for digest and bytes to pad out to the next cipher block
		const unsigned padBytes = sizeOfPaddingForCipherBlocks(sizeof(sha1_digest_t));
		unsigned digestBlocksSize = sizeof(sha1_digest_t) + padBytes;
		smart_array_ptr<uint8_t> digestBlocks = new uint8_t[digestBlocksSize];
		hash.Final();
		hash.GetHash(digestBlocks.get());
		
		// set the pad bytes to random values
		RandomNumberGenerator rng;
		rng.generateBlock(&(digestBlocks.get())[sizeof(sha1_digest_t)], padBytes);
		
		// encrypt with session key
		if (isEncrypted())
		{
			Rijndael cipher;
			cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_sessionKey, Rijndael::Key16Bytes, imageHeader.m_iv);
			cipher.blockEncrypt(digestBlocks.get(), digestBlocksSize * 8, digestBlocks.get());
		}
		
		// write to the stream
		stream.write(reinterpret_cast<char *>(digestBlocks.get()), digestBlocksSize);
	}
}
Exemple #4
0
bool App::saveTree()
{
    // backup dir checking (see also preferences.cpp)
    if (preferences.saveBackupFile)
    {
        QDir backupDir(preferences.backupLocation);
        
        if (!backupDir.exists())
        {
            QMessageBox::critical(this, "Invalid directory", "Please, enter the existing\ndirectory in backup location.", 0, 0);
            return false;
        }
    }
    
    QFile saveF(Global::applicationFileName("iqnotes", currentFile + ".xml"));
    QFile rijnF(Global::applicationFileName("iqnotes", currentFile + ".rijn"));

    QString saveS;
    QTextStream saveData(saveS, IO_WriteOnly);
	saveData.setEncoding(saveData.UnicodeUTF8);
	
    saveData << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<iqnotes>\n"
    << "<config>\n"
    << "<backup save=\"" << (preferences.saveBackupFile ? "yes" : "no") << "\" location=\"" << preferences.backupLocation << "\"/>\n"
             << "<notes showreminder=\"" << (preferences.showReminder ? "yes" : "no") << "\" />\n"
    << "<security passwd=\"" << preferences.passwdHex << "\"/>\n"
    << "</config>\n"

    << "<entries>\n";

    for (Entry *e = entriesList->first(); e; e = entriesList->next())
    {
        saveData << "<entry name=\"" << quoteXML(e->getName()) << "\" defaultpic=\"" << quoteXML(e->getDefaultPic()) << "\">\n";

        for (PropertyStruct *ps = e->first(); ps; ps = e->next())
        {
            saveData << "<property name=\"" << quoteXML(ps->getName()) << "\" "
            << "type=\"" << (ps->getType() == PropertyStruct::ONE_LINE ? "oneLine" : "multiLine") << "\"/>\n";
        }

        saveData << "</entry>\n";
    }

    saveData << "</entries>\n";

    notes->saveTree(&saveData);

    saveData << "</iqnotes>\n";
	//SF.close();
    QCString dataUTF8 = saveS.utf8();

    if (!preferences.passwdHex.length())
    {
        saveF.open(IO_WriteOnly);

        QTextStream saveData1(&saveF);
		saveData1.setEncoding(saveData1.UnicodeUTF8);
		saveData1 << saveS;

        if (preferences.saveBackupFile)
        {
            QFile backupSaveF(preferences.backupLocation + "/" + currentFile + ".xml");
            QTextStream saveData2(&backupSaveF);
            backupSaveF.open(IO_WriteOnly);
            saveData2 << dataUTF8;
        }

        if (rijnF.exists())
            rijnF.remove();
    }
    else
    {
        Rijndael rijndael;
        unsigned char *rijnEncrypt = (unsigned char*)malloc(dataUTF8.length() + 16);

        rijnF.open(IO_WriteOnly);

        rijndael.init(Rijndael::CBC, Rijndael::Encrypt, preferences.passwd16Bin, Rijndael::Key16Bytes);
        int len = rijndael.padEncrypt((unsigned char*)(const char*)dataUTF8, dataUTF8.length(), rijnEncrypt);

        rijnF.writeBlock((const char *)rijnEncrypt, len);
        if (preferences.saveBackupFile)
        {
            QFile rijnBackupF(preferences.backupLocation + "/" + currentFile + ".rijn");
            rijnBackupF.open(IO_WriteOnly);
            rijnBackupF.writeBlock((const char *)rijnEncrypt, len);
        }

        free(rijnEncrypt);

        if (saveF.exists())
            saveF.remove();
    }

    return true;
}