VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Volume/Keyfile.cpp
blob: e390ee8859ae707365e0b00744eb1664f23dec63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
/*
 Copyright (c) 2008-2009 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.
*/

#include "Platform/Serializer.h"
#include "Common/SecurityToken.h"
#include "Crc32.h"
#include "Keyfile.h"
#include "VolumeException.h"

namespace VeraCrypt
{
	void Keyfile::Apply (const BufferPtr &pool) const
	{
		if (Path.IsDirectory())
			throw ParameterIncorrect (SRC_POS);

		File file;

		Crc32 crc32;
		size_t poolPos = 0;
		uint64 totalLength = 0;
		uint64 readLength;

		SecureBuffer keyfileBuf (File::GetOptimalReadSize());

		if (SecurityToken::IsKeyfilePathValid (Path))
		{
			// Apply keyfile generated by a security token
			vector <byte> keyfileData;
			SecurityToken::GetKeyfileData (SecurityTokenKeyfile (wstring (Path)), keyfileData);

			if (keyfileData.size() < MinProcessedLength)
				throw InsufficientData (SRC_POS, Path);

			for (size_t i = 0; i < keyfileData.size(); i++)
			{
				uint32 crc = crc32.Process (keyfileData[i]);

				pool[poolPos++] += (byte) (crc >> 24);
				pool[poolPos++] += (byte) (crc >> 16);
				pool[poolPos++] += (byte) (crc >> 8);
				pool[poolPos++] += (byte) crc;

				if (poolPos >= pool.Size())
					poolPos = 0;

				if (++totalLength >= MaxProcessedLength)
					break;
			}

			Memory::Erase (&keyfileData.front(), keyfileData.size());
			goto done;
		}

		file.Open (Path, File::OpenRead, File::ShareRead);

		while ((readLength = file.Read (keyfileBuf)) > 0)
		{
			for (size_t i = 0; i < readLength; i++)
			{
				uint32 crc = crc32.Process (keyfileBuf[i]);

				pool[poolPos++] += (byte) (crc >> 24);
				pool[poolPos++] += (byte) (crc >> 16);
				pool[poolPos++] += (byte) (crc >> 8);
				pool[poolPos++] += (byte) crc;

				if (poolPos >= pool.Size())
					poolPos = 0;

				if (++totalLength >= MaxProcessedLength)
					goto done;
			}
		}
done:
		if (totalLength < MinProcessedLength)
			throw InsufficientData (SRC_POS, Path);
	}

	shared_ptr <VolumePassword> Keyfile::ApplyListToPassword (shared_ptr <KeyfileList> keyfiles, shared_ptr <VolumePassword> password)
	{
		if (!password)
			password.reset (new VolumePassword);

		if (!keyfiles || keyfiles->size() < 1)
			return password;

		KeyfileList keyfilesExp;
		HiddenFileWasPresentInKeyfilePath = false;

		// Enumerate directories
		foreach (shared_ptr <Keyfile> keyfile, *keyfiles)
		{
			if (FilesystemPath (*keyfile).IsDirectory())
			{
				size_t keyfileCount = 0;
				foreach_ref (const FilePath &path, Directory::GetFilePaths (*keyfile))
				{
#ifdef TC_UNIX
					// Skip hidden files
					if (wstring (path.ToBaseName()).find (L'.') == 0)
					{
						HiddenFileWasPresentInKeyfilePath = true;
						continue;
					}
#endif
					keyfilesExp.push_back (make_shared <Keyfile> (path));
					++keyfileCount;
				}

				if (keyfileCount == 0)
					throw KeyfilePathEmpty (SRC_POS, FilesystemPath (*keyfile));
			}
			else
			{
				keyfilesExp.push_back (keyfile);
			}
		}

		make_shared_auto (VolumePassword, newPassword);

		if (keyfilesExp.size() < 1)
		{
			newPassword->Set (*password);
		}
		else
		{
			SecureBuffer keyfilePool (VolumePassword::MaxSize);

			// Pad password with zeros if shorter than max length
			keyfilePool.Zero();
			keyfilePool.CopyFrom (ConstBufferPtr (password->DataPtr(), password->Size()));

			// Apply all keyfiles
			foreach_ref (const Keyfile &k, keyfilesExp)
			{
				k.Apply (keyfilePool);
			}

			newPassword->Set (keyfilePool);
		}

		return newPassword;
	}

	shared_ptr <KeyfileList> Keyfile::DeserializeList (shared_ptr <Stream> stream, const string &name)
	{
		shared_ptr <KeyfileList> keyfiles;
		Serializer sr (stream);
		
		if (!sr.DeserializeBool (name + "Null"))
		{
			keyfiles.reset (new KeyfileList);
			foreach (const wstring &k, sr.DeserializeWStringList (name))
				keyfiles->push_back (make_shared <Keyfile> (k));
		}
		return keyfiles;
	}

	void Keyfile::SerializeList (shared_ptr <Stream> stream, const string &name, shared_ptr <KeyfileList> keyfiles)
	{
		Serializer sr (stream);
		sr.Serialize (name + "Null", keyfiles == nullptr);
		if (keyfiles)
		{
			list <wstring> sl;

			foreach_ref (const Keyfile &k, *keyfiles)
				sl.push_back (FilesystemPath (k));

			sr.Serialize (name, sl);
		}
	}

	bool Keyfile::HiddenFileWasPresentInKeyfilePath = false;
}
pan>); if (h) { { // DWORD_PTR prevMask = SetThreadAffinityMask(h, (DWORD_PTR)affinity); /* if (prevMask == 0) { // affinity change is non-critical error, so we can ignore it // wres = GetError(); } */ } { DWORD prevSuspendCount = ResumeThread(h); /* ResumeThread() returns: 0 : was_not_suspended 1 : was_resumed -1 : error */ if (prevSuspendCount == (DWORD)-1) wres = GetError(); } } /* maybe we must use errno here, but probably GetLastError() is also OK. */ return wres; #endif } static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) { *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); return HandleToWRes(*p); } WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) { // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore() *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); return HandleToWRes(*p); } WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) { // if (Semaphore_IsCreated(p)) { WRes wres = Semaphore_Close(p); if (wres != 0) return wres; } return Semaphore_Create(p, initCount, maxCount); } static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) { return Semaphore_Release(p, (LONG)num, NULL); } WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } WRes CriticalSection_Init(CCriticalSection *p) { /* InitializeCriticalSection() can raise exception: Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception Windows Vista+ : no exceptions */ #ifdef _MSC_VER #ifdef __clang__ #pragma GCC diagnostic ignored "-Wlanguage-extension-token" #endif __try #endif { InitializeCriticalSection(p); /* InitializeCriticalSectionAndSpinCount(p, 0); */ } #ifdef _MSC_VER __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; } #endif return 0; } #else // _WIN32 // ---------- POSIX ---------- #ifndef __APPLE__ #ifndef Z7_AFFINITY_DISABLE // _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET // clang < 3.6 : unknown warning group '-Wreserved-id-macro' // clang 3.6 - 12.01 : gives warning "macro name is a reserved identifier" // clang >= 13 : do not give warning #if !defined(_GNU_SOURCE) #if defined(__clang__) && (__clang_major__ >= 4) && (__clang_major__ <= 12) #pragma GCC diagnostic ignored "-Wreserved-id-macro" #endif #define _GNU_SOURCE #endif // !defined(_GNU_SOURCE) #endif // Z7_AFFINITY_DISABLE #endif // __APPLE__ #include "Threads.h" #include <errno.h> #include <stdlib.h> #include <string.h> #ifdef Z7_AFFINITY_SUPPORTED // #include <sched.h> #endif // #include <stdio.h> // #define PRF(p) p #define PRF(p) #define Print(s) PRF(printf("\n%s\n", s);) WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet) { // new thread in Posix probably inherits affinity from parrent thread Print("Thread_Create_With_CpuSet") pthread_attr_t attr; int ret; // int ret2; p->_created = 0; RINOK(pthread_attr_init(&attr)) ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if (!ret) { if (cpuSet) { #ifdef Z7_AFFINITY_SUPPORTED /* printf("\n affinity :"); unsigned i; for (i = 0; i < sizeof(*cpuSet) && i < 8; i++) { Byte b = *((const Byte *)cpuSet + i); char temp[32]; #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) temp[0] = GET_HEX_CHAR((b & 0xF)); temp[1] = GET_HEX_CHAR((b >> 4)); // temp[0] = GET_HEX_CHAR((b >> 4)); // big-endian // temp[1] = GET_HEX_CHAR((b & 0xF)); // big-endian temp[2] = 0; printf("%s", temp); } printf("\n"); */ // ret2 = pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet); // if (ret2) ret = ret2; #endif } ret = pthread_create(&p->_tid, &attr, func, param); if (!ret) { p->_created = 1; /* if (cpuSet) { // ret2 = pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet); // if (ret2) ret = ret2; } */ } } // ret2 = pthread_attr_destroy(&attr); // if (ret2 != 0) ret = ret2; return ret; } WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) { return Thread_Create_With_CpuSet(p, func, param, NULL); } WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) { Print("Thread_Create_WithAffinity") CCpuSet cs; unsigned i; CpuSet_Zero(&cs); for (i = 0; i < sizeof(affinity) * 8; i++) { if (affinity == 0) break; if (affinity & 1) { CpuSet_Set(&cs, i); } affinity >>= 1; } return Thread_Create_With_CpuSet(p, func, param, &cs); } WRes Thread_Close(CThread *p) { // Print("Thread_Close") int ret; if (!p->_created) return 0; ret = pthread_detach(p->_tid); p->_tid = 0; p->_created = 0; return ret; } WRes Thread_Wait_Close(CThread *p) { // Print("Thread_Wait_Close") void *thread_return; int ret; if (!p->_created) return EINVAL; ret = pthread_join(p->_tid, &thread_return); // probably we can't use that (_tid) after pthread_join(), so we close thread here p->_created = 0; p->_tid = 0; return ret; } static WRes Event_Create(CEvent *p, int manualReset, int signaled) { RINOK(pthread_mutex_init(&p->_mutex, NULL)) RINOK(pthread_cond_init(&p->_cond, NULL)) p->_manual_reset = manualReset; p->_state = (signaled ? True : False); p->_created = 1; return 0; } WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, True, signaled); } WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, False, signaled); } WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } WRes Event_Set(CEvent *p) { RINOK(pthread_mutex_lock(&p->_mutex)) p->_state = True; int res1 = pthread_cond_broadcast(&p->_cond); int res2 = pthread_mutex_unlock(&p->_mutex); return (res2 ? res2 : res1); } WRes Event_Reset(CEvent *p) { RINOK(pthread_mutex_lock(&p->_mutex)) p->_state = False; return pthread_mutex_unlock(&p->_mutex); } WRes Event_Wait(CEvent *p) { RINOK(pthread_mutex_lock(&p->_mutex)) while (p->_state == False) { // ETIMEDOUT // ret = pthread_cond_wait(&p->_cond, &p->_mutex); // if (ret != 0) break; } if (p->_manual_reset == False) { p->_state = False; } return pthread_mutex_unlock(&p->_mutex); } WRes Event_Close(CEvent *p) { if (!p->_created) return 0; p->_created = 0; { int res1 = pthread_mutex_destroy(&p->_mutex); int res2 = pthread_cond_destroy(&p->_cond); return (res1 ? res1 : res2); } } WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) { if (initCount > maxCount || maxCount < 1) return EINVAL; RINOK(pthread_mutex_init(&p->_mutex, NULL)) RINOK(pthread_cond_init(&p->_cond, NULL)) p->_count = initCount; p->_maxCount = maxCount; p->_created = 1; return 0; } WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) { if (Semaphore_IsCreated(p)) { /* WRes wres = Semaphore_Close(p); if (wres != 0) return wres; */ if (initCount > maxCount || maxCount < 1) return EINVAL; // return EINVAL; // for debug p->_count = initCount; p->_maxCount = maxCount; return 0; } return Semaphore_Create(p, initCount, maxCount); } WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount) { UInt32 newCount; int ret; if (releaseCount < 1) return EINVAL; RINOK(pthread_mutex_lock(&p->_mutex)) newCount = p->_count + releaseCount; if (newCount > p->_maxCount) ret = ERROR_TOO_MANY_POSTS; // EINVAL; else { p->_count = newCount; ret = pthread_cond_broadcast(&p->_cond); } RINOK(pthread_mutex_unlock(&p->_mutex)) return ret; } WRes Semaphore_Wait(CSemaphore *p) { RINOK(pthread_mutex_lock(&p->_mutex)) while (p->_count < 1) { pthread_cond_wait(&p->_cond, &p->_mutex); } p->_count--; return pthread_mutex_unlock(&p->_mutex); } WRes Semaphore_Close(CSemaphore *p) { if (!p->_created) return 0; p->_created = 0; { int res1 = pthread_mutex_destroy(&p->_mutex); int res2 = pthread_cond_destroy(&p->_cond); return (res1 ? res1 : res2); } } WRes CriticalSection_Init(CCriticalSection *p) { // Print("CriticalSection_Init") if (!p) return EINTR; return pthread_mutex_init(&p->_mutex, NULL); } void CriticalSection_Enter(CCriticalSection *p) { // Print("CriticalSection_Enter") if (p) { // int ret = pthread_mutex_lock(&p->_mutex); } } void CriticalSection_Leave(CCriticalSection *p) { // Print("CriticalSection_Leave") if (p) { // int ret = pthread_mutex_unlock(&p->_mutex); } } void CriticalSection_Delete(CCriticalSection *p) { // Print("CriticalSection_Delete") if (p) { // int ret = pthread_mutex_destroy(&p->_mutex); } } LONG InterlockedIncrement(LONG volatile *addend) { // Print("InterlockedIncrement") #ifdef USE_HACK_UNSAFE_ATOMIC LONG val = *addend + 1; *addend = val; return val; #else #if defined(__clang__) && (__clang_major__ >= 8) #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst" #endif return __sync_add_and_fetch(addend, 1); #endif } #endif // _WIN32 WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p) { if (Event_IsCreated(p)) return Event_Reset(p); return AutoResetEvent_CreateNotSignaled(p); } #undef PRF #undef Print