mirror of
https://github.com/vgough/encfs.git
synced 2024-11-22 16:03:34 +01:00
a89752dfe7
git-svn-id: http://encfs.googlecode.com/svn/trunk@121 db9cf616-1c43-0410-9cb8-a902689de0d6
178 lines
6.3 KiB
C++
178 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
|