diff --git a/Makefile b/Makefile index 142e92d..bef297d 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,19 @@ CXX := c++ CXXFLAGS := -Wall -pedantic -Wno-long-long -O2 -LDFLAGS := -lcrypto +LDFLAGS := PREFIX := /usr/local -OBJFILES = git-crypt.o commands.o crypto.o gpg.o key.o util.o parse_options.o +OBJFILES = \ + git-crypt.o \ + commands.o \ + crypto.o \ + gpg.o \ + key.o \ + util.o \ + parse_options.o + +OBJFILES += crypto-openssl.o +LDFLAGS += -lcrypto all: git-crypt diff --git a/crypto-openssl.cpp b/crypto-openssl.cpp new file mode 100644 index 0000000..6ae8293 --- /dev/null +++ b/crypto-openssl.cpp @@ -0,0 +1,108 @@ +/* + * 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 . + * + * 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 "crypto.hpp" +#include "key.hpp" +#include +#include +#include +#include +#include +#include +#include + +void init_crypto () +{ + ERR_load_crypto_strings(); +} + +struct 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 () +{ + delete impl; +} + +void Aes_ecb_encryptor::encrypt(const unsigned char* plain, unsigned char* cipher) +{ + AES_encrypt(plain, cipher, &(impl->key)); +} + +struct Hmac_impl { + HMAC_CTX ctx; +}; + +Hmac_sha1_state::Hmac_sha1_state (const unsigned char* key, size_t key_len) +{ + impl = new Hmac_impl; + HMAC_Init(&(impl->ctx), key, key_len, EVP_sha1()); +} + +Hmac_sha1_state::~Hmac_sha1_state () +{ + HMAC_cleanup(&(impl->ctx)); + delete impl; +} + +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()); + } +} + diff --git a/crypto.cpp b/crypto.cpp index c11d5e2..db081ae 100644 --- a/crypto.cpp +++ b/crypto.cpp @@ -30,22 +30,11 @@ #include "crypto.hpp" #include "util.hpp" -#include -#include -#include -#include -#include -#include -#include #include -#include Aes_ctr_encryptor::Aes_ctr_encryptor (const unsigned char* raw_key, const unsigned char* arg_nonce) +: ecb(raw_key) { - if (AES_set_encrypt_key(raw_key, KEY_LEN * 8, &key) != 0) { - throw Crypto_error("Aes_ctr_encryptor::Aes_ctr_encryptor", "AES_set_encrypt_key failed"); - } - std::memcpy(nonce, arg_nonce, NONCE_LEN); byte_counter = 0; std::memset(otp, '\0', sizeof(otp)); @@ -64,7 +53,7 @@ void Aes_ctr_encryptor::process (const unsigned char* in, unsigned char* out, si store_be32(ctr + NONCE_LEN, byte_counter / BLOCK_LEN); // Generate a new OTP - AES_encrypt(ctr, otp, &key); + ecb.encrypt(ctr, otp); } // encrypt one byte @@ -76,28 +65,6 @@ void Aes_ctr_encryptor::process (const unsigned char* in, unsigned char* out, si } } -Hmac_sha1_state::Hmac_sha1_state (const unsigned char* key, size_t key_len) -{ - HMAC_Init(&ctx, key, key_len, EVP_sha1()); -} - -Hmac_sha1_state::~Hmac_sha1_state () -{ - HMAC_cleanup(&ctx); -} - -void Hmac_sha1_state::add (const unsigned char* buffer, size_t buffer_len) -{ - HMAC_Update(&ctx, buffer, buffer_len); -} - -void Hmac_sha1_state::get (unsigned char* digest) -{ - unsigned int len; - HMAC_Final(&ctx, digest, &len); -} - - // Encrypt/decrypt an entire input stream, writing to the given output stream void Aes_ctr_encryptor::process_stream (std::istream& in, std::ostream& out, const unsigned char* key, const unsigned char* nonce) { @@ -111,16 +78,3 @@ void Aes_ctr_encryptor::process_stream (std::istream& in, std::ostream& out, con } } -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()); - } -} - diff --git a/crypto.hpp b/crypto.hpp index 63772a1..ae6a14c 100644 --- a/crypto.hpp +++ b/crypto.hpp @@ -32,13 +32,13 @@ #define GIT_CRYPT_CRYPTO_HPP #include "key.hpp" -#include -#include #include #include #include #include +void init_crypto (); + struct Crypto_error { std::string where; std::string message; @@ -46,6 +46,28 @@ struct Crypto_error { Crypto_error (const std::string& w, const std::string& m) : where(w), message(m) { } }; +struct Aes_impl; + +class Aes_ecb_encryptor { +public: + enum { + KEY_LEN = AES_KEY_LEN, + BLOCK_LEN = 16 + }; + +private: + Aes_impl* impl; + + // disallow copy/assignment: + Aes_ecb_encryptor (const Aes_ecb_encryptor&); + Aes_ecb_encryptor& operator= (const Aes_ecb_encryptor&); + +public: + Aes_ecb_encryptor (const unsigned char* key); + ~Aes_ecb_encryptor (); + void encrypt (const unsigned char* plain, unsigned char* cipher); +}; + class Aes_ctr_encryptor { public: enum { @@ -56,10 +78,10 @@ public: }; private: - AES_KEY key; - char nonce[NONCE_LEN];// First 96 bits of counter - uint32_t byte_counter; // How many bytes processed so far? - unsigned char otp[BLOCK_LEN]; // The current OTP that's in use + Aes_ecb_encryptor ecb; + char nonce[NONCE_LEN];// First 96 bits of counter + uint32_t byte_counter; // How many bytes processed so far? + unsigned char otp[BLOCK_LEN]; // The current OTP that's in use public: Aes_ctr_encryptor (const unsigned char* key, const unsigned char* nonce); @@ -72,6 +94,8 @@ public: typedef Aes_ctr_encryptor Aes_ctr_decryptor; +struct Hmac_impl; + class Hmac_sha1_state { public: enum { @@ -80,7 +104,7 @@ public: }; private: - HMAC_CTX ctx; + Hmac_impl* impl; // disallow copy/assignment: Hmac_sha1_state (const Hmac_sha1_state&) { } diff --git a/git-crypt.cpp b/git-crypt.cpp index 58b9923..e2cc9fc 100644 --- a/git-crypt.cpp +++ b/git-crypt.cpp @@ -39,7 +39,6 @@ #include #include #include -#include const char* argv0; @@ -90,7 +89,7 @@ try { */ init_std_streams(); - ERR_load_crypto_strings(); + init_crypto(); /* * Parse command line arguments