mirror of
https://github.com/vgough/encfs.git
synced 2024-11-28 19:03:42 +01:00
63c2d1c539
git-svn-id: http://encfs.googlecode.com/svn/trunk@97 db9cf616-1c43-0410-9cb8-a902689de0d6
207 lines
6.3 KiB
C++
207 lines
6.3 KiB
C++
/*****************************************************************************
|
|
* Author: Valient Gough <vgough@pobox.com>
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (c) 2004, Valient Gough
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by the
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "base/base64.h"
|
|
#include "base/Error.h"
|
|
#include "base/i18n.h"
|
|
#include "cipher/CipherV1.h"
|
|
#include "fs/StreamNameIO.h"
|
|
|
|
#include <glog/logging.h>
|
|
|
|
#include <cstring>
|
|
|
|
namespace encfs {
|
|
|
|
static shared_ptr<NameIO> NewStreamNameIO( const Interface &iface,
|
|
const shared_ptr<CipherV1> &cipher )
|
|
{
|
|
return shared_ptr<NameIO>( new StreamNameIO( iface, cipher ) );
|
|
}
|
|
|
|
static bool StreamIO_registered = NameIO::Register("Stream",
|
|
gettext_noop("Stream encoding, keeps filenames as short as possible"),
|
|
StreamNameIO::CurrentInterface(),
|
|
NewStreamNameIO, true);
|
|
|
|
|
|
/*
|
|
- Version 0.1 is for EncFS 0.x support. The difference to 1.0 is that 0.x
|
|
stores the file checksums at the end of the encoded name, where 1.0
|
|
stores them at the beginning.
|
|
|
|
- Version 1.0 is the basic stream encoding mode used since the beginning of
|
|
EncFS. There is a slight difference in filename encodings from EncFS 0.x
|
|
to 1.0.x. This implements just the 1.0.x method.
|
|
|
|
- Version 1.1 adds support for IV chaining. This is transparently
|
|
backward compatible, since older filesystems do not use IV chaining.
|
|
|
|
- Version 2.0 uses full 64 bit IV during IV chaining mode. Prior versions
|
|
used only the 16 bit output from MAC_16. This reduces the theoretical
|
|
possibility (unlikely to make any difference in practice) of two files
|
|
with the same name in different directories ending up with the same
|
|
encrypted name. Added because there is no good reason to chop to 16
|
|
bits.
|
|
|
|
- Version 2.1 adds support for version 0 for EncFS 0.x compatibility.
|
|
*/
|
|
Interface StreamNameIO::CurrentInterface()
|
|
{
|
|
// implement major version 2, 1, and 0
|
|
return makeInterface("nameio/stream", 2, 1, 2);
|
|
}
|
|
|
|
StreamNameIO::StreamNameIO( const Interface &iface,
|
|
const shared_ptr<CipherV1> &cipher )
|
|
: _interface( iface.major() )
|
|
, _cipher( cipher )
|
|
{
|
|
|
|
}
|
|
|
|
StreamNameIO::~StreamNameIO()
|
|
{
|
|
}
|
|
|
|
Interface StreamNameIO::interface() const
|
|
{
|
|
return CurrentInterface();
|
|
}
|
|
|
|
int StreamNameIO::maxEncodedNameLen( int plaintextStreamLen ) const
|
|
{
|
|
int encodedStreamLen = 2 + plaintextStreamLen;
|
|
return B256ToB64Bytes( encodedStreamLen );
|
|
}
|
|
|
|
int StreamNameIO::maxDecodedNameLen( int encodedStreamLen ) const
|
|
{
|
|
int decLen256 = B64ToB256Bytes( encodedStreamLen );
|
|
return decLen256 - 2;
|
|
}
|
|
|
|
int StreamNameIO::encodeName( const char *plaintextName, int length,
|
|
uint64_t *iv, char *encodedName ) const
|
|
{
|
|
uint64_t tmpIV = 0;
|
|
if( iv && _interface >= 2 )
|
|
tmpIV = *iv;
|
|
|
|
unsigned int mac = _cipher->reduceMac16(
|
|
_cipher->MAC_64((const byte *)plaintextName, length, iv ));
|
|
|
|
// add on checksum bytes
|
|
unsigned char *encodeBegin;
|
|
if(_interface >= 1)
|
|
{
|
|
// current versions store the checksum at the beginning
|
|
encodedName[0] = (mac >> 8) & 0xff;
|
|
encodedName[1] = (mac ) & 0xff;
|
|
encodeBegin = (unsigned char *)encodedName+2;
|
|
} else
|
|
{
|
|
// encfs 0.x stored checksums at the end.
|
|
encodedName[length] = (mac >> 8) & 0xff;
|
|
encodedName[length+1] = (mac ) & 0xff;
|
|
encodeBegin = (unsigned char *)encodedName;
|
|
}
|
|
|
|
// stream encode the plaintext bytes
|
|
memcpy( encodeBegin, plaintextName, length );
|
|
_cipher->streamEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV);
|
|
|
|
// convert the entire thing to base 64 ascii..
|
|
int encodedStreamLen = length + 2;
|
|
int encLen64 = B256ToB64Bytes( encodedStreamLen );
|
|
|
|
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen,
|
|
8, 6, true );
|
|
B64ToAscii( (unsigned char *)encodedName, encLen64 );
|
|
|
|
return encLen64;
|
|
}
|
|
|
|
int StreamNameIO::decodeName( const char *encodedName, int length,
|
|
uint64_t *iv, char *plaintextName ) const
|
|
{
|
|
rAssert(length > 2);
|
|
int decLen256 = B64ToB256Bytes( length );
|
|
int decodedStreamLen = decLen256 - 2;
|
|
|
|
if(decodedStreamLen <= 0)
|
|
throw Error("Filename too small to decode");
|
|
|
|
BUFFER_INIT( tmpBuf, 32, (unsigned int)length );
|
|
|
|
// decode into tmpBuf, because this step produces more data then we can fit
|
|
// into the result buffer..
|
|
AsciiToB64( (unsigned char *)tmpBuf, (unsigned char *)encodedName, length );
|
|
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
|
|
|
|
// pull out the checksum value which is used as an initialization vector
|
|
uint64_t tmpIV = 0;
|
|
unsigned int mac;
|
|
if(_interface >= 1)
|
|
{
|
|
// current versions store the checksum at the beginning
|
|
mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8
|
|
| ((unsigned int)((unsigned char)tmpBuf[1]));
|
|
|
|
// version 2 adds support for IV chaining..
|
|
if( iv && _interface >= 2 )
|
|
tmpIV = *iv;
|
|
|
|
memcpy( plaintextName, tmpBuf+2, decodedStreamLen );
|
|
} else
|
|
{
|
|
// encfs 0.x stored checksums at the end.
|
|
mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8
|
|
| ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen+1]));
|
|
|
|
memcpy( plaintextName, tmpBuf, decodedStreamLen );
|
|
}
|
|
|
|
_cipher->streamDecode( (unsigned char *)plaintextName, decodedStreamLen,
|
|
(uint64_t)mac ^ tmpIV );
|
|
|
|
// compute MAC to check with stored value
|
|
unsigned int mac2 = _cipher->reduceMac16(
|
|
_cipher->MAC_64((const byte *)plaintextName, decodedStreamLen, iv));
|
|
|
|
BUFFER_RESET( tmpBuf );
|
|
if(mac2 != mac)
|
|
{
|
|
VLOG(1) << "checksum mismatch: expected " << mac << ", got " << mac2
|
|
<< "on decode of " << decodedStreamLen << " bytes";
|
|
throw Error( "checksum mismatch in filename decode" );
|
|
}
|
|
|
|
return decodedStreamLen;
|
|
}
|
|
|
|
bool StreamNameIO::Enabled()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
} // namespace encfs
|
|
|