1
0
mirror of https://github.com/biergaizi/codecrypt synced 2024-06-28 09:53:46 +00:00

algos_sig: complete

This commit is contained in:
Mirek Kratochvil 2013-01-27 15:02:54 +01:00
parent 844bdac363
commit f6c1ee90c9
6 changed files with 222 additions and 9 deletions

@ -62,7 +62,7 @@ public:
}
virtual int sign (const bvector&msg, bvector&sig,
sencode* privkey, bool&dirty, prng&rng) {
sencode** privkey, bool&dirty, prng&rng) {
return -1;
}

@ -16,7 +16,219 @@
* along with Codecrypt. If not, see <http://www.gnu.org/licenses/>.
*/
#include "algos_enc.h"
#include "algos_sig.h"
#include "fmtseq.h"
#include "sha_hash.h"
#include "rmd_hash.h"
#include "arcfour.h"
/*
* DISCUSSION.
*
* Because the Merkle signatures "trapdoor" function isn't really trapdoor but
* plain uninvertible, every message in the scheme MUST have exactly one
* possible signature -- well there's no possibility to verify stuff
* nondeterministically. That completely sucks, because we can't get any
* coolness of "Probabilistic signature scheme" as known from RSA and others
* with inversion possibilities.
*
* That basically means that plaintexts MUST be prepared in the way that the
* signer knows they will never collide with anything he could want to sign (or
* especially NOT want to sign). Hopefully this is a common practice for
* digital signatures now.
*
* This scheme, apart from actual signature, protects against finding a
* low-length hash collision (which isn't very hard, assuming general
* availability of amounts of storage suitable for rainbow tables) by expanding
* the message to a reasonable minimum length prior to hashing. Algorithm is
* simple:
*
* 1. convert message from bvector to byte representation
*
* 2. if message is longer than the minimum length, forget padding :)
*
* 3. if it's shorter, use it as a seed for PRNG and pad it with PRNG output to
* minimum length.
*
* Then hash it as usual, FMTSeq it, publish the signature, enjoy.
*/
#define min(a,b) ((a)<(b)?(a):(b))
static void msg_pad (const bvector&in, std::vector<byte>&out, size_t minsize)
{
uint i;
out.clear();
out.resize ( ( (in.size() - 1) >> 3) + 1, 0);
for (i = 0; i < in.size(); ++i)
if (in[i]) out[i >> 3] |= 1 << (i & 0x7);
if (out.size() >= minsize) return;
arcfour<byte> g;
g.init (8);
//stuff in as much seed material as possible
for (i = 0; i < (out.size() >> 8); ++i) {
std::vector<byte> sub (out.begin() + (i << 8),
min (out.end(),
out.begin() + ( (i + 1) << 8) ) );
g.load_key (sub);
}
g.discard (256);
i = out.size();
out.resize (minsize);
for (; i < minsize; ++i) out[i] = g.gen();
}
/*
* actual signature stuff.
*/
template <int h, int l, int hs, class message_hash, class tree_hash>
int fmtseq_generic_sign (const bvector&msg,
bvector&sig,
sencode**privkey,
bool&dirty,
prng&rng)
{
//load the key
fmtseq::privkey Priv;
if (!Priv.unserialize (*privkey) ) return 1;
//check parameters
if ( (Priv.h != h) || (Priv.l != l)
|| (Priv.hs != hs) ) return 2;
//prepare the message and hash it
std::vector<byte> M, H;
msg_pad (msg, M, hs);
message_hash msghf;
H = msghf (M);
//convert to bvector
bvector hash;
hash.resize (hs, 0);
for (uint i = 0; i < hs; ++i) hash[i] = 1 & (H[i >> 3] >> (i & 0x7) );
//make a signature
tree_hash hf;
if (Priv.sign (hash, sig, hf) ) return 3;
//if it went okay, refresh the privkey
sencode* new_pk = Priv.serialize();
if (!new_pk) return 4;
sencode_destroy (*privkey);
*privkey = new_pk;
dirty = true;
//all OK.
return 0;
}
template <int h, int l, int hs, class message_hash, class tree_hash>
int fmtseq_generic_verify (const bvector&sig,
const bvector&msg,
sencode*pubkey)
{
//load the key
fmtseq::pubkey Pub;
if (!Pub.unserialize (pubkey) ) return 1;
//check parameters
if ( (Pub.H != h * l) || (Pub.hs != hs) ) return 2;
//prepare the message and hash it
std::vector<byte> M, H;
msg_pad (msg, M, hs);
message_hash msghf;
H = msghf (M);
//convert to bvector
bvector hash;
hash.resize (hs, 0);
for (uint i = 0; i < hs; ++i) hash[i] = 1 & (H[i >> 3] >> (i & 0x7) );
//check the signature
tree_hash hf;
if (Pub.verify (sig, hash, hf) ) return 3;
//otherwise the sig is okay!
return 0;
}
/*
* actual instantiations
*/
int algo_fmtseq128::sign (const bvector&msg,
bvector&sig,
sencode**privkey,
bool&dirty,
prng&rng)
{
return fmtseq_generic_sign
<4, 4, 256, sha256hash, rmd128hash>
(msg, sig, privkey, dirty, rng);
}
int algo_fmtseq128::verify (const bvector&sig,
const bvector&msg,
sencode*pubkey)
{
return fmtseq_generic_verify
<4, 4, 256, sha256hash, rmd128hash>
(sig, msg, pubkey);
}
int algo_fmtseq256::sign (const bvector&msg,
bvector&sig,
sencode**privkey,
bool&dirty,
prng&rng)
{
return fmtseq_generic_sign
<4, 4, 512, sha512hash, sha256hash>
(msg, sig, privkey, dirty, rng);
}
int algo_fmtseq256::verify (const bvector&sig,
const bvector&msg,
sencode*pubkey)
{
return fmtseq_generic_verify
<4, 4, 512, sha512hash, sha256hash>
(sig, msg, pubkey);
}
int algo_fmtseq128::create_keypair (sencode**pub, sencode**priv, prng&rng)
{
fmtseq::pubkey Pub;
fmtseq::privkey Priv;
rmd128hash hf;
if (fmtseq::generate (Pub, Priv, rng, hf, 256, 4, 4) )
return 1;
*pub = Pub.serialize();
*priv = Priv.serialize();
}
int algo_fmtseq256::create_keypair (sencode**pub, sencode**priv, prng&rng)
{
fmtseq::pubkey Pub;
fmtseq::privkey Priv;
sha256hash hf;
if (fmtseq::generate (Pub, Priv, rng, hf, 512, 4, 4) )
return 1;
*pub = Pub.serialize();
*priv = Priv.serialize();
}

@ -37,7 +37,7 @@ public:
}
virtual int sign (const bvector&msg, bvector&sig,
sencode* privkey, bool&dirty, prng&rng);
sencode** privkey, bool&dirty, prng&rng);
virtual int verify (const bvector&sig, const bvector&msg,
sencode* pubkey);
int create_keypair (sencode**pub, sencode**priv, prng&rng);
@ -59,7 +59,7 @@ public:
}
virtual int sign (const bvector&msg, bvector&sig,
sencode* privkey, bool&dirty, prng&rng);
sencode** privkey, bool&dirty, prng&rng);
virtual int verify (const bvector&sig, const bvector&msg,
sencode* pubkey);
int create_keypair (sencode**pub, sencode**priv, prng&rng);

@ -81,7 +81,8 @@ public:
}
uint signature_size (hash_func&hf) {
return ( (h * l + fmtseq_commitments (hs) ) * hf.size() * 8) + (h * l);
return ( (h * l + fmtseq_commitments (hs) ) * hf.size() * 8)
+ (h * l);
}
sencode* serialize();

@ -82,7 +82,7 @@ int signed_msg::sign (const bvector&msg,
bool privkey_dirty = false;
int r;
r = alg->sign (message, signature, privkey, privkey_dirty, rng);
r = alg->sign (message, signature, &privkey, privkey_dirty, rng);
if (r) return r;
@ -90,7 +90,7 @@ int signed_msg::sign (const bvector&msg,
kr.remove_privkey (key_id);
//this actually shouldn't fail, key_id is not present
kr.store_privkey (key_id, privkey);
//we can't output a signature without storing privkey changes
//we can't output a signature without storing privkey changes!
if (!kr.disk_sync() ) return 3;
}

@ -17,8 +17,8 @@
* along with Codecrypt. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _sha_hash_h_
#define _sha_hash_h_
#ifndef _rmd_hash_h_
#define _rmd_hash_h_
#include "hash.h"
#include "ripemd128.h"