Skip to content

Commit

Permalink
Added command to change repo password
Browse files Browse the repository at this point in the history
Also:
- Slight refactoring (zcollector renamed to backup_collector)
- Fixed typo (s/genarate/generate/g)
  • Loading branch information
Vlad1mir-D committed Dec 15, 2014
1 parent bb576a1 commit a331eb0
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 31 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ If you have a 32-bit system and a lot of cores, consider lowering the number of
* While you can pipe any data into the program, the data should be uncompressed and unencrypted -- otherwise no deduplication could be performed on it. `zbackup` would compress and encrypt the data itself, so there's no need to do that yourself. So just run `tar c` and pipe it into `zbackup` directly. If backing up disk images employing encryption, pipe the unencrypted version (the one you normally mount). If you create `.zip` or `.rar` files, use no compression (`-0` or `-m0`) and no encryption.
* Parallel LZMA compression uses a lot of RAM (several hundreds of megabytes, depending on the number of threads used), and ten times more virtual address space. The latter is only relevant on 32-bit architectures where it's limited to 2 or 3 GB. If you hit the ceiling, lower the number of threads with `--threads`.
* Since the data is deduplicated, there's naturally no redundancy in it. A loss of a single file can lead to a loss of virtually all data. Make sure you store it on a redundant storage (RAID1, a cloud provider etc).
* The encryption key, if used, is stored in the `info` file in the root of the repo. It is encrypted with your password. Technically thus you can change your password without re-encrypting any data, and as long as no one possesses the old `info` file and knows your old password, you would be safe (even though the actual option to change password is not implemented yet -- someone who needs this is welcome to create a pull request -- the possibility is all there). Also note that it is crucial you don't lose your `info` file, as otherwise the whole backup would be lost.
* The encryption key, if used, is stored in the `info` file in the root of the repo. It is encrypted with your password. Technically thus you can change your password without re-encrypting any data, and as long as no one possesses the old `info` file and knows your old password, you would be safe (note that ability to change repo type between encrypted and non-encrypted is not implemented yet -- someone who needs this is welcome to create a pull request -- the possibility is all there). Also note that it is crucial you don't lose your `info` file, as otherwise the whole backup would be lost.

# Limitations

Expand Down Expand Up @@ -166,7 +166,7 @@ won't be able to read those bundles.
There's a lot to be improved in the program. It was released with the minimum amount of functionality to be useful. It is also stable. This should hopefully stimulate people to join the development and add all those other fancy features. Here's a list of ideas:

* Additional options, such as configurable chunk and bundle sizes etc.
* A command to change password.
* Ability to change bundle type (between encrypted and non-encrypted).
* Improved garbage collection. The program should support ability to specify maximum index file size / maximum index file count (for better compatibility with cloud storages as well) or something like retention policy.
* A command to fsck the repo by doing something close to what garbage collection does, but also checking all hashes and so on.
* Parallel decompression. Right now decompression is single-threaded, but it is possible to look ahead in the stream and perform prefetching.
Expand Down
2 changes: 1 addition & 1 deletion zcollector.cc → backup_collector.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2012-2014 Konstantin Isakov <[email protected]> and ZBackup contributors, see CONTRIBUTORS
// Part of ZBackup. Licensed under GNU GPLv2 or later + OpenSSL, see LICENSE

#include "zcollector.hh"
#include "backup_collector.hh"

#include <string>
#include <vector>
Expand Down
4 changes: 2 additions & 2 deletions zcollector.hh → backup_collector.hh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright (c) 2012-2014 Konstantin Isakov <[email protected]> and ZBackup contributors, see CONTRIBUTORS
// Part of ZBackup. Licensed under GNU GPLv2 or later + OpenSSL, see LICENSE

#ifndef Z_COLLECTOR_HH_INCLUDED__
#define Z_COLLECTOR_HH_INCLUDED__
#ifndef BACKUP_COLLECTOR_HH_INCLUDED__
#define BACKUP_COLLECTOR_HH_INCLUDED__

#include "zbackup_base.hh"
#include "chunk_storage.hh"
Expand Down
4 changes: 2 additions & 2 deletions chunk_storage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ void Writer::commit()
// Generate a random filename
unsigned char buf[ 24 ]; // Same comments as for Bundle::IdSize

Random::genaratePseudo( buf, sizeof( buf ) );
Random::generatePseudo( buf, sizeof( buf ) );

indexTempFile->moveOverTo( Dir::addPath( indexDir,
toHex( buf, sizeof( buf ) ) ) );
Expand Down Expand Up @@ -152,7 +152,7 @@ Bundle::Id const & Writer::getCurrentBundleId()
if ( !hasCurrentBundleId )
{
// Generate a new one
Random::genaratePseudo( &currentBundleId, sizeof( currentBundleId ) );
Random::generatePseudo( &currentBundleId, sizeof( currentBundleId ) );
hasCurrentBundleId = true;
}

Expand Down
2 changes: 1 addition & 1 deletion encrypted_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ void OutputStream::writeRandomIv()
if ( key.hasKey() )
{
char iv[ Encryption::IvSize ];
Random::genaratePseudo( iv, sizeof( iv ) );
Random::generatePseudo( iv, sizeof( iv ) );
write( iv, sizeof( iv ) );
}
}
Expand Down
15 changes: 9 additions & 6 deletions encryption_key.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,24 +66,27 @@ EncryptionKey::~EncryptionKey()
}

void EncryptionKey::generate( string const & password,
EncryptionKeyInfo & info )
EncryptionKeyInfo & info,
EncryptionKey & encryptionkey )
{
// Use this buf for salts
char buf[ 16 ];
char buf[ KeySize ];

Random::genaratePseudo( buf, sizeof( buf ) );
Random::generatePseudo( buf, sizeof( buf ) );
info.set_salt( buf, sizeof( buf ) );
info.set_rounds( 10000 ); // TODO: make this configurable

char derivedKey[ KeySize ];
deriveKey( password, info, derivedKey, sizeof( derivedKey ) );

char key[ KeySize ];

Random::genarateTrue( key, sizeof( key ) );
if ( encryptionkey.hasKey() )
memcpy( key, encryptionkey.getKey(), KeySize );
else
Random::generateTrue( key, sizeof( key ) );

// Fill in the HMAC verification part
Random::genaratePseudo( buf, sizeof( buf ) );
Random::generatePseudo( buf, sizeof( buf ) );
info.set_key_check_input( buf, sizeof( buf ) );
info.set_key_check_hmac( calculateKeyHmac( key, sizeof( key ),
info.key_check_input() ) );
Expand Down
3 changes: 2 additions & 1 deletion encryption_key.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public:
{ return sizeof( key ); }

/// Generates new key info using the given password
static void generate( string const & password, EncryptionKeyInfo & );
static void generate( string const & password, EncryptionKeyInfo &,
EncryptionKey & encryptionkey );

/// Returns a static instance without any key set
static EncryptionKey const & noKey();
Expand Down
4 changes: 2 additions & 2 deletions random.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
#include <openssl/rand.h>

namespace Random {
void genarateTrue( void * buf, unsigned size )
void generateTrue( void * buf, unsigned size )
{
if ( RAND_bytes( (unsigned char *) buf, size ) != 1 )
throw exCantGenerate();
}

void genaratePseudo( void * buf, unsigned size )
void generatePseudo( void * buf, unsigned size )
{
if ( RAND_pseudo_bytes( (unsigned char *) buf, size ) < 0 )
throw exCantGenerate();
Expand Down
4 changes: 2 additions & 2 deletions random.hh
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ namespace Random {
DEF_EX( exCantGenerate, "Error generating random sequence, try later", std::exception )

/// This one fills the buffer with true randomness, suitable for a key
void genarateTrue( void * buf, unsigned size );
void generateTrue( void * buf, unsigned size );
/// This one fills the buffer with pseudo randomness, suitable for salts but not
/// keys
void genaratePseudo( void * buf, unsigned size );
void generatePseudo( void * buf, unsigned size );
}

#endif
47 changes: 37 additions & 10 deletions zbackup.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include "zbackup.hh"
#include "index_file.hh"
#include "bundle.hh"
#include "zcollector.hh"
#include "backup_collector.hh"

using std::vector;
using std::bitset;
Expand Down Expand Up @@ -321,8 +321,8 @@ void ZExchange::exchange( string const & srcPath, string const & dstPath,
}
}

DEF_EX( exExchangeWithLessThanTwoKeys, "Specify password flag (--non-encrypted or --password-file)"
" for import/export operation twice (first for source and second for destination)", std::exception )
DEF_EX( exSpecifyTwoKeys, "Specify password flag (--non-encrypted or --password-file)"
" for import/export/passwd operation twice (first for source and second for destination)", std::exception )
DEF_EX( exNonEncryptedWithKey, "--non-encrypted and --password-file are incompatible", std::exception )
DEF_EX( exSpecifyEncryptionOptions, "Specify either --password-file or --non-encrypted", std::exception )
DEF_EX_STR( exInvalidThreadsValue, "Invalid threads value specified:", std::exception )
Expand Down Expand Up @@ -491,7 +491,7 @@ int main( int argc, char *argv[] )

"Usage: %s [flags] <command> [command args]\n"
" Flags: --non-encrypted|--password-file <file>\n"
" password flag should be specified twice if import/export\n"
" password flag should be specified twice if import/export/passwd\n"
" command specified\n"
" --silent (default is verbose)\n"
" --threads <number> (default is %zu on your system)\n"
Expand All @@ -508,7 +508,8 @@ int main( int argc, char *argv[] )
" performs export from source to destination storage;\n"
" import <source storage path> <destination storage path> -\n"
" performs import from source to destination storage;\n"
" gc <storage path> - performs chunk garbage collection.\n"
" gc <storage path> - performs chunk garbage collection;\n"
" passwd <storage path> - changes repository info file passphrase.\n"
" For export/import storage path must be valid (initialized) storage.\n"
"", *argv,
defaultThreads, defaultCacheSizeMb );
Expand All @@ -518,12 +519,16 @@ int main( int argc, char *argv[] )
if ( passwords.size() > 1 &&
( ( passwords[ 0 ].empty() && !passwords[ 1 ].empty() ) ||
( !passwords[ 0 ].empty() && passwords[ 1 ].empty() ) ) &&
( strcmp( args[ 0 ], "export" ) != 0 && strcmp( args[ 0 ], "import" ) != 0 ) )
( strcmp( args[ 0 ], "export" ) != 0 &&
strcmp( args[ 0 ], "import" ) != 0 &&
strcmp( args[ 0 ], "passwd" ) ) )
throw exNonEncryptedWithKey();
else
if ( passwords.size() < 2 &&
( strcmp( args[ 0 ], "export" ) == 0 || strcmp( args[ 0 ], "import" ) == 0 ) )
throw exExchangeWithLessThanTwoKeys();
if ( passwords.size() != 2 &&
( strcmp( args[ 0 ], "export" ) == 0 ||
strcmp( args[ 0 ], "import" ) == 0 ||
strcmp( args[ 0 ], "passwd" ) == 0 ) )
throw exSpecifyTwoKeys();
else
if ( passwords.size() < 1 )
throw exSpecifyEncryptionOptions();
Expand Down Expand Up @@ -614,14 +619,36 @@ int main( int argc, char *argv[] )
// Perform the restore
if ( args.size() != 2 )
{
fprintf( stderr, "Usage: %s gc <backup directory>\n",
fprintf( stderr, "Usage: %s gc <storage path>\n",
*argv );
return EXIT_FAILURE;
}
ZCollector zr( args[ 1 ], passwords[ 0 ], threads, cacheSizeMb * 1048576 );
zr.gc();
}
else
if ( strcmp( args[ 0 ], "passwd" ) == 0 )
{
// Perform the password change
if ( args.size() != 2 )
{
fprintf( stderr, "Usage: %s passwd <storage path>\n",
*argv );
return EXIT_FAILURE;
}

ZBackupBase zbb( args[ 1 ], passwords[ 0 ], true );
if ( passwords[ 0 ].empty() != passwords[ 1 ].empty() )
{
fprintf( stderr,
"Changing repo encryption type (non-encrypted to encrypted and vice versa) "
"is not supported yet.\n"
"Current repo type: %s\n", zbb.encryptionkey.hasKey() ? "encrypted" : "non-encrypted" );
return EXIT_FAILURE;
}
zbb.setPassword( passwords[ 1 ] );
}
else
{
fprintf( stderr, "Error: unknown command line option: %s\n", args[ 0 ] );
return EXIT_FAILURE;
Expand Down
18 changes: 16 additions & 2 deletions zbackup_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,15 @@ void ZBackupBase::initStorage( string const & storageDir,
// TODO: make the following configurable
storageInfo.set_chunk_max_size( 65536 );
storageInfo.set_bundle_max_payload_size( 0x200000 );
EncryptionKey encryptionkey = EncryptionKey::noKey();

if ( isEncrypted )
EncryptionKey::generate( password,
*storageInfo.mutable_encryption_key() );
*storageInfo.mutable_encryption_key(),
encryptionkey );

storageInfo.set_default_compression_method( Compression::CompressionMethod::defaultCompression->getName() );
storageInfo.set_default_compression_method(
Compression::CompressionMethod::defaultCompression->getName() );

Paths paths( storageDir );

Expand Down Expand Up @@ -131,3 +134,14 @@ void ZBackupBase::useDefaultCompressionMethod()
Compression::CompressionMethod::defaultCompression = compression;
}

void ZBackupBase::setPassword( string const & password )
{
EncryptionKey::generate( password,
*storageInfo.mutable_encryption_key(), encryptionkey );

StorageInfoFile::save( getStorageInfoPath(), storageInfo );

EncryptionKey encryptionkey( password, storageInfo.has_encryption_key() ?
&storageInfo.encryption_key() : 0 );
}

2 changes: 2 additions & 0 deletions zbackup_base.hh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public:

void useDefaultCompressionMethod();

void setPassword( std::string const & password );

StorageInfo storageInfo;
EncryptionKey encryptionkey;
TmpMgr tmpMgr;
Expand Down

0 comments on commit a331eb0

Please sign in to comment.