1
0
mirror of https://github.com/biergaizi/codecrypt synced 2024-06-30 19:03:12 +00:00
codecrypt/src/algos_enc.cpp

447 lines
11 KiB
C++
Raw Normal View History

2013-01-16 21:30:03 +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/>.
*/
#include "algos_enc.h"
#include "mce_qd.h"
2013-01-17 11:05:01 +00:00
/*
* keygen
*/
2013-01-16 21:30:03 +00:00
int algo_mceqd128::create_keypair (sencode**pub, sencode**priv, prng&rng)
{
mce_qd::pubkey Pub;
mce_qd::privkey Priv;
if (mce_qd::generate (Pub, Priv, rng, 16, 7, 32, 4) )
return 1;
*pub = Pub.serialize();
*priv = Priv.serialize();
return 0;
}
int algo_mceqd192::create_keypair (sencode**pub, sencode**priv, prng&rng)
{
mce_qd::pubkey Pub;
mce_qd::privkey Priv;
if (mce_qd::generate (Pub, Priv, rng, 16, 8, 27, 4) )
return 1;
*pub = Pub.serialize();
*priv = Priv.serialize();
return 0;
}
2013-01-16 21:30:03 +00:00
int algo_mceqd256::create_keypair (sencode**pub, sencode**priv, prng&rng)
{
mce_qd::pubkey Pub;
mce_qd::privkey Priv;
if (mce_qd::generate (Pub, Priv, rng, 16, 8, 32, 4) )
return 1;
*pub = Pub.serialize();
*priv = Priv.serialize();
return 0;
}
2013-01-17 11:05:01 +00:00
/*
* Padding. Ha-ha.
*
* This wouldn't be necessary, but the ciphertext length would then very easily
* leak information about plaintext length (= len(c) - len(McE block) ).
* Moreover we need to somehow convert bvector bits to actual bytes.
*
* First, the bvector is converted to vector of bytes so it's easy to work with
* it. Result is in the form
*
* bits [randombits] nrbits
*
* where
* bits = message bits
* randombits = randomness that pads the message bits to whole byte.
* nrbits = 1 byte with number of random bits applied
*
* Then we are padding stuff with a padding of length at most 255 blocks, to
* format:
2013-01-17 11:05:01 +00:00
*
* messagemessage [randomrandomrandom] 1bytesize
*
* where
* message = "tail" of the message that has overflown to the last block
* random = random bytes
* 1bytesize = how many bytes of the mesage are there in the last block
*
* Note that:
* - the last block is _always present_
2013-01-18 10:38:37 +00:00
* (even if there are no message bytes in it, there still must be the zero
* 1byte number that is telling us.)
2013-01-17 11:05:01 +00:00
* - stuff in bytes is always thought about as big-endian
*
* 1bytesize is determined from message and message length in bits, as:
*
* size = h1(msg) + h2(|msg|)
*
* where h1 and h2 are hash functions to [0..127]
2013-01-17 11:05:01 +00:00
*/
#include "rmd_hash.h"
static byte msg_pad_length (const std::vector<byte>& msg)
{
uint64_t len = msg.size();
std::vector<byte> lenbytes;
lenbytes.resize (sizeof (uint64_t), 0);
for (uint i = 0; i < sizeof (uint64_t); ++i) {
lenbytes[i] = len & 0xff;
len >>= 8;
}
std::vector<byte> tmp;
rmd128hash hf;
byte res = 0;
tmp = hf (lenbytes);
res += tmp[0] & 0x7f;
tmp = hf (msg);
res += tmp[0] & 0x7f;
return res;
}
2013-01-17 11:05:01 +00:00
static void message_pad (const bvector&in, std::vector<byte>&out, prng&rng)
{
out.clear();
//make space for the bit stage
if (in.size() == 0) out.resize (1, 0);
else out.resize ( ( (in.size() - 1) >> 3) + 2, 0);
//copy message bits
uint i;
2013-01-17 11:05:01 +00:00
for (i = 0; i < in.size(); ++i)
if (in[i]) out[i >> 3] |= 1 << (i & 0x7);
//pad with random bits to whole byte
unsigned char rtmp = rng.random (256);
for (; i & 0x7; ++i)
if (rtmp >> (i & 0x7) )
out[i >> 3] |= 1 << (i & 0x7);
//append message overflow size
out[i >> 3] = in.size() & 0x7;
//byte stage
byte padsize = msg_pad_length (out);
uint out_end = out.size();
2013-01-17 11:05:01 +00:00
//make space for the bytes
out.resize (out_end + padsize + 1, 0);
2013-01-17 11:05:01 +00:00
//fill random bytes
for (i = 0; i < padsize; ++i)
out[out_end + i] = rng.random (256);
2013-01-17 11:05:01 +00:00
//fill the overflow size byte
out[out_end + padsize] = padsize;
2013-01-17 11:05:01 +00:00
}
static bool message_unpad (std::vector<byte> in, bvector&out)
2013-01-17 11:05:01 +00:00
{
//check byte padding sizes
if (!in.size() ) return false;
2013-01-16 21:30:03 +00:00
//get rid of the byte padding
uint padsize = in[in.size() - 1];
if (padsize + 1 > in.size() ) return false;
uint in_end = in.size() - padsize - 1;
if (!in_end) return false; //we need the last byte for bit padding
in.resize (in_end);
if (padsize != msg_pad_length (in) ) return false;
//get bit padding information (now it's the last byte)
uint bit_overflow = in[in_end - 1];
//there must not be more than one byte of overflown bits
if (bit_overflow >= 8) return false;
//check if there's byte with overflow bits
if (bit_overflow && (in_end < 2) ) return false;
//convert to bvector
uint msg_size = ( (in_end - (bit_overflow ? 2 : 1) ) << 3)
+ bit_overflow;
out.clear();
out.resize (msg_size);
for (uint i = 0; i < msg_size; ++i)
out[i] = 1 & (in[i >> 3] >> (i & 0x7) );
return true;
2013-01-17 11:05:01 +00:00
}
/*
* Fujisaki-okamoto part
*/
#define min(a,b) ((a)<(b)?(a):(b))
#include "sha_hash.h"
#include "arcfour.h"
/*
2013-01-18 10:38:37 +00:00
* Generic F-O functions. Note that ranksize must be equal to
*
* floor(log(comb(ciphersize,errorcount))/log(2))
*
2013-01-18 10:38:37 +00:00
* otherwise it probably fails. miserably.
*/
template < class pubkey_type,
int plainsize,
int ciphersize,
int errorcount,
class hash_type,
int ranksize >
static int fo_encrypt (const bvector&plain, bvector&cipher,
sencode* pubkey, prng&rng)
{
uint i;
//load the key
pubkey_type Pub;
2013-01-26 21:55:56 +00:00
if (!Pub.unserialize (pubkey) ) return 1;
//verify that key parameters match our scheme
2013-01-26 21:55:56 +00:00
if (Pub.plain_size() != plainsize) return 2;
if (Pub.cipher_size() != ciphersize) return 3;
if (Pub.error_count() != errorcount) return 4;
//create the unencrypted message part
std::vector<byte> M;
message_pad (plain, M, rng);
//create the symmetric key
std::vector<byte> K;
K.resize (plainsize >> 3);
for (i = 0; i < K.size(); ++i) K[i] = rng.random (256);
//create the base for error vector
std::vector<byte> H, M2;
M2 = M;
M2.insert (M2.end(), K.begin(), K.end() );
hash_type hf;
H = hf (M2);
//prepare the error vector
bvector ev_rank;
ev_rank.resize (ranksize);
2013-01-18 10:38:37 +00:00
for (i = 0; i < ranksize; ++i)
ev_rank[i] = 1 & (H[ (i >> 3) % H.size()] >> (i & 0x7) );
bvector ev;
ev_rank.colex_unrank (ev, ciphersize, errorcount);
//prepare plaintext
bvector mce_plain;
mce_plain.resize (plainsize);
2013-01-26 21:55:56 +00:00
for (i = 0; i < plainsize; ++i) mce_plain[i] = 1 & (K[i >> 3] >> (i & 0x7) );
//run McEliece
2013-01-26 21:55:56 +00:00
if (Pub.encrypt (mce_plain, cipher, ev) ) return 5;
//encrypt the message part (xor with arcfour)
arcfour<byte> arc;
arc.init (8);
//whole key must be tossed in, so split if when necessary
for (i = 0; i < (K.size() >> 8); ++i) {
std::vector<byte> subkey (K.begin() + (i << 8),
min (K.end(),
K.begin() + ( (i + 1) << 8) ) );
arc.load_key (subkey);
}
arc.discard (256);
for (i = 0; i < M.size(); ++i) M[i] = M[i] ^ arc.gen();
//append the message part to the ciphertext
cipher.resize (ciphersize + (M.size() << 3) );
for (i = 0; i < (M.size() << 3); ++i)
cipher[ciphersize + i] = 1 & (M[i >> 3] >> (i & 0x7) );
return 0;
}
template < class privkey_type,
int plainsize,
int ciphersize,
int errorcount,
class hash_type,
int ranksize >
static int fo_decrypt (const bvector&cipher, bvector&plain,
sencode* privkey)
{
uint i;
//load the key
privkey_type Priv;
2013-01-26 21:55:56 +00:00
if (!Priv.unserialize (privkey) ) return 1;
if (Priv.prepare() ) return 100;
//verify that key parameters match the scheme
2013-01-26 21:55:56 +00:00
if (Priv.plain_size() != plainsize) return 2;
if (Priv.cipher_size() != ciphersize) return 3;
if (Priv.error_count() != errorcount) return 4;
2013-01-18 10:38:37 +00:00
//get the McE part
2013-01-26 21:55:56 +00:00
if (cipher.size() < ciphersize) return 5;
2013-01-18 10:38:37 +00:00
bvector mce_cipher, mce_plain, ev;
mce_cipher.insert (mce_cipher.end(),
cipher.begin(),
cipher.begin() + ciphersize);
//decrypt the symmetric key
2013-01-26 21:55:56 +00:00
if (Priv.decrypt (mce_cipher, mce_plain, ev) ) return 6;
2013-01-18 10:38:37 +00:00
//convert stuff to byte vectors
std::vector<byte> K, M;
K.resize (plainsize >> 3, 0);
for (i = 0; i < plainsize; ++i)
if (mce_plain[i]) K[i >> 3] |= 1 << (i & 0x7);
uint msize = cipher.size() - ciphersize;
2013-01-26 21:55:56 +00:00
if (msize & 0x7) return 7;
2013-01-18 10:38:37 +00:00
M.resize (msize >> 3, 0);
for (i = 0; i < msize; ++i)
if (cipher[ciphersize + i]) M[i >> 3] |= 1 << (i & 0x7);
//prepare arcfour
arcfour<byte> arc;
arc.init (8);
//stuff in the whole key
for (i = 0; i < (K.size() >> 8); ++i) {
std::vector<byte> subkey (K.begin() + (i << 8),
min (K.end(),
K.begin() + ( (i + 1) << 8) ) );
arc.load_key (subkey);
}
arc.discard (256);
//decrypt the message part
2013-01-18 10:38:37 +00:00
for (i = 0; i < M.size(); ++i) M[i] = M[i] ^ arc.gen();
2013-01-18 10:38:37 +00:00
//compute the hash of K+M
std::vector<byte>H, M2;
M2 = M;
M2.insert (M2.end(), K.begin(), K.end() );
hash_type hf;
H = hf (M2);
/*
* prepare the error vector (again. Avoiding colex ranking which is
* little less deterministic than it could be (produces varying amounts
* of whitespace)
*/
bvector ev_rank, ev2;
ev_rank.resize (ranksize);
for (i = 0; i < ranksize; ++i)
ev_rank[i] = 1 & (H[ (i >> 3) % H.size()] >> (i & 0x7) );
ev_rank.colex_unrank (ev2, ciphersize, errorcount);
//now it should match, otherwise someone mangled the message.
2013-01-26 21:55:56 +00:00
if (ev != ev2) return 8;
2013-01-18 10:38:37 +00:00
//if the message seems okay, unpad and return it.
2013-01-26 21:55:56 +00:00
if (!message_unpad (M, plain) ) return 9;
2013-01-18 10:38:37 +00:00
return 0;
}
/*
* Instances for actual encryption/descryption algorithms
2013-01-17 11:05:01 +00:00
*/
int algo_mceqd128::encrypt (const bvector&plain, bvector&cipher,
sencode* pubkey, prng&rng)
{
return fo_encrypt
< mce_qd::pubkey,
2048, 4096, 128,
sha256hash,
816 >
(plain, cipher, pubkey, rng);
2013-01-17 11:05:01 +00:00
}
int algo_mceqd192::encrypt (const bvector&plain, bvector&cipher,
sencode* pubkey, prng&rng)
{
return fo_encrypt
< mce_qd::pubkey,
2816, 6912, 256,
sha384hash,
1574 >
(plain, cipher, pubkey, rng);
}
2013-01-17 11:05:01 +00:00
int algo_mceqd256::encrypt (const bvector&plain, bvector&cipher,
sencode* pubkey, prng&rng)
{
return fo_encrypt
< mce_qd::pubkey,
4096, 8192, 256,
sha512hash,
1638 >
(plain, cipher, pubkey, rng);
2013-01-17 11:05:01 +00:00
}
int algo_mceqd128::decrypt (const bvector&cipher, bvector&plain,
sencode* privkey)
{
return fo_decrypt
< mce_qd::privkey,
2048, 4096, 128,
sha256hash,
816 >
(cipher, plain, privkey);
2013-01-17 11:05:01 +00:00
}
int algo_mceqd192::decrypt (const bvector&cipher, bvector&plain,
sencode* privkey)
{
return fo_decrypt
< mce_qd::privkey,
2816, 6912, 256,
sha384hash,
1574 >
(cipher, plain, privkey);
}
2013-01-17 11:05:01 +00:00
int algo_mceqd256::decrypt (const bvector&cipher, bvector&plain,
sencode* privkey)
{
return fo_decrypt
< mce_qd::privkey,
4096, 8192, 256,
2013-01-18 10:38:37 +00:00
sha512hash,
1638 >
(cipher, plain, privkey);
2013-01-17 11:05:01 +00:00
}