; ; Copyright (c) 2010 TrueCrypt Developers Association. All rights reserved. ; ; Governed by the TrueCrypt License 3.0 the full text of which is contained in ; the file License.txt included in TrueCrypt binary and source code distribution ; packages. ; %ifidn __BITS__, 16 %define R e %elifidn __BITS__, 32 %define R e %elifidn __BITS__, 64 %define R r %endif %macro export_function 1-2 0 %ifdef MS_STDCALL global %1@%2 export _%1@%2 %1@%2: %elifidn __BITS__, 16 global _%1 _%1: %else global %1 %1: %endif %endmacro %macro aes_function_entry 1 ; void (const byte *ks, byte *data); export_function %1, 8 %ifidn __BITS__, 32 mov ecx, [esp + 4 + 4 * 0] mov edx, [esp + 4 + 4 * 1] %elifidn __BITS__, 64 %ifnidn __OUTPUT_FORMAT__, win64 mov rcx, rdi mov rdx, rsi %endif %endif ; ecx/rcx = ks ; edx/rdx = data %endmacro %macro aes_function_exit 0 ; void (const byte *, byte *); %ifdef MS_STDCALL ret 8 %else ret %endif %endmacro %macro push_xmm 2 sub rsp, 16 * (%2 - %1 + 1) %assign stackoffset 0 %assign regnumber %1 %rep (%2 - %1 + 1) movdqu [rsp + 16 * stackoffset], xmm%[regnumber] %assign stackoffset stackoffset+1 %assign regnumber regnumber+1 %endrep %endmacro %macro pop_xmm 2 %assign stackoffset 0 %assign regnumber %1 %rep (%2 - %1 + 1) movdqu xmm%[regnumber], [rsp + 16 * stackoffset] %assign stackoffset stackoffset+1 %assign regnumber regnumber+1 %endrep add rsp, 16 * (%2 - %1 + 1) %endmacro %macro aes_hw_cpu 2 %define OPERATION %1 %define BLOCK_COUNT %2 ; Load data blocks %assign block 1 %rep BLOCK_COUNT movdqu xmm%[block], [%[R]dx + 16 * (block - 1)] %assign block block+1 %endrep ; Encrypt/decrypt data blocks %assign round 0 %rep 15 movdqu xmm0, [%[R]cx + 16 * round] %assign block 1 %rep BLOCK_COUNT %if round = 0 pxor xmm%[block], xmm0 %else %if round < 14 aes%[OPERATION] xmm%[block], xmm0 %else aes%[OPERATION]last xmm%[block], xmm0 %endif %endif %assign block block+1 %endrep %assign round round+1 %endrep ; Store data blocks %assign block 1 %rep BLOCK_COUNT movdqu [%[R]dx + 16 * (block - 1)], xmm%[block] %assign block block+1 %endrep %undef OPERATION %undef BLOCK_COUNT %endmacro %macro aes_hw_cpu_32_blocks 1 %define OPERATION_32_BLOCKS %1 %ifidn __BITS__, 64 %define MAX_REG_BLOCK_COUNT 15 %else %define MAX_REG_BLOCK_COUNT 7 %endif %ifidn __OUTPUT_FORMAT__, win64 %if MAX_REG_BLOCK_COUNT > 5 push_xmm 6, MAX_REG_BLOCK_COUNT %endif %endif mov eax, 32 / MAX_REG_BLOCK_COUNT .1: aes_hw_cpu %[OPERATION_32_BLOCKS], MAX_REG_BLOCK_COUNT add %[R]dx, 16 * MAX_REG_BLOCK_COUNT dec eax jnz .1 %if (32 % MAX_REG_BLOCK_COUNT) != 0 aes_hw_cpu %[OPERATION_32_BLOCKS], (32 % MAX_REG_BLOCK_COUNT) %endif %ifidn __OUTPUT_FORMAT__, win64 %if MAX_REG_BLOCK_COUNT > 5 pop_xmm 6, MAX_REG_BLOCK_COUNT %endif %endif %undef OPERATION_32_BLOCKS %undef MAX_REG_BLOCK_COUNT %endmacro %ifidn __BITS__, 16 USE16 SEGMENT _TEXT PUBLIC CLASS=CODE USE16 SEGMENT _DATA PUBLIC CLASS=DATA USE16 GROUP DGROUP _TEXT _DATA SECTION _TEXT %else SECTION .text %endif ; void aes_hw_cpu_enable_sse (); export_function aes_hw_cpu_enable_sse mov %[R]ax, cr4 or ax, 1 << 9 mov cr4, %[R]ax ret %ifidn __BITS__, 16 ; byte is_aes_hw_cpu_supported (); export_function is_aes_hw_cpu_supported mov eax, 1 cpuid mov eax, ecx shr eax, 25 and al, 1 ret ; void aes_hw_cpu_decrypt (const byte *ks, byte *data); export_function aes_hw_cpu_decrypt mov ax, -16 jmp aes_hw_cpu_encrypt_decrypt ; void aes_hw_cpu_encrypt (const byte *ks, byte *data); export_function aes_hw_cpu_encrypt mov ax, 16 aes_hw_cpu_encrypt_decrypt: push bp mov bp, sp push di push si mov si, [bp + 4] ; ks mov di, [bp + 4 + 2] ; data movdqu xmm0, [si] movdqu xmm1, [di] pxor xmm1, xmm0 mov cx, 13 .round1_13: add si, ax movdqu xmm0, [si] cmp ax, 0 jl .decrypt aesenc xmm1, xmm0 jmp .2 .decrypt: aesdec xmm1, xmm0 .2: loop .round1_13 add si, ax movdqu xmm0, [si] cmp ax, 0 jl .decrypt_last aesenclast xmm1, xmm0 jmp .3 .decrypt_last: aesdeclast xmm1, xmm0 .3: movdqu [di], xmm1 pop si pop di pop bp ret %else ; __BITS__ != 16 ; byte is_aes_hw_cpu_supported (); ; We comment this since we have an alternative C implementation ; that supports Hyper-V detection workaround ; ; export_function is_aes_hw_cpu_supported ; push %[R]bx ; ; mov eax, 1 ; cpuid ; mov eax, ecx ; shr eax, 25 ; and eax, 1 ; ; pop %[R]bx ; ret ; void aes_hw_cpu_decrypt (const byte *ks, byte *data); aes_function_entry aes_hw_cpu_decrypt aes_hw_cpu dec, 1 aes_function_exit ; void aes_hw_cpu_decrypt_32_blocks (const byte *ks, byte *data); aes_function_entry aes_hw_cpu_decrypt_32_blocks aes_hw_cpu_32_blocks dec aes_function_exit ; void aes_hw_cpu_encrypt (const byte *ks, byte *data); aes_function_entry aes_hw_cpu_encrypt aes_hw_cpu enc, 1 aes_function_exit ; void aes_hw_cpu_encrypt_32_blocks (const byte *ks, byte *data); aes_function_entry aes_hw_cpu_encrypt_32_blocks aes_hw_cpu_32_blocks enc aes_function_exit %endif ; __BITS__ != 16 ='n60' href='#n60'>60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
/*
 Derived from source code of TrueCrypt 7.1a, which is
 Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
 by the TrueCrypt License 3.0.

 Modifications and additions to the original source code (contained in this file) 
 and all other portions of this file are Copyright (c) 2013-2015 IDRIX
 and are governed by the Apache License 2.0 the full text of which is
 contained in the file License.txt included in VeraCrypt binary and source
 code distribution packages.
*/

#include "System.h"
#include <wx/tokenzr.h>
#include "Platform/FileStream.h"
#include "Xml.h"

namespace VeraCrypt
{
	XmlParser::XmlParser (const FilePath &fileName)
	{
		make_shared_auto (File, file);
		file->Open (fileName);
		FileStream stream (file);

		XmlText = wxString::FromUTF8 (stream.ReadToEnd().c_str());
	}

	wxString XmlParser::ConvertEscapedChars (wxString xmlString) const
	{
		xmlString.Replace (L"&lt;", L"<");
		xmlString.Replace (L"&gt;", L">");
		xmlString.Replace (L"&amp;", L"&");
		xmlString.Replace (L"&quot;", L"\"");
		return xmlString;
	}

	XmlNodeList XmlParser::GetNodes (const wxString &nodeName) const
	{
		XmlNodeList nodeList;

		size_t nodePos = 0;
		while ((nodePos = XmlText.find (L"<" + nodeName, nodePos)) != string::npos)
		{
			XmlNode xmlNode;
			xmlNode.Name = nodeName;

			size_t nodeEnd = XmlText.find (L">", nodePos);
			if (nodeEnd == string::npos)
				throw ParameterIncorrect (SRC_POS);

			wxString nodeTagText = XmlText.substr (nodePos + 1, nodeEnd - nodePos - 1);
			nodePos = nodeEnd;

			if (nodeTagText.size() > nodeName.size() && nodeTagText[nodeName.size()] != L' ' && nodeTagText[nodeName.size()] != L'/')
				continue;

			nodeTagText = nodeTagText.substr (nodeName.size());


			// Attributes
			wxStringTokenizer tokenizer (nodeTagText, L"\"", wxTOKEN_RET_EMPTY);
			while (tokenizer.HasMoreTokens())
			{
				wxString attributeName = tokenizer.GetNextToken();
				attributeName.Replace (L" ", L"", true);
				attributeName.Replace (L"=", L"");

				if (!attributeName.empty() && tokenizer.HasMoreTokens())
				{
					wxString attributeText = tokenizer.GetNextToken();
					xmlNode.Attributes[attributeName] = ConvertEscapedChars (attributeText);
				}
			}

			// Inner text
			if (!nodeTagText.EndsWith (L"/"))
			{
				size_t innerTextPos = nodeEnd + 1;
				size_t innerTextEnd = XmlText.find (L"</" + nodeName + L">", innerTextPos);
				if (innerTextEnd == string::npos)
					throw ParameterIncorrect (SRC_POS);

				xmlNode.InnerText = ConvertEscapedChars (XmlText.substr (innerTextPos, innerTextEnd - innerTextPos));
				nodePos = innerTextEnd;
			}

			nodeList.push_back (xmlNode);
		}

		return nodeList;
	}

	XmlWriter::XmlWriter (const FilePath &fileName)
	{
		MemOutStream.reset (new wxMemoryOutputStream);
		TextOutStream.reset (new wxTextOutputStream (*MemOutStream));
		OutFile.Open (fileName, File::CreateWrite);

		*TextOutStream << L"<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl << L"<VeraCrypt>" << endl;
		CurrentIndentLevel = 0;
	}

	void XmlWriter::Close()
	{
		if (MemOutStream.get())
		{
			*TextOutStream << L"</VeraCrypt>" << endl;

			wxStreamBuffer *buf = MemOutStream->GetOutputStreamBuffer();
			OutFile.Write (ConstBufferPtr (reinterpret_cast <byte *> (buf->GetBufferStart()), buf->GetBufferSize()));
			OutFile.Close();

			TextOutStream.reset();
			MemOutStream.reset();
		}
	}

	wxString XmlWriter::EscapeChars (wxString rawString) const
	{
		rawString.Replace (L"<", L"&lt;");
		rawString.Replace (L">", L"&gt;");
		rawString.Replace (L"&", L"&amp;");
		rawString.Replace (L"\"", L"&quot;");
		return rawString;
	}

	void XmlWriter::WriteNode (const XmlNode &xmlNode)
	{
		XmlNodeList nodes;
		nodes.push_back (xmlNode);
		WriteNodes (nodes);
	}

	void XmlWriter::WriteNodes (const XmlNodeList &xmlNodes)
	{
		CurrentIndentLevel++;
		wxString indent;
		for (int i = 0; i < CurrentIndentLevel; ++i)
			indent += L"\t";

		foreach (const XmlNode &node, xmlNodes)
		{
			*TextOutStream << indent << L"<" << node.Name;

			typedef pair <wxString, wxString> AttribPair;
			foreach (AttribPair attrib, node.Attributes)
			{
				*TextOutStream << L" " << attrib.first << L"=\"" << EscapeChars (attrib.second) << L"\"";
			}

			if (!node.InnerNodes.empty())
			{
				*TextOutStream << L">" << endl;
				WriteNodes (node.InnerNodes);
				*TextOutStream << indent;
			}
			else if (!node.InnerText.empty())
			{
				*TextOutStream << L">" << EscapeChars (node.InnerText);
			}
			else
			{
				*TextOutStream << L"/>" << endl;
				continue;
			}

			*TextOutStream << L"</" << node.Name << L">" << endl;
		}

		CurrentIndentLevel--;
	}

	XmlWriter::~XmlWriter ()
	{
		try
		{
			Close();
		}
		catch (...) { }
	}
}