mirror of
https://github.com/vgough/encfs.git
synced 2024-11-25 09:23:13 +01:00
d1a9ccdd19
git-svn-id: http://encfs.googlecode.com/svn/trunk@123 db9cf616-1c43-0410-9cb8-a902689de0d6
166 lines
5.8 KiB
C++
166 lines
5.8 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>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace encfs {
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
|
|
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.
|
|
|
|
- Version 3.0 drops Encfs 0.x support.
|
|
*/
|
|
Interface StreamNameIO::CurrentInterface() {
|
|
// implements support for version 3, 2, and 1.
|
|
return makeInterface("nameio/stream", 3, 0, 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;
|
|
}
|
|
|
|
string StreamNameIO::encodeName(const string &plaintextName,
|
|
uint64_t *iv) const {
|
|
uint64_t tmpIV = 0;
|
|
int length = plaintextName.length();
|
|
if (iv && _interface >= 2) tmpIV = *iv;
|
|
|
|
unsigned int mac = _cipher->reduceMac16(_cipher->MAC_64(
|
|
reinterpret_cast<const byte *>(plaintextName.data()), length, iv));
|
|
tmpIV ^= (uint64_t)mac;
|
|
|
|
int encodedStreamLen = length + 2;
|
|
int encLen64 = B256ToB64Bytes(encodedStreamLen);
|
|
|
|
// add on checksum bytes
|
|
vector<byte> encoded(encLen64);
|
|
encoded[0] = static_cast<byte>((mac >> 8) & 0xff);
|
|
encoded[1] = static_cast<byte>((mac) & 0xff);
|
|
|
|
// stream encode the plaintext bytes
|
|
memcpy(&encoded[2], plaintextName.data(), length);
|
|
_cipher->streamEncode(&encoded[2], length, tmpIV);
|
|
|
|
// convert the entire thing to base 64 ascii..
|
|
changeBase2Inline(encoded.data(), encodedStreamLen, 8, 6, true);
|
|
B64ToAscii(encoded.data(), encLen64);
|
|
|
|
return string(encoded.begin(), encoded.end());
|
|
}
|
|
|
|
string StreamNameIO::decodeName(const string &encodedName,
|
|
uint64_t *iv) const {
|
|
int length = encodedName.length();
|
|
rAssert(length > 2);
|
|
int decLen256 = B64ToB256Bytes(length);
|
|
int decodedStreamLen = decLen256 - 2;
|
|
|
|
if (decodedStreamLen <= 0) throw Error("Filename too small to decode");
|
|
|
|
vector<byte> tmpBuf(length, 0);
|
|
|
|
// decode into tmpBuf, because this step produces more data then we can fit
|
|
// into the result buffer..
|
|
memcpy(tmpBuf.data(), encodedName.data(), length);
|
|
AsciiToB64(tmpBuf.data(), length);
|
|
changeBase2Inline(tmpBuf.data(), length, 6, 8, false);
|
|
|
|
// pull out the checksum value which is used as an initialization vector
|
|
uint64_t tmpIV = 0;
|
|
unsigned int mac = ((unsigned int)tmpBuf[0]) << 8 | ((unsigned int)tmpBuf[1]);
|
|
|
|
// version 2 adds support for IV chaining..
|
|
if (iv && _interface >= 2) tmpIV = *iv;
|
|
|
|
tmpIV ^= (uint64_t)mac;
|
|
_cipher->streamDecode(&tmpBuf.at(2), decodedStreamLen, tmpIV);
|
|
|
|
// compute MAC to check with stored value
|
|
unsigned int mac2 = _cipher->reduceMac16(
|
|
_cipher->MAC_64(&tmpBuf.at(2), decodedStreamLen, iv));
|
|
|
|
if (mac2 != mac) {
|
|
VLOG(1) << "checksum mismatch: expected " << mac << ", got " << mac2
|
|
<< "on decode of " << decodedStreamLen << " bytes";
|
|
throw Error("checksum mismatch in filename decode");
|
|
}
|
|
|
|
return string(reinterpret_cast<char*>(&tmpBuf.at(2)), decodedStreamLen);
|
|
}
|
|
|
|
bool StreamNameIO::Enabled() { return true; }
|
|
|
|
} // namespace encfs
|