diff --git a/src/actions.cpp b/src/actions.cpp index f63f78a..5939815 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -24,6 +24,7 @@ #include "envelope.h" #include "base64.h" #include "message.h" +#include "hashfile.h" #include "bvector.h" #include @@ -34,6 +35,7 @@ #define ENVELOPE_SIG "signed" #define ENVELOPE_CLEARSIGN "clearsigned" #define ENVELOPE_DETACHSIGN "detachsign" +#define ENVELOPE_HASHFILE "hashfile" #define MSG_CLEARTEXT "MESSAGE-IN-CLEARTEXT" #define MSG_DETACHED "MESSAGE-DETACHED" @@ -315,11 +317,57 @@ int action_decrypt (bool armor, return 0; } +int action_hash_sign (bool armor, const std::string&symmetric) +{ + hashfile hf; + if (!hf.create (std::cin) ) { + err ("error: hashing failed"); + return 1; + } + + sencode*H = hf.serialize(); + std::string data = H->encode(); + sencode_destroy (H); + + std::ofstream hf_out; + hf_out.open (symmetric == "-" ? "/dev/stdin" : symmetric.c_str(), + std::ios::out | std::ios::binary); + if (!hf_out) { + err ("error: can't open hashfile for writing"); + return 1; + } + + if (armor) { + std::vector parts; + parts.resize (1); + base64_encode (data, parts[0]); + arcfour_rng r; + r.seed (256); + data = envelope_format (ENVELOPE_HASHFILE, parts, r); + } + + hf_out << data; + if (!hf_out.good() ) { + err ("error: can't write to hashfile"); + return 1; + } + + hf_out.close(); + if (!hf_out.good() ) { + err ("error: couldn't close hashfile"); + return 1; + } + + return 0; +} int action_sign (const std::string&user, bool armor, const std::string&detach, bool clearsign, const std::string&symmetric, keyring&KR, algorithm_suite&AS) { + //symmetric processing has its own function + if (symmetric.length() ) + return action_hash_sign (armor, symmetric); /* * check detach/armor/clearsign validity first. @@ -451,11 +499,70 @@ int action_sign (const std::string&user, bool armor, const std::string&detach, return 0; } +int action_hash_verify (bool armor, const std::string&symmetric) +{ + // first, input the hashfile + std::ifstream hf_in; + hf_in.open (symmetric.c_str(), std::ios::in | std::ios::binary); + if (!hf_in) { + err ("error: can't open hashfile"); + return 1; + } + + std::string hf_data; + if (!read_all_input (hf_data, hf_in) ) { + err ("error: can't read hashfile"); + return 1; + } + hf_in.close(); + + if (armor) { + std::vector parts; + std::string type; + if (!envelope_read (hf_data, 0, type, parts) ) { + err ("error: no data envelope found"); + return 1; + } + + if (type != ENVELOPE_HASHFILE || parts.size() != 1) { + err ("error: wrong envelope format"); + return 1; + } + + if (!base64_decode (parts[0], hf_data) ) { + err ("error: malformed data"); + return 1; + } + } + + sencode*H = sencode_decode (hf_data); + if (!H) { + err ("error: could not parse input sencode"); + return 1; + } + + hashfile hf; + if (!hf.unserialize (H) ) { + err ("error: could not parse input structure"); + return 1; + } + + sencode_destroy (H); + + int ret = hf.verify (std::cin); + if (ret) err ("error: hashfile verification failed"); + + return ret; +} int action_verify (bool armor, const std::string&detach, bool clearsign, bool yes, const std::string&symmetric, keyring&KR, algorithm_suite&AS) { + //symmetric processing has its own function + if (symmetric.length() ) + return action_hash_verify (armor, symmetric); + /* * check flags validity, open detach if possible */ diff --git a/src/hashfile.h b/src/hashfile.h index 4d6b211..b9a19ff 100644 --- a/src/hashfile.h +++ b/src/hashfile.h @@ -20,6 +20,8 @@ #define _ccr_hashfile_h_ #include "types.h" +#include "sencode.h" + #include #include #include @@ -28,10 +30,14 @@ class hashfile { public: - std::map > hashes; + typedef std::map > hashes_t; + hashes_t hashes; bool create (std::istream&); int verify (std::istream&); + + sencode* serialize(); + bool unserialize (sencode*); }; #endif diff --git a/src/serialization.cpp b/src/serialization.cpp index 6ce9c2e..3280d5a 100644 --- a/src/serialization.cpp +++ b/src/serialization.cpp @@ -28,6 +28,7 @@ #include "mce_qd.h" #include "fmtseq.h" #include "message.h" +#include "hashfile.h" static sencode* serialize_uint_vector (std::vector*v) { @@ -666,3 +667,63 @@ bool signed_msg::unserialize (sencode*s) return message.unserialize (L->items[3]) && signature.unserialize (L->items[4]); } + +/* + * hashfiles are stored as + * + * ( CCR-HASHFILE + * ( HASH1NAME HASH1DATA ) + * ( HASH2NAME HASH2DATA ) + * ... + * ) + */ + +#define HASHFILE_IDENT "CCR-HASHFILE" + +sencode* hashfile::serialize() +{ + sencode_list*L = new sencode_list(); + L->items.resize (1 + hashes.size() ); + L->items[0] = new sencode_bytes (HASHFILE_IDENT); + uint pos = 1; + for (hashes_t::iterator i = hashes.begin(), e = hashes.end(); i != e; ++i, ++pos) { + sencode_list*hash = new sencode_list(); + hash->items.resize (2); + hash->items[0] = new sencode_bytes (i->first); + hash->items[1] = new sencode_bytes (i->second); + L->items[pos] = hash; + } + + return L; +} + +bool hashfile::unserialize (sencode*s) +{ + sencode_list*L = dynamic_cast (s); + if (!L) return false; + if (L->items.size() < 1) return false; + + sencode_bytes*ID; + + ID = dynamic_cast (L->items[0]); + if (!ID) return false; + if (ID->b != HASHFILE_IDENT) return false; + + for (uint pos = 1; pos < L->items.size(); ++pos) { + sencode_list*hash = dynamic_cast (L->items[pos]); + if (hash->items.size() != 2) return false; + + sencode_bytes + *name = dynamic_cast (hash->items[0]), + *value = dynamic_cast (hash->items[1]); + + if (!name || !value) return false; + + //prevent multiple hash entries of same hash + if (hashes.count (name->b) ) return false; + + hashes[name->b] = std::vector (value->b.begin(), value->b.end() ); + } + + return true; +}