Merge tag '0.6.0' into debian

This commit is contained in:
Andrew Ayer
2017-11-26 10:27:44 -08:00
20 changed files with 321 additions and 136 deletions

14
INSTALL
View File

@@ -2,19 +2,19 @@ DEPENDENCIES
To build git-crypt, you need:
Debian/Ubuntu package RHEL/CentOS package
Debian/Ubuntu package RHEL/CentOS package
-----------------------------------------------------------------------------
Make make make
A C++ compiler (e.g. gcc) g++ gcc-c++
OpenSSL development files libssl-dev openssl-devel
Make make make
A C++11 compiler (e.g. gcc 4.9+) g++ gcc-c++
OpenSSL development files libssl-dev openssl-devel
To use git-crypt, you need:
Debian/Ubuntu package RHEL/CentOS package
Debian/Ubuntu package RHEL/CentOS package
-----------------------------------------------------------------------------
Git 1.7.2 or newer git git
OpenSSL openssl openssl
Git 1.7.2 or newer git git
OpenSSL openssl openssl
Note: Git 1.8.5 or newer is recommended for best performance.

View File

@@ -2,19 +2,19 @@
To build git-crypt, you need:
| Debian/Ubuntu package | RHEL/CentOS package
---------------------------|-----------------------|------------------------
Make | make | make
A C++ compiler (e.g. gcc) | g++ | gcc-c++
OpenSSL development files | libssl-dev | openssl-devel
| Software | Debian/Ubuntu package | RHEL/CentOS package|
|---------------------------------|-----------------------|--------------------|
|Make | make | make |
|A C++11 compiler (e.g. gcc 4.9+) | g++ | gcc-c++ |
|OpenSSL development files | libssl-dev | openssl-devel |
To use git-crypt, you need:
| Debian/Ubuntu package | RHEL/CentOS package
---------------------------|-----------------------|------------------------
Git 1.7.2 or newer | git | git
OpenSSL | openssl | openssl
| Software | Debian/Ubuntu package | RHEL/CentOS package|
|---------------------------------|-----------------------|--------------------|
|Git 1.7.2 or newer | git | git |
|OpenSSL | openssl | openssl |
Note: Git 1.8.5 or newer is recommended for best performance.

View File

@@ -5,6 +5,7 @@
#
CXXFLAGS ?= -Wall -pedantic -Wno-long-long -O2
CXXFLAGS += -std=c++11
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man
@@ -23,7 +24,7 @@ OBJFILES = \
coprocess.o \
fhstream.o
OBJFILES += crypto-openssl.o
OBJFILES += crypto-openssl-10.o crypto-openssl-11.o
LDFLAGS += -lcrypto
XSLTPROC ?= xsltproc
@@ -54,7 +55,7 @@ coprocess.o: coprocess.cpp coprocess-unix.cpp coprocess-win32.cpp
build-man: man/man1/git-crypt.1
man/man1/git-crypt.1: man/git-crypt.xml
$(XSLTPROC) $(DOCBOOK_FLAGS) $(DOCBOOK_XSL) $<
$(XSLTPROC) $(DOCBOOK_FLAGS) $(DOCBOOK_XSL) man/git-crypt.xml
#
# Clean

13
NEWS
View File

@@ -1,3 +1,16 @@
v0.6.0 (2017-11-26)
* Add support for OpenSSL 1.1 (still works with OpenSSL 1.0).
* Switch to C++11 (gcc 4.9 or higher now required to build).
* Allow GPG to fail on some keys (makes unlock work better if there are
multiple keys that can unlock the repo but only some are available).
* Allow the repo state directory to be configured with the
git-crypt.repoStateDir git config option.
* Respect the gpg.program git config option.
* Don't hard code path to git-crypt in .git/config on Linux (ensures
repo continues to work if git-crypt is moved).
* Ensure git-crypt's gpg files won't be treated as text by Git.
* Minor improvements to build system, documentation.
v0.5.0 (2015-05-30)
* Drastically speed up lock/unlock when used with Git 1.8.5 or newer.
* Add git-crypt(1) man page (pass ENABLE_MAN=yes to make to build).

13
NEWS.md
View File

@@ -1,6 +1,19 @@
News
====
######v0.6.0 (2017-11-26)
* Add support for OpenSSL 1.1 (still works with OpenSSL 1.0).
* Switch to C++11 (gcc 4.9 or higher now required to build).
* Allow GPG to fail on some keys (makes unlock work better if there are
multiple keys that can unlock the repo but only some are available).
* Allow the repo state directory to be configured with the
git-crypt.repoStateDir git config option.
* Respect the gpg.program git config option.
* Don't hard code path to git-crypt in .git/config on Linux (ensures
repo continues to work if git-crypt is moved).
* Ensure git-crypt's gpg files won't be treated as text by Git.
* Minor improvements to build system, documentation.
######v0.5.0 (2015-05-30)
* Drastically speed up lock/unlock when used with Git 1.8.5 or newer.
* Add git-crypt(1) man page (pass `ENABLE_MAN=yes` to make to build).

6
README
View File

@@ -69,7 +69,7 @@ encryption and decryption happen transparently.
CURRENT STATUS
The latest version of git-crypt is 0.5.0, released on 2015-05-30.
The latest version of git-crypt is 0.6.0, released on 2017-11-26.
git-crypt aims to be bug-free and reliable, meaning it shouldn't
crash, malfunction, or expose your confidential data. However,
it has not yet reached maturity, meaning it is not as documented,
@@ -79,7 +79,7 @@ backwards-incompatible changes introduced before version 1.0.
SECURITY
git-crypt is more secure that other transparent git encryption systems.
git-crypt is more secure than other transparent git encryption systems.
git-crypt encrypts files using AES-256 in CTR mode with a synthetic IV
derived from the SHA-1 HMAC of the file. This mode of operation is
provably semantically secure under deterministic chosen-plaintext attack.
@@ -98,7 +98,7 @@ all of the files in a repository. Where git-crypt really shines is where
most of your repository is public, but you have a few files (perhaps
private keys named *.key, or a file with API credentials) which you
need to encrypt. For encrypting an entire repository, consider using a
system like git-remote-gcrypt <https://github.com/joeyh/git-remote-gcrypt>
system like git-remote-gcrypt <https://spwhitton.name/tech/code/git-remote-gcrypt/>
instead. (Note: no endorsement is made of git-remote-gcrypt's security.)
git-crypt does not encrypt file names, commit messages, symlink targets,

View File

@@ -70,8 +70,8 @@ encryption and decryption happen transparently.
Current Status
--------------
The latest version of git-crypt is [0.5.0](NEWS.md), released on
2015-05-30. git-crypt aims to be bug-free and reliable, meaning it
The latest version of git-crypt is [0.6.0](NEWS.md), released on
2017-11-26. git-crypt aims to be bug-free and reliable, meaning it
shouldn't crash, malfunction, or expose your confidential data.
However, it has not yet reached maturity, meaning it is not as
documented, featureful, or easy-to-use as it should be. Additionally,
@@ -81,7 +81,7 @@ there may be backwards-incompatible changes introduced before version
Security
--------
git-crypt is more secure that other transparent git encryption systems.
git-crypt is more secure than other transparent git encryption systems.
git-crypt encrypts files using AES-256 in CTR mode with a synthetic IV
derived from the SHA-1 HMAC of the file. This mode of operation is
provably semantically secure under deterministic chosen-plaintext attack.
@@ -100,7 +100,7 @@ all of the files in a repository. Where git-crypt really shines is where
most of your repository is public, but you have a few files (perhaps
private keys named *.key, or a file with API credentials) which you
need to encrypt. For encrypting an entire repository, consider using a
system like [git-remote-gcrypt](https://github.com/joeyh/git-remote-gcrypt)
system like [git-remote-gcrypt](https://spwhitton.name/tech/code/git-remote-gcrypt/)
instead. (Note: no endorsement is made of git-remote-gcrypt's security.)
git-crypt does not encrypt file names, commit messages, symlink targets,

View File

@@ -12,6 +12,10 @@ For their contributions to git-crypt, I thank:
* Linus G Thiel
* Michael Schout
* Simon Kotlinski
* Kevin Menard
* Wael M. Nasreddine
* Kevin Borgolte
* Adrian Cohea
* And everyone who has tested git-crypt, provided feedback, reported
bugs, and participated in discussions about new features.

View File

@@ -48,6 +48,7 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <exception>
#include <vector>
static std::string attribute_name (const char* key_name)
@@ -254,6 +255,27 @@ static std::string get_internal_key_path (const char* key_name)
return path;
}
std::string get_git_config (const std::string& name)
{
// git config --get
std::vector<std::string> command;
command.push_back("git");
command.push_back("config");
command.push_back("--get");
command.push_back(name);
std::stringstream output;
if (!successful_exit(exec_command(command, output))) {
throw Error("'git config' missing value for key '" + name +"'");
}
std::string value;
std::getline(output, value);
return value;
}
static std::string get_repo_state_path ()
{
// git rev-parse --show-toplevel
@@ -276,7 +298,18 @@ static std::string get_repo_state_path ()
throw Error("Could not determine Git working tree - is this a non-bare repo?");
}
path += "/.git-crypt";
// Check if the repo state dir has been explicitly configured. If so, use that in path construction.
if (git_has_config("git-crypt.repoStateDir")) {
std::string repoStateDir = get_git_config("git-crypt.repoStateDir");
// The repoStateDir value must always be relative to git work tree to ensure the repoStateDir can be committed
// along with the remainder of the repository.
path += '/' + repoStateDir;
} else {
// There is no explicitly configured repo state dir configured, so use the default.
path += "/.git-crypt";
}
return path;
}
@@ -455,7 +488,7 @@ static bool check_if_file_is_encrypted (const std::string& filename)
static bool is_git_file_mode (const std::string& mode)
{
return (std::strtoul(mode.c_str(), NULL, 8) & 0170000) == 0100000;
return (std::strtoul(mode.c_str(), nullptr, 8) & 0170000) == 0100000;
}
static void get_encrypted_files (std::vector<std::string>& files, const char* key_name)
@@ -476,8 +509,8 @@ static void get_encrypted_files (std::vector<std::string>& files, const char* ke
ls_files.spawn(ls_files_command);
Coprocess check_attr;
std::ostream* check_attr_stdin = NULL;
std::istream* check_attr_stdout = NULL;
std::ostream* check_attr_stdin = nullptr;
std::istream* check_attr_stdout = nullptr;
if (git_version() >= make_version(1, 8, 5)) {
// In Git 1.8.5 (released 27 Nov 2013) and higher, we use a single `git check-attr` process
// to get the attributes of all files at once. In prior versions, we have to fork and exec
@@ -557,13 +590,20 @@ static void load_key (Key_file& key_file, const char* key_name, const char* key_
static bool decrypt_repo_key (Key_file& key_file, const char* key_name, uint32_t key_version, const std::vector<std::string>& secret_keys, const std::string& keys_path)
{
std::exception_ptr gpg_error;
for (std::vector<std::string>::const_iterator seckey(secret_keys.begin()); seckey != secret_keys.end(); ++seckey) {
std::ostringstream path_builder;
path_builder << keys_path << '/' << (key_name ? key_name : "default") << '/' << key_version << '/' << *seckey << ".gpg";
std::string path(path_builder.str());
if (access(path.c_str(), F_OK) == 0) {
std::stringstream decrypted_contents;
gpg_decrypt_from_file(path, decrypted_contents);
try {
gpg_decrypt_from_file(path, decrypted_contents);
} catch (const Gpg_error&) {
gpg_error = std::current_exception();
continue;
}
Key_file this_version_key_file;
this_version_key_file.load(decrypted_contents);
const Key_file::Entry* this_version_entry = this_version_key_file.get(key_version);
@@ -578,6 +618,11 @@ static bool decrypt_repo_key (Key_file& key_file, const char* key_name, uint32_t
return true;
}
}
if (gpg_error) {
std::rethrow_exception(gpg_error);
}
return false;
}
@@ -1202,6 +1247,7 @@ int add_gpg_user (int argc, const char** argv)
state_gitattributes_file << "# Do not edit this file. To specify the files to encrypt, create your own\n";
state_gitattributes_file << "# .gitattributes file in the directory where your files are.\n";
state_gitattributes_file << "* !filter !diff\n";
state_gitattributes_file << "*.gpg binary\n";
state_gitattributes_file.close();
if (!state_gitattributes_file) {
std::clog << "Error: unable to write " << state_gitattributes_path << std::endl;

View File

@@ -70,4 +70,7 @@ void help_migrate_key (std::ostream&);
void help_refresh (std::ostream&);
void help_status (std::ostream&);
// other
std::string get_git_config (const std::string& name);
#endif

View File

@@ -41,7 +41,7 @@ static int execvp (const std::string& file, const std::vector<std::string>& args
for (std::vector<std::string>::const_iterator arg(args.begin()); arg != args.end(); ++arg) {
args_c_str.push_back(arg->c_str());
}
args_c_str.push_back(NULL);
args_c_str.push_back(nullptr);
return execvp(file.c_str(), const_cast<char**>(&args_c_str[0]));
}
@@ -50,10 +50,10 @@ Coprocess::Coprocess ()
pid = -1;
stdin_pipe_reader = -1;
stdin_pipe_writer = -1;
stdin_pipe_ostream = NULL;
stdin_pipe_ostream = nullptr;
stdout_pipe_reader = -1;
stdout_pipe_writer = -1;
stdout_pipe_istream = NULL;
stdout_pipe_istream = nullptr;
}
Coprocess::~Coprocess ()
@@ -79,7 +79,7 @@ std::ostream* Coprocess::stdin_pipe ()
void Coprocess::close_stdin ()
{
delete stdin_pipe_ostream;
stdin_pipe_ostream = NULL;
stdin_pipe_ostream = nullptr;
if (stdin_pipe_writer != -1) {
close(stdin_pipe_writer);
stdin_pipe_writer = -1;
@@ -107,7 +107,7 @@ std::istream* Coprocess::stdout_pipe ()
void Coprocess::close_stdout ()
{
delete stdout_pipe_istream;
stdout_pipe_istream = NULL;
stdout_pipe_istream = nullptr;
if (stdout_pipe_writer != -1) {
close(stdout_pipe_writer);
stdout_pipe_writer = -1;

View File

@@ -96,14 +96,14 @@ static HANDLE spawn_command (const std::vector<std::string>& command, HANDLE std
std::string cmdline(format_cmdline(command));
if (!CreateProcessA(NULL, // application name (NULL to use command line)
if (!CreateProcessA(nullptr, // application name (nullptr to use command line)
const_cast<char*>(cmdline.c_str()),
NULL, // process security attributes
NULL, // primary thread security attributes
nullptr, // process security attributes
nullptr, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
nullptr, // use parent's environment
nullptr, // use parent's current directory
&start_info,
&proc_info)) {
throw System_error("CreateProcess", cmdline, GetLastError());
@@ -117,13 +117,13 @@ static HANDLE spawn_command (const std::vector<std::string>& command, HANDLE std
Coprocess::Coprocess ()
{
proc_handle = NULL;
stdin_pipe_reader = NULL;
stdin_pipe_writer = NULL;
stdin_pipe_ostream = NULL;
stdout_pipe_reader = NULL;
stdout_pipe_writer = NULL;
stdout_pipe_istream = NULL;
proc_handle = nullptr;
stdin_pipe_reader = nullptr;
stdin_pipe_writer = nullptr;
stdin_pipe_ostream = nullptr;
stdout_pipe_reader = nullptr;
stdout_pipe_writer = nullptr;
stdout_pipe_istream = nullptr;
}
Coprocess::~Coprocess ()
@@ -143,7 +143,7 @@ std::ostream* Coprocess::stdin_pipe ()
// Set the bInheritHandle flag so pipe handles are inherited.
sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
sec_attr.bInheritHandle = TRUE;
sec_attr.lpSecurityDescriptor = NULL;
sec_attr.lpSecurityDescriptor = nullptr;
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&stdin_pipe_reader, &stdin_pipe_writer, &sec_attr, 0)) {
@@ -163,14 +163,14 @@ std::ostream* Coprocess::stdin_pipe ()
void Coprocess::close_stdin ()
{
delete stdin_pipe_ostream;
stdin_pipe_ostream = NULL;
stdin_pipe_ostream = nullptr;
if (stdin_pipe_writer) {
CloseHandle(stdin_pipe_writer);
stdin_pipe_writer = NULL;
stdin_pipe_writer = nullptr;
}
if (stdin_pipe_reader) {
CloseHandle(stdin_pipe_reader);
stdin_pipe_reader = NULL;
stdin_pipe_reader = nullptr;
}
}
@@ -182,7 +182,7 @@ std::istream* Coprocess::stdout_pipe ()
// Set the bInheritHandle flag so pipe handles are inherited.
sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
sec_attr.bInheritHandle = TRUE;
sec_attr.lpSecurityDescriptor = NULL;
sec_attr.lpSecurityDescriptor = nullptr;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&stdout_pipe_reader, &stdout_pipe_writer, &sec_attr, 0)) {
@@ -202,27 +202,27 @@ std::istream* Coprocess::stdout_pipe ()
void Coprocess::close_stdout ()
{
delete stdout_pipe_istream;
stdout_pipe_istream = NULL;
stdout_pipe_istream = nullptr;
if (stdout_pipe_writer) {
CloseHandle(stdout_pipe_writer);
stdout_pipe_writer = NULL;
stdout_pipe_writer = nullptr;
}
if (stdout_pipe_reader) {
CloseHandle(stdout_pipe_reader);
stdout_pipe_reader = NULL;
stdout_pipe_reader = nullptr;
}
}
void Coprocess::spawn (const std::vector<std::string>& args)
{
proc_handle = spawn_command(args, stdin_pipe_reader, stdout_pipe_writer, NULL);
proc_handle = spawn_command(args, stdin_pipe_reader, stdout_pipe_writer, nullptr);
if (stdin_pipe_reader) {
CloseHandle(stdin_pipe_reader);
stdin_pipe_reader = NULL;
stdin_pipe_reader = nullptr;
}
if (stdout_pipe_writer) {
CloseHandle(stdout_pipe_writer);
stdout_pipe_writer = NULL;
stdout_pipe_writer = nullptr;
}
}
@@ -243,7 +243,7 @@ int Coprocess::wait ()
size_t Coprocess::write_stdin (void* handle, const void* buf, size_t count)
{
DWORD bytes_written;
if (!WriteFile(static_cast<Coprocess*>(handle)->stdin_pipe_writer, buf, count, &bytes_written, NULL)) {
if (!WriteFile(static_cast<Coprocess*>(handle)->stdin_pipe_writer, buf, count, &bytes_written, nullptr)) {
throw System_error("WriteFile", "", GetLastError());
}
return bytes_written;
@@ -257,7 +257,7 @@ size_t Coprocess::read_stdout (void* handle, void* buf, size_t count)
// fails with ERROR_BROKEN_PIPE.
DWORD bytes_read;
do {
if (!ReadFile(static_cast<Coprocess*>(handle)->stdout_pipe_reader, buf, count, &bytes_read, NULL)) {
if (!ReadFile(static_cast<Coprocess*>(handle)->stdout_pipe_reader, buf, count, &bytes_read, nullptr)) {
const DWORD read_error = GetLastError();
if (read_error != ERROR_BROKEN_PIPE) {
throw System_error("ReadFile", "", read_error);

View File

@@ -28,6 +28,10 @@
* as that of the covered work.
*/
#include <openssl/opensslconf.h>
#if !defined(OPENSSL_API_COMPAT)
#include "crypto.hpp"
#include "key.hpp"
#include "util.hpp"
@@ -59,8 +63,8 @@ Aes_ecb_encryptor::Aes_ecb_encryptor (const unsigned char* raw_key)
Aes_ecb_encryptor::~Aes_ecb_encryptor ()
{
// Note: Explicit destructor necessary because class contains an auto_ptr
// which contains an incomplete type when the auto_ptr is declared.
// Note: Explicit destructor necessary because class contains an unique_ptr
// which contains an incomplete type when the unique_ptr is declared.
explicit_memset(&impl->key, '\0', sizeof(impl->key));
}
@@ -82,8 +86,8 @@ Hmac_sha1_state::Hmac_sha1_state (const unsigned char* key, size_t key_len)
Hmac_sha1_state::~Hmac_sha1_state ()
{
// Note: Explicit destructor necessary because class contains an auto_ptr
// which contains an incomplete type when the auto_ptr is declared.
// Note: Explicit destructor necessary because class contains an unique_ptr
// which contains an incomplete type when the unique_ptr is declared.
HMAC_cleanup(&(impl->ctx));
}
@@ -113,3 +117,4 @@ void random_bytes (unsigned char* buffer, size_t len)
}
}
#endif

119
crypto-openssl-11.cpp Normal file
View File

@@ -0,0 +1,119 @@
/*
* Copyright 2012, 2014 Andrew Ayer
*
* This file is part of git-crypt.
*
* git-crypt is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* git-crypt 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with git-crypt. If not, see <http://www.gnu.org/licenses/>.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify the Program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, the licensors of the Program
* grant you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#include <openssl/opensslconf.h>
#if defined(OPENSSL_API_COMPAT)
#include "crypto.hpp"
#include "key.hpp"
#include "util.hpp"
#include <openssl/aes.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <sstream>
#include <cstring>
void init_crypto ()
{
ERR_load_crypto_strings();
}
struct Aes_ecb_encryptor::Aes_impl {
AES_KEY key;
};
Aes_ecb_encryptor::Aes_ecb_encryptor (const unsigned char* raw_key)
: impl(new Aes_impl)
{
if (AES_set_encrypt_key(raw_key, KEY_LEN * 8, &(impl->key)) != 0) {
throw Crypto_error("Aes_ctr_encryptor::Aes_ctr_encryptor", "AES_set_encrypt_key failed");
}
}
Aes_ecb_encryptor::~Aes_ecb_encryptor ()
{
// Note: Explicit destructor necessary because class contains an unique_ptr
// which contains an incomplete type when the unique_ptr is declared.
explicit_memset(&impl->key, '\0', sizeof(impl->key));
}
void Aes_ecb_encryptor::encrypt(const unsigned char* plain, unsigned char* cipher)
{
AES_encrypt(plain, cipher, &(impl->key));
}
struct Hmac_sha1_state::Hmac_impl {
HMAC_CTX *ctx;
};
Hmac_sha1_state::Hmac_sha1_state (const unsigned char* key, size_t key_len)
: impl(new Hmac_impl)
{
impl->ctx = HMAC_CTX_new();
HMAC_Init_ex(impl->ctx, key, key_len, EVP_sha1(), nullptr);
}
Hmac_sha1_state::~Hmac_sha1_state ()
{
HMAC_CTX_free(impl->ctx);
}
void Hmac_sha1_state::add (const unsigned char* buffer, size_t buffer_len)
{
HMAC_Update(impl->ctx, buffer, buffer_len);
}
void Hmac_sha1_state::get (unsigned char* digest)
{
unsigned int len;
HMAC_Final(impl->ctx, digest, &len);
}
void random_bytes (unsigned char* buffer, size_t len)
{
if (RAND_bytes(buffer, len) != 1) {
std::ostringstream message;
while (unsigned long code = ERR_get_error()) {
char error_string[120];
ERR_error_string_n(code, error_string, sizeof(error_string));
message << "OpenSSL Error: " << error_string << "; ";
}
throw Crypto_error("random_bytes", message.str());
}
}
#endif

View File

@@ -57,7 +57,7 @@ public:
private:
struct Aes_impl;
std::auto_ptr<Aes_impl> impl;
std::unique_ptr<Aes_impl> impl;
public:
Aes_ecb_encryptor (const unsigned char* key);
@@ -102,7 +102,7 @@ public:
private:
struct Hmac_impl;
std::auto_ptr<Hmac_impl> impl;
std::unique_ptr<Hmac_impl> impl;
public:
Hmac_sha1_state (const unsigned char* key, size_t key_len);

View File

@@ -31,7 +31,7 @@
#ifndef GIT_CRYPT_GIT_CRYPT_HPP
#define GIT_CRYPT_GIT_CRYPT_HPP
#define VERSION "0.5.0"
#define VERSION "0.6.0"
extern const char* argv0; // initialized in main() to argv[0]

20
gpg.cpp
View File

@@ -30,8 +30,18 @@
#include "gpg.hpp"
#include "util.hpp"
#include "commands.hpp"
#include <sstream>
static std::string gpg_get_executable()
{
std::string gpgbin = "gpg";
try {
gpgbin = get_git_config("gpg.program");
} catch (...) {
}
return gpgbin;
}
static std::string gpg_nth_column (const std::string& line, unsigned int col)
{
std::string::size_type pos = 0;
@@ -62,7 +72,7 @@ std::string gpg_get_uid (const std::string& fingerprint)
{
// gpg --batch --with-colons --fixed-list-mode --list-keys 0x7A399B2DB06D039020CD1CE1D0F3702D61489532
std::vector<std::string> command;
command.push_back("gpg");
command.push_back(gpg_get_executable());
command.push_back("--batch");
command.push_back("--with-colons");
command.push_back("--fixed-list-mode");
@@ -94,7 +104,7 @@ std::vector<std::string> gpg_lookup_key (const std::string& query)
// gpg --batch --with-colons --fingerprint --list-keys jsmith@example.com
std::vector<std::string> command;
command.push_back("gpg");
command.push_back(gpg_get_executable());
command.push_back("--batch");
command.push_back("--with-colons");
command.push_back("--fingerprint");
@@ -125,7 +135,7 @@ std::vector<std::string> gpg_list_secret_keys ()
{
// gpg --batch --with-colons --list-secret-keys --fingerprint
std::vector<std::string> command;
command.push_back("gpg");
command.push_back(gpg_get_executable());
command.push_back("--batch");
command.push_back("--with-colons");
command.push_back("--list-secret-keys");
@@ -154,7 +164,7 @@ void gpg_encrypt_to_file (const std::string& filename, const std::string& recipi
{
// gpg --batch -o FILENAME -r RECIPIENT -e
std::vector<std::string> command;
command.push_back("gpg");
command.push_back(gpg_get_executable());
command.push_back("--batch");
if (key_is_trusted) {
command.push_back("--trust-model");
@@ -174,7 +184,7 @@ void gpg_decrypt_from_file (const std::string& filename, std::ostream& output)
{
// gpg -q -d FILENAME
std::vector<std::string> command;
command.push_back("gpg");
command.push_back(gpg_get_executable());
command.push_back("-q");
command.push_back("-d");
command.push_back(filename);

View File

@@ -7,8 +7,8 @@
-->
<refentryinfo>
<title>git-crypt</title>
<date>2015-05-30</date>
<productname>git-crypt 0.5.0</productname>
<date>2017-11-26</date>
<productname>git-crypt 0.6.0</productname>
<author>
<othername>Andrew Ayer</othername>

View File

@@ -125,40 +125,20 @@ void mkdir_parent (const std::string& path)
}
}
static std::string readlink (const char* pathname)
{
std::vector<char> buffer(64);
ssize_t len;
while ((len = ::readlink(pathname, &buffer[0], buffer.size())) == static_cast<ssize_t>(buffer.size())) {
// buffer may have been truncated - grow and try again
buffer.resize(buffer.size() * 2);
}
if (len == -1) {
throw System_error("readlink", pathname, errno);
}
return std::string(buffer.begin(), buffer.begin() + len);
}
std::string our_exe_path ()
{
try {
return readlink("/proc/self/exe");
} catch (const System_error&) {
if (argv0[0] == '/') {
// argv[0] starts with / => it's an absolute path
return argv0;
} else if (std::strchr(argv0, '/')) {
// argv[0] contains / => it a relative path that should be resolved
char* resolved_path_p = realpath(argv0, NULL);
std::string resolved_path(resolved_path_p);
free(resolved_path_p);
return resolved_path;
} else {
// argv[0] is just a bare filename => not much we can do
return argv0;
}
if (argv0[0] == '/') {
// argv[0] starts with / => it's an absolute path
return argv0;
} else if (std::strchr(argv0, '/')) {
// argv[0] contains / => it a relative path that should be resolved
char* resolved_path_p = realpath(argv0, nullptr);
std::string resolved_path(resolved_path_p);
free(resolved_path_p);
return resolved_path;
} else {
// argv[0] is just a bare filename => not much we can do
return argv0;
}
}
@@ -169,7 +149,7 @@ int exit_status (int wait_status)
void touch_file (const std::string& filename)
{
if (utimes(filename.c_str(), NULL) == -1 && errno != ENOENT) {
if (utimes(filename.c_str(), nullptr) == -1 && errno != ENOENT) {
throw System_error("utimes", filename, errno);
}
}
@@ -199,19 +179,6 @@ int util_rename (const char* from, const char* to)
return rename(from, to);
}
static size_t sizeof_dirent_for (DIR* p)
{
long name_max = fpathconf(dirfd(p), _PC_NAME_MAX);
if (name_max == -1) {
#ifdef NAME_MAX
name_max = NAME_MAX;
#else
name_max = 255;
#endif
}
return offsetof(struct dirent, d_name) + name_max + 1; // final +1 is for d_name's null terminator
}
std::vector<std::string> get_directory_contents (const char* path)
{
std::vector<std::string> contents;
@@ -221,19 +188,23 @@ std::vector<std::string> get_directory_contents (const char* path)
throw System_error("opendir", path, errno);
}
try {
std::vector<unsigned char> buffer(sizeof_dirent_for(dir));
struct dirent* dirent_buffer = reinterpret_cast<struct dirent*>(&buffer[0]);
struct dirent* ent = NULL;
int err = 0;
while ((err = readdir_r(dir, dirent_buffer, &ent)) == 0 && ent != NULL) {
if (std::strcmp(ent->d_name, ".") == 0 || std::strcmp(ent->d_name, "..") == 0) {
continue;
errno = 0;
// Note: readdir is reentrant in new implementations. In old implementations,
// it might not be, but git-crypt isn't multi-threaded so that's OK.
// We don't use readdir_r because it's buggy and deprecated:
// https://womble.decadent.org.uk/readdir_r-advisory.html
// http://austingroupbugs.net/view.php?id=696
// http://man7.org/linux/man-pages/man3/readdir_r.3.html
while (struct dirent* ent = readdir(dir)) {
if (!(std::strcmp(ent->d_name, ".") == 0 || std::strcmp(ent->d_name, "..") == 0)) {
contents.push_back(ent->d_name);
}
contents.push_back(ent->d_name);
}
if (err != 0) {
throw System_error("readdir_r", path, errno);
if (errno) {
throw System_error("readdir", path, errno);
}
} catch (...) {
closedir(dir);
throw;

View File

@@ -46,12 +46,12 @@ std::string System_error::message () const
LPTSTR error_message;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
nullptr,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&error_message),
0,
NULL);
nullptr);
mesg += error_message;
LocalFree(error_message);
}
@@ -100,7 +100,7 @@ void mkdir_parent (const std::string& path)
std::string prefix(path.substr(0, slash));
if (GetFileAttributes(prefix.c_str()) == INVALID_FILE_ATTRIBUTES) {
// prefix does not exist, so try to create it
if (!CreateDirectory(prefix.c_str(), NULL)) {
if (!CreateDirectory(prefix.c_str(), nullptr)) {
throw System_error("CreateDirectory", prefix, GetLastError());
}
}
@@ -114,7 +114,7 @@ std::string our_exe_path ()
std::vector<char> buffer(128);
size_t len;
while ((len = GetModuleFileNameA(NULL, &buffer[0], buffer.size())) == buffer.size()) {
while ((len = GetModuleFileNameA(nullptr, &buffer[0], buffer.size())) == buffer.size()) {
// buffer may have been truncated - grow and try again
buffer.resize(buffer.size() * 2);
}
@@ -132,7 +132,7 @@ int exit_status (int status)
void touch_file (const std::string& filename)
{
HANDLE fh = CreateFileA(filename.c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
HANDLE fh = CreateFileA(filename.c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
if (fh == INVALID_HANDLE_VALUE) {
DWORD error = GetLastError();
if (error == ERROR_FILE_NOT_FOUND) {
@@ -146,7 +146,7 @@ void touch_file (const std::string& filename)
FILETIME file_time;
SystemTimeToFileTime(&system_time, &file_time);
if (!SetFileTime(fh, NULL, NULL, &file_time)) {
if (!SetFileTime(fh, nullptr, nullptr, &file_time)) {
DWORD error = GetLastError();
CloseHandle(fh);
throw System_error("SetFileTime", filename, error);