mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2025-11-11 19:08:26 -06:00
336 lines
8.1 KiB
C++
336 lines
8.1 KiB
C++
/*
|
|
Copyright (c) 2008 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/Memory.h"
|
|
#include "Common/Crc.h"
|
|
#include "Common/Endian.h"
|
|
#include "EncryptionModeCBC.h"
|
|
|
|
namespace VeraCrypt
|
|
{
|
|
void EncryptionModeCBC::Decrypt (byte *data, uint64 length) const
|
|
{
|
|
if_debug (ValidateState ());
|
|
if_debug (ValidateParameters (data, length));
|
|
|
|
if (IsOuterCBC (Ciphers))
|
|
{
|
|
DecryptBuffer (data, length, Ciphers, (uint32 *) IV.Ptr(), (uint32 *) (IV.Ptr() + WhiteningIVOffset));
|
|
}
|
|
else
|
|
{
|
|
for (CipherList::const_reverse_iterator iCipherList = Ciphers.rbegin();
|
|
iCipherList != Ciphers.rend();
|
|
++iCipherList)
|
|
{
|
|
CipherList cl;
|
|
cl.push_back (*iCipherList);
|
|
|
|
DecryptBuffer (data, length, cl, (uint32 *) IV.Ptr(), (uint32 *) (IV.Ptr() + WhiteningIVOffset));
|
|
}
|
|
}
|
|
}
|
|
|
|
void EncryptionModeCBC::DecryptBuffer (byte *data, uint64 length, const CipherList &ciphers, const uint32 *iv, const uint32 *whitening) const
|
|
{
|
|
size_t blockSize = ciphers.front()->GetBlockSize();
|
|
if (blockSize != 8 && blockSize != 16)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
uint32 *data32 = (uint32 *) data;
|
|
uint32 bufIV[4];
|
|
uint32 ct[4];
|
|
uint64 i;
|
|
|
|
bufIV[0] = iv[0];
|
|
bufIV[1] = iv[1];
|
|
if (blockSize == 16)
|
|
{
|
|
bufIV[2] = iv[2];
|
|
bufIV[3] = iv[3];
|
|
}
|
|
|
|
for (i = 0; i < length / blockSize; i++)
|
|
{
|
|
// Dewhitening
|
|
data32[0] ^= whitening[0];
|
|
data32[1] ^= whitening[1];
|
|
if (blockSize == 16)
|
|
{
|
|
data32[2] ^= whitening[0];
|
|
data32[3] ^= whitening[1];
|
|
}
|
|
|
|
// CBC
|
|
ct[0] = data32[0];
|
|
ct[1] = data32[1];
|
|
if (blockSize == 16)
|
|
{
|
|
ct[2] = data32[2];
|
|
ct[3] = data32[3];
|
|
}
|
|
|
|
for (CipherList::const_reverse_iterator iCipherList = ciphers.rbegin();
|
|
iCipherList != ciphers.rend();
|
|
++iCipherList)
|
|
{
|
|
const Cipher &c = **iCipherList;
|
|
|
|
if (c.GetBlockSize () != blockSize)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
c.DecryptBlock ((byte *) data32);
|
|
}
|
|
|
|
// CBC
|
|
data32[0] ^= bufIV[0];
|
|
data32[1] ^= bufIV[1];
|
|
bufIV[0] = ct[0];
|
|
bufIV[1] = ct[1];
|
|
if (blockSize == 16)
|
|
{
|
|
data32[2] ^= bufIV[2];
|
|
data32[3] ^= bufIV[3];
|
|
bufIV[2] = ct[2];
|
|
bufIV[3] = ct[3];
|
|
}
|
|
|
|
data32 += blockSize / sizeof(*data32);
|
|
}
|
|
|
|
Memory::Erase (bufIV, sizeof (bufIV));
|
|
Memory::Erase (ct, sizeof (ct));
|
|
}
|
|
|
|
void EncryptionModeCBC::DecryptSectorsCurrentThread (byte *data, uint64 sectorIndex, uint64 sectorCount, size_t sectorSize) const
|
|
{
|
|
if_debug (ValidateState ());
|
|
if_debug (ValidateParameters (data, sectorCount, sectorSize));
|
|
|
|
uint32 sectorIV[4];
|
|
uint32 sectorWhitening[2];
|
|
|
|
while (sectorCount--)
|
|
{
|
|
if (IsOuterCBC (Ciphers))
|
|
{
|
|
InitSectorIVAndWhitening (sectorIndex, Ciphers.front()->GetBlockSize(), (uint64 *) IV.Ptr(), sectorIV, sectorWhitening);
|
|
DecryptBuffer (data, sectorSize, Ciphers, sectorIV, sectorWhitening);
|
|
}
|
|
else
|
|
{
|
|
for (CipherList::const_reverse_iterator iCipherList = Ciphers.rbegin();
|
|
iCipherList != Ciphers.rend();
|
|
++iCipherList)
|
|
{
|
|
const Cipher &c = **iCipherList;
|
|
CipherList cl;
|
|
cl.push_back (*iCipherList);
|
|
|
|
InitSectorIVAndWhitening (sectorIndex, c.GetBlockSize(), (uint64 *) IV.Ptr(), sectorIV, sectorWhitening);
|
|
DecryptBuffer (data, sectorSize, cl, sectorIV, sectorWhitening);
|
|
}
|
|
}
|
|
|
|
data += sectorSize;
|
|
sectorIndex++;
|
|
}
|
|
|
|
Memory::Erase (sectorIV, sizeof (sectorIV));
|
|
Memory::Erase (sectorWhitening, sizeof (sectorWhitening));
|
|
}
|
|
|
|
void EncryptionModeCBC::Encrypt (byte *data, uint64 length) const
|
|
{
|
|
if_debug (ValidateState ());
|
|
if_debug (ValidateParameters (data, length));
|
|
|
|
if (IsOuterCBC (Ciphers))
|
|
{
|
|
EncryptBuffer (data, length, Ciphers, (uint32 *) IV.Ptr(), (uint32 *) (IV.Ptr() + WhiteningIVOffset));
|
|
}
|
|
else
|
|
{
|
|
for (CipherList::const_iterator iCipherList = Ciphers.begin();
|
|
iCipherList != Ciphers.end();
|
|
++iCipherList)
|
|
{
|
|
CipherList cl;
|
|
cl.push_back (*iCipherList);
|
|
|
|
EncryptBuffer (data, length, cl, (uint32 *) IV.Ptr(), (uint32 *) (IV.Ptr() + WhiteningIVOffset));
|
|
}
|
|
}
|
|
}
|
|
|
|
void EncryptionModeCBC::EncryptBuffer (byte *data, uint64 length, const CipherList &ciphers, const uint32 *iv, const uint32 *whitening) const
|
|
{
|
|
size_t blockSize = ciphers.front()->GetBlockSize();
|
|
if (blockSize != 8 && blockSize != 16)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
uint32 *data32 = (uint32 *) data;
|
|
uint32 bufIV[4];
|
|
uint64 i;
|
|
|
|
bufIV[0] = iv[0];
|
|
bufIV[1] = iv[1];
|
|
if (blockSize == 16)
|
|
{
|
|
bufIV[2] = iv[2];
|
|
bufIV[3] = iv[3];
|
|
}
|
|
|
|
for (i = 0; i < length / blockSize; i++)
|
|
{
|
|
data32[0] ^= bufIV[0];
|
|
data32[1] ^= bufIV[1];
|
|
if (blockSize == 16)
|
|
{
|
|
data32[2] ^= bufIV[2];
|
|
data32[3] ^= bufIV[3];
|
|
}
|
|
|
|
for (CipherList::const_iterator iCipherList = ciphers.begin();
|
|
iCipherList != ciphers.end();
|
|
++iCipherList)
|
|
{
|
|
const Cipher &c = **iCipherList;
|
|
|
|
if (c.GetBlockSize () != blockSize)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
c.EncryptBlock ((byte *) data32);
|
|
}
|
|
|
|
bufIV[0] = data32[0];
|
|
bufIV[1] = data32[1];
|
|
if (blockSize == 16)
|
|
{
|
|
bufIV[2] = data32[2];
|
|
bufIV[3] = data32[3];
|
|
}
|
|
|
|
data32[0] ^= whitening[0];
|
|
data32[1] ^= whitening[1];
|
|
if (blockSize == 16)
|
|
{
|
|
data32[2] ^= whitening[0];
|
|
data32[3] ^= whitening[1];
|
|
}
|
|
|
|
data32 += blockSize / sizeof(*data32);
|
|
}
|
|
|
|
Memory::Erase (bufIV, sizeof (bufIV));
|
|
}
|
|
|
|
void EncryptionModeCBC::EncryptSectorsCurrentThread (byte *data, uint64 sectorIndex, uint64 sectorCount, size_t sectorSize) const
|
|
{
|
|
if_debug (ValidateState ());
|
|
if_debug (ValidateParameters (data, sectorCount, sectorSize));
|
|
|
|
uint32 sectorIV[4];
|
|
uint32 sectorWhitening[2];
|
|
|
|
while (sectorCount--)
|
|
{
|
|
if (IsOuterCBC (Ciphers))
|
|
{
|
|
InitSectorIVAndWhitening (sectorIndex, Ciphers.front()->GetBlockSize(), (uint64 *) IV.Ptr(), sectorIV, sectorWhitening);
|
|
EncryptBuffer (data, sectorSize, Ciphers, sectorIV, sectorWhitening);
|
|
}
|
|
else
|
|
{
|
|
for (CipherList::const_iterator iCipherList = Ciphers.begin();
|
|
iCipherList != Ciphers.end();
|
|
++iCipherList)
|
|
{
|
|
const Cipher &c = **iCipherList;
|
|
CipherList cl;
|
|
cl.push_back (*iCipherList);
|
|
|
|
InitSectorIVAndWhitening (sectorIndex, c.GetBlockSize(), (uint64 *) IV.Ptr(), sectorIV, sectorWhitening);
|
|
EncryptBuffer (data, sectorSize, cl, sectorIV, sectorWhitening);
|
|
}
|
|
}
|
|
|
|
data += sectorSize;
|
|
sectorIndex++;
|
|
}
|
|
|
|
Memory::Erase (sectorIV, sizeof (sectorIV));
|
|
Memory::Erase (sectorWhitening, sizeof (sectorWhitening));
|
|
}
|
|
|
|
void EncryptionModeCBC::InitSectorIVAndWhitening (uint64 sectorIndex, size_t blockSize, const uint64 *ivSeed, uint32 *iv, uint32 *whitening) const
|
|
{
|
|
if (blockSize != 8 && blockSize != 16)
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
uint64 iv64[4];
|
|
uint32 *iv32 = (uint32 *) iv64;
|
|
|
|
iv64[0] = ivSeed[0] ^ Endian::Little (sectorIndex);
|
|
iv64[1] = ivSeed[1] ^ Endian::Little (sectorIndex);
|
|
iv64[2] = ivSeed[2] ^ Endian::Little (sectorIndex);
|
|
if (blockSize == 16)
|
|
{
|
|
iv64[3] = ivSeed[3] ^ Endian::Little (sectorIndex);
|
|
}
|
|
|
|
iv[0] = iv32[0];
|
|
iv[1] = iv32[1];
|
|
|
|
if (blockSize == 8)
|
|
{
|
|
whitening[0] = Endian::Little ( crc32int ( &iv32[2] ) ^ crc32int ( &iv32[5] ) );
|
|
whitening[1] = Endian::Little ( crc32int ( &iv32[3] ) ^ crc32int ( &iv32[4] ) );
|
|
}
|
|
else
|
|
{
|
|
iv[2] = iv32[2];
|
|
iv[3] = iv32[3];
|
|
|
|
whitening[0] = Endian::Little ( crc32int ( &iv32[4] ) ^ crc32int ( &iv32[7] ) );
|
|
whitening[1] = Endian::Little ( crc32int ( &iv32[5] ) ^ crc32int ( &iv32[6] ) );
|
|
}
|
|
}
|
|
|
|
bool EncryptionModeCBC::IsOuterCBC (const CipherList &ciphers) const
|
|
{
|
|
if (ciphers.size() < 2)
|
|
return false;
|
|
|
|
size_t blockSize = ciphers.front()->GetBlockSize();
|
|
|
|
for (CipherList::const_iterator iCipherList = ciphers.begin();
|
|
iCipherList != ciphers.end();
|
|
++iCipherList)
|
|
{
|
|
const Cipher &c = **iCipherList;
|
|
if (c.GetBlockSize() != blockSize)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void EncryptionModeCBC::SetKey (const ConstBufferPtr &key)
|
|
{
|
|
if (key.Size() != GetKeySize ())
|
|
throw ParameterIncorrect (SRC_POS);
|
|
|
|
if (!KeySet)
|
|
IV.Allocate (GetKeySize ());
|
|
|
|
IV.CopyFrom (key);
|
|
KeySet = true;
|
|
}
|
|
}
|