diff options
Diffstat (limited to 'src/Volume/Keyfile.cpp')
-rw-r--r-- | src/Volume/Keyfile.cpp | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/Volume/Keyfile.cpp b/src/Volume/Keyfile.cpp new file mode 100644 index 00000000..d132dbb8 --- /dev/null +++ b/src/Volume/Keyfile.cpp @@ -0,0 +1,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 TrueCrypt +{ + 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; +} |