1
0
mirror of https://github.com/biergaizi/codecrypt synced 2024-06-28 18:03:36 +00:00
codecrypt/src/keyring.cpp

384 lines
8.4 KiB
C++
Raw Normal View History

2012-09-30 09:55:23 +00:00
2012-11-05 21:45:35 +00:00
/*
* This file is part of Codecrypt.
*
* Codecrypt 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.
*
* Codecrypt 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 Codecrypt. If not, see <http://www.gnu.org/licenses/>.
*/
2013-01-04 11:43:36 +00:00
#include "keyring.h"
2012-11-06 08:46:18 +00:00
2013-04-01 15:49:58 +00:00
void keyring::clear()
2013-01-04 11:43:36 +00:00
{
2013-04-01 15:49:58 +00:00
for (std::map<std::string, pubkey_entry>::iterator
i = pubs.begin(), e = pubs.end(); i != e; ++i)
sencode_destroy (i->second.key);
pubs.clear();
for (std::map<std::string, keypair_entry>::iterator
i = pairs.begin(), e = pairs.end(); i != e; ++i) {
sencode_destroy (i->second.pub.key);
sencode_destroy (i->second.privkey);
}
pairs.clear();
2013-01-04 11:43:36 +00:00
}
2013-04-01 15:49:58 +00:00
/*
* KeyID is SHA256 of pubkey string representation. Also serves as a
* simple fingerprint.
*/
2013-01-04 11:43:36 +00:00
2013-04-01 15:49:58 +00:00
#include "sha2.h"
#include <stdint.h>
2013-01-04 11:43:36 +00:00
2013-04-01 15:49:58 +00:00
std::string keyring::get_keyid (const std::string&pubkey)
2013-01-04 11:43:36 +00:00
{
2013-04-01 15:49:58 +00:00
SHA256_CTX ctx;
uint8_t t;
2013-01-04 11:43:36 +00:00
2013-04-01 15:49:58 +00:00
SHA256_Init (&ctx);
2013-01-04 11:43:36 +00:00
2013-04-01 15:49:58 +00:00
for (size_t i = 0; i < pubkey.length(); ++i) {
t = pubkey[i];
SHA256_Update (&ctx, &t, 1);
}
2013-01-04 11:43:36 +00:00
2013-04-01 15:49:58 +00:00
std::string r;
r.resize (64, ' ');
SHA256_End (&ctx, & (r[0]) );
2013-01-04 11:43:36 +00:00
2013-04-01 15:49:58 +00:00
return r;
2013-01-04 11:43:36 +00:00
}
2012-09-30 09:55:23 +00:00
2013-01-21 16:00:20 +00:00
/*
* DISK KEYRING STORAGE
*
* Whole thing is stored in two files just like in GnuPG:
*
* ${CCR_DIR}/pubkeys
2013-04-01 15:49:58 +00:00
* ${CCR_DIR}/secrets
*
* CCR_DIR is taken from environment, and defaults to ${HOME}/.ccr
2013-01-21 16:00:20 +00:00
*
* format of the files is raw sencode.
*
* Public key file is organized as follows:
*
* (
* "ccr public key storage"
* ( "key-name" pubkey_in_string_encoded_as_sencode )
* ( "key-name" pubkey_in_... )
* ( "key-name" pubkey )
2013-01-21 16:00:20 +00:00
* ...
* )
*
* Reason for pubkeys not to be _embedded_ in sencode is for simpler KeyID
* computation. We'd either need too much encoding/decoding or some ugly magic
* otherwise.
*
2013-01-21 16:00:20 +00:00
* Private keys are stored together with their pubkeys, so that they don't have
* to be generated everytime user asks for them:
*
* (
* "ccr private keyring"
2013-04-01 15:49:58 +00:00
* ( "key-name" privkey pubkey )
* ( "key-name" privkey pubkey )
* ( "key-name" privkey pubkey )
2013-01-21 16:00:20 +00:00
* ...
* )
*
*/
2013-04-15 14:00:26 +00:00
#include <stdlib.h>
static std::string get_user_dir()
{
const char*tmp = getenv ("CCR_DIR");
if (tmp) return std::string (tmp);
2013-04-15 14:00:26 +00:00
const char*home = getenv ("HOME");
if (home) return std::string (home) + "/.ccr";
2013-04-15 14:00:26 +00:00
return "./.ccr"; //fallback for desolate systems
}
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
2013-04-15 14:00:26 +00:00
#include <unistd.h>
#include <errno.h>
#include <fstream>
#define SECRETS_FILENAME "/secrets"
#define PUBKEYS_FILENAME "/pubkeys"
2013-04-15 14:00:26 +00:00
/*
* prepares the user directory with empty files and similar stuff.
*
* We try to setup file permissions properly here and don't care about it later
* (so that the user can override the default value by easy unixy way)
*/
static bool ensure_empty_sencode_file (const std::string&fn, mode_t mode)
{
struct stat st;
if (stat (fn.c_str(), &st) ) {
if (errno != ENOENT)
return false;
//if it simply doesn't exist, create it
sencode_list l;
std::string emptyfile = l.encode();
int fd, res;
fd = creat (fn.c_str(), mode);
if (fd < 0) return false;
res = write (fd, emptyfile.c_str(), emptyfile.length() );
if (close (fd) ) return false;
if (res != emptyfile.length() ) return false;
} else {
if (!S_ISREG (st.st_mode) )
return false;
}
if (access (fn.c_str(), R_OK | W_OK) ) return false;
return true;
}
static bool prepare_user_dir (const std::string&dir)
2013-04-15 14:00:26 +00:00
{
//try to create the directory
mkdir (dir.c_str(), 0777);
//and no matter what, verify it's there
struct stat st;
if (stat (dir.c_str(), &st) )
return false;
if (!S_ISDIR (st.st_mode) )
return false;
//create empty key storages, if not present
std::string fn;
ensure_empty_sencode_file (dir + PUBKEYS_FILENAME, S_IRUSR | S_IWUSR);
ensure_empty_sencode_file (dir + SECRETS_FILENAME, S_IRUSR | S_IWUSR);
2013-04-15 14:00:26 +00:00
return true; //seems m'kay
}
static bool file_get_sencode (const std::string&fn, sencode**out)
{
//check whether it is a file first
struct stat st;
if (stat (fn.c_str(), &st) )
return false;
if (!S_ISREG (st.st_mode) )
return false;
//not we got the size, prepare buffer space
std::string data;
data.resize (st.st_size, 0);
std::ifstream in (fn.c_str(), std::ios::in | std::ios::binary);
if (!in) return false;
in.read (&data[0], st.st_size);
in.close();
if (!sencode_decode (data, out) )
return false;
return true;
}
static bool file_put_sencode (const std::string&fn, sencode*in)
{
std::string data = in->encode();
std::ofstream out (fn.c_str(), std::ios::out | std::ios::binary);
if (!out) return false;
out.write (data.c_str(), data.length() );
if (!out.good() ) return false;
out.close();
if (!out.good() ) return false;
return true;
}
2013-04-01 15:49:58 +00:00
bool keyring::load()
{
std::string dir = get_user_dir();
std::string fn;
sencode_list*L;
/*
* pubkeys loading
*/
fn = dir + PUBKEYS_FILENAME;
sencode* pubkeys;
if (!file_get_sencode (fn, &pubkeys) )
return false;
L = dynamic_cast<sencode_list*> (pubkeys);
if (!L) goto pubkeys_fail;
2013-04-01 15:49:58 +00:00
//parse all pubkey entries
for (std::vector<sencode*>::iterator
i = L->items.begin(), e = L->items.end();
i != e; ++i) {
sencode_list*entry = dynamic_cast<sencode_list*> (*i);
if (!entry) goto pubkeys_fail;
if (entry->items.size() != 2) goto pubkeys_fail;
sencode_bytes
*ident = dynamic_cast<sencode_bytes*> (entry->items[0]),
*pubkey = dynamic_cast<sencode_bytes*> (entry->items[1]);
if (! (ident && pubkey) ) goto pubkeys_fail;
std::string keyid = get_keyid (pubkey->b);
sencode*key;
if (!sencode_decode (pubkey->b, &key) )
goto pubkeys_fail;
pubs[keyid] = pubkey_entry (keyid, ident->b, key);
}
sencode_destroy (pubkeys);
/*
* keypairs loading
*/
fn = dir + SECRETS_FILENAME;
sencode*keypairs;
if (!file_get_sencode (fn, &keypairs) )
return false;
L = dynamic_cast<sencode_list*> (keypairs);
if (!L) goto keypairs_fail;
//entries
for (std::vector<sencode*>::iterator
i = L->items.begin(), e = L->items.end();
i != e; ++i) {
sencode_list*entry = dynamic_cast<sencode_list*> (*i);
if (!entry) goto keypairs_fail;
if (entry->items.size() != 3) goto keypairs_fail;
sencode_bytes
*ident = dynamic_cast<sencode_bytes*> (entry->items[0]),
*privkey = dynamic_cast<sencode_bytes*> (entry->items[1]),
*pubkey = dynamic_cast<sencode_bytes*> (entry->items[2]);
if (! (ident && privkey && pubkey) ) goto keypairs_fail;
std::string keyid = get_keyid (pubkey->b);
sencode *priv, *pub;
if (!sencode_decode (privkey->b, &priv) )
goto keypairs_fail;
if (!sencode_decode (pubkey->b, &pub) ) {
sencode_destroy (priv);
goto keypairs_fail;
}
pairs[keyid] = keypair_entry (keyid, ident->b, pub, priv);
}
sencode_destroy (keypairs);
return true;
pubkeys_fail:
sencode_destroy (pubkeys);
return false;
keypairs_fail:
sencode_destroy (keypairs);
return false;
2013-04-01 15:49:58 +00:00
}
bool keyring::save()
2013-01-21 16:00:20 +00:00
{
std::string dir, fn;
sencode_list*L;
bool res;
dir = get_user_dir();
/*
* pubkeys
*/
L = new sencode_list();
for (std::map<std::string, pubkey_entry>::iterator
i = pubs.begin(), e = pubs.end();
i != e; ++i) {
sencode_list*a = new sencode_list();
a->items.resize (2);
a->items[0] = new sencode_bytes (i->second.name);
a->items[1] = new sencode_bytes (i->second.key->encode() );
L->items.push_back (a);
}
2013-04-01 15:49:58 +00:00
//save them
fn = dir + PUBKEYS_FILENAME;
res = file_put_sencode (fn, L);
sencode_destroy (L);
if (!res) return false;
/*
* keypairs
*/
L = new sencode_list();
for (std::map<std::string, keypair_entry>::iterator
i = pairs.begin(), e = pairs.end();
i != e; ++i) {
sencode_list*a = new sencode_list;
a->items.resize (3);
a->items[0] = new sencode_bytes (i->second.pub.name);
a->items[1] = new sencode_bytes (i->second.privkey->encode() );
a->items[2] = new sencode_bytes (i->second.pub.key->encode() );
L->items.push_back (a);
}
//save
fn = dir + SECRETS_FILENAME;
res = file_put_sencode (fn, L);
sencode_destroy (L);
if (!res) return false;
return true;
2013-04-15 14:00:26 +00:00
}
bool keyring::open()
{
//ensure the existence of file structure
//create the lock
2013-04-15 14:00:26 +00:00
}
bool keyring::close()
{
//close the lock
2013-04-15 14:00:26 +00:00
2013-01-21 16:00:20 +00:00
}