mirror of
https://github.com/AGWA/git-crypt.git
synced 2025-12-22 23:26:11 -08:00
This abstracts away the details of argument quoting, which differs between Unix and Windows. Also replace all uses of the system() library call with exec_command(). Although system() exists on Windows, it executes the command via cmd.exe, which has ridiculous escaping rules.
177 lines
5.6 KiB
C++
177 lines
5.6 KiB
C++
/*
|
|
* Copyright 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 "gpg.hpp"
|
|
#include "util.hpp"
|
|
#include <sstream>
|
|
|
|
static std::string gpg_nth_column (const std::string& line, unsigned int col)
|
|
{
|
|
std::string::size_type pos = 0;
|
|
|
|
for (unsigned int i = 0; i < col; ++i) {
|
|
pos = line.find_first_of(':', pos);
|
|
if (pos == std::string::npos) {
|
|
throw Gpg_error("Malformed output from gpg");
|
|
}
|
|
pos = pos + 1;
|
|
}
|
|
|
|
const std::string::size_type end_pos = line.find_first_of(':', pos);
|
|
|
|
return end_pos != std::string::npos ?
|
|
line.substr(pos, end_pos - pos) :
|
|
line.substr(pos);
|
|
}
|
|
|
|
// given a key fingerprint, return the last 8 nibbles
|
|
std::string gpg_shorten_fingerprint (const std::string& fingerprint)
|
|
{
|
|
return fingerprint.size() == 40 ? fingerprint.substr(32) : fingerprint;
|
|
}
|
|
|
|
// given a key fingerprint, return the key's UID (e.g. "John Smith <jsmith@example.com>")
|
|
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("--batch");
|
|
command.push_back("--with-colons");
|
|
command.push_back("--fixed-list-mode");
|
|
command.push_back("--list-keys");
|
|
command.push_back("0x" + fingerprint);
|
|
std::stringstream command_output;
|
|
if (!successful_exit(exec_command(command, command_output))) {
|
|
// This could happen if the keyring does not contain a public key with this fingerprint
|
|
return "";
|
|
}
|
|
|
|
while (command_output.peek() != -1) {
|
|
std::string line;
|
|
std::getline(command_output, line);
|
|
if (line.substr(0, 4) == "uid:") {
|
|
// uid:u::::1395975462::AB97D6E3E5D8789988CA55E5F77D9E7397D05229::John Smith <jsmith@example.com>:
|
|
// want the 9th column (counting from 0)
|
|
return gpg_nth_column(line, 9);
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
// return a list of fingerprints of public keys matching the given search query (such as jsmith@example.com)
|
|
std::vector<std::string> gpg_lookup_key (const std::string& query)
|
|
{
|
|
std::vector<std::string> fingerprints;
|
|
|
|
// gpg --batch --with-colons --fingerprint --list-keys jsmith@example.com
|
|
std::vector<std::string> command;
|
|
command.push_back("gpg");
|
|
command.push_back("--batch");
|
|
command.push_back("--with-colons");
|
|
command.push_back("--fingerprint");
|
|
command.push_back("--list-keys");
|
|
command.push_back(query);
|
|
std::stringstream command_output;
|
|
if (successful_exit(exec_command(command, command_output))) {
|
|
while (command_output.peek() != -1) {
|
|
std::string line;
|
|
std::getline(command_output, line);
|
|
if (line.substr(0, 4) == "fpr:") {
|
|
// fpr:::::::::7A399B2DB06D039020CD1CE1D0F3702D61489532:
|
|
// want the 9th column (counting from 0)
|
|
fingerprints.push_back(gpg_nth_column(line, 9));
|
|
}
|
|
}
|
|
}
|
|
|
|
return fingerprints;
|
|
}
|
|
|
|
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("--batch");
|
|
command.push_back("--with-colons");
|
|
command.push_back("--list-secret-keys");
|
|
command.push_back("--fingerprint");
|
|
std::stringstream command_output;
|
|
if (!successful_exit(exec_command(command, command_output))) {
|
|
throw Gpg_error("gpg --list-secret-keys failed");
|
|
}
|
|
|
|
std::vector<std::string> secret_keys;
|
|
|
|
while (command_output.peek() != -1) {
|
|
std::string line;
|
|
std::getline(command_output, line);
|
|
if (line.substr(0, 4) == "fpr:") {
|
|
// fpr:::::::::7A399B2DB06D039020CD1CE1D0F3702D61489532:
|
|
// want the 9th column (counting from 0)
|
|
secret_keys.push_back(gpg_nth_column(line, 9));
|
|
}
|
|
}
|
|
|
|
return secret_keys;
|
|
}
|
|
|
|
void gpg_encrypt_to_file (const std::string& filename, const std::string& recipient_fingerprint, const char* p, size_t len)
|
|
{
|
|
// gpg --batch -o FILENAME -r RECIPIENT -e
|
|
std::vector<std::string> command;
|
|
command.push_back("gpg");
|
|
command.push_back("--batch");
|
|
command.push_back("-o");
|
|
command.push_back(filename);
|
|
command.push_back("-r");
|
|
command.push_back("0x" + recipient_fingerprint);
|
|
command.push_back("-e");
|
|
if (!successful_exit(exec_command_with_input(command, p, len))) {
|
|
throw Gpg_error("Failed to encrypt");
|
|
}
|
|
}
|
|
|
|
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("-q");
|
|
command.push_back("-d");
|
|
command.push_back(filename);
|
|
if (!successful_exit(exec_command(command, output))) {
|
|
throw Gpg_error("Failed to decrypt");
|
|
}
|
|
}
|
|
|