From a2c1c3992d6db91bbb8624f11ffe061cc2665b10 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Sat, 31 Oct 2015 10:00:10 +0100 Subject: [PATCH] mce_qd: add a security warning --- src/mce_qd.cpp | 68 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/src/mce_qd.cpp b/src/mce_qd.cpp index 4d18ba6..504801f 100644 --- a/src/mce_qd.cpp +++ b/src/mce_qd.cpp @@ -22,12 +22,26 @@ using namespace mce_qd; #include "decoding.h" #include "qd_utils.h" +#include "iohelpers.h" #include +static void print_attack_warning() +{ + bool printed = false; + if (printed) return; + err ("\n***MCEQD SECURITY WARNING***\n\n" + "Security of the QD-McEliece variant was greatly reduced to less than 2^50\n" + "by an algebraic attack! The functions are kept only for compatibility.\n" + "Be sure to use another encryption variant instead."); + printed = true; +} + int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, uint m, uint T, uint block_count, uint block_discard) { + print_attack_warning(); + //convenience gf2m&fld = priv.fld; std::vector&essence = priv.essence; @@ -68,8 +82,8 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, i = 1 << s; //i = 2^s Hsig[i] = choose_random (fld.n, rng, used); - essence[s] = fld.add (essence[m - 1], fld.inv (Hsig[i]) ); - used.insert (fld.inv (essence[s]) ); + essence[s] = fld.add (essence[m - 1], fld.inv (Hsig[i])); + used.insert (fld.inv (essence[s])); for (j = 1; j < i; ++j) { if (i + j >= n) break; @@ -79,12 +93,12 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, fld.add ( fld.inv (Hsig[j]), essence[m - 1] - ) ) ); + ))); used.insert (Hsig[i + j]); used.insert (fld.inv (fld.add (fld.inv (Hsig[i + j]), - essence[m - 1]) ) ); + essence[m - 1]))); } } @@ -99,7 +113,7 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, for (i = 0; i < t; ++i) { //tmp(x)=x-z=x-(1/h_i) tmp[0] = fld.inv (Hsig[i]); - if (used.count (tmp[0]) ) { + if (used.count (tmp[0])) { consistent = false; break; } @@ -115,7 +129,7 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, fld.inv (Hsig[i]), essence[m - 1]); - if (used.count (support[i]) ) { + if (used.count (support[i])) { consistent = false; break; } @@ -142,7 +156,7 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, //permute individual blocks priv.block_perms.resize (block_count); - bl.resize (blp.size() ); + bl.resize (blp.size()); for (i = 0; i < block_count; ++i) { priv.block_perms[i] = rng.random (block_size); permutation::permute_dyadic (priv.block_perms[i], @@ -176,7 +190,7 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, /* do a modified QD-blockwise gaussian elimination on hblocks. * If it fails, retry. */ - if (!qd_to_right_echelon_form (hblocks) ) continue; + if (!qd_to_right_echelon_form (hblocks)) continue; pub.qd_sigs.resize2 (block_count - fld.m, block_size * fld.m, 0); @@ -201,6 +215,8 @@ int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, int privkey::prepare() { + print_attack_warning(); + uint s, i, j; std::vector Hsig, support; uint omega; @@ -216,7 +232,7 @@ int privkey::prepare() for (s = 0; ( (uint) 1 << s) < n; ++s) { i = 1 << s; //i = 2^s - Hsig[i] = fld.inv (fld.add (essence[s], essence[fld.m - 1]) ); + Hsig[i] = fld.inv (fld.add (essence[s], essence[fld.m - 1])); for (j = 1; j < i; ++j) { if (i + j >= n) break; @@ -226,7 +242,7 @@ int privkey::prepare() fld.add ( fld.inv (Hsig[j]), essence[fld.m - 1] - ) ) ); + ))); } } @@ -241,7 +257,7 @@ int privkey::prepare() tmp.resize (2, 1); //tmp(x)=x+1 for (i = 0; i < block_size; ++i) { tmp[0] = fld.inv (Hsig[i]); //tmp(x)=x+1/h_i - if (used.count (tmp[0]) ) + if (used.count (tmp[0])) return 1; used.insert (tmp[0]); g.mult (tmp, fld); @@ -256,7 +272,7 @@ int privkey::prepare() (fld.inv (Hsig[i]), essence[fld.m - 1]); //support consistency check - if (used.count (support[i]) ) + if (used.count (support[i])) return 1; used.insert (support[i]); } @@ -264,7 +280,7 @@ int privkey::prepare() //choose some omega omega = fld.n; for (i = 0; i < fld.n; ++i) - if (!used.count (i) ) { + if (!used.count (i)) { omega = i; break; } @@ -342,6 +358,8 @@ int pubkey::encrypt (const bvector& in, bvector&out, prng&rng) int pubkey::encrypt (const bvector & in, bvector & out, const bvector&errors) { + print_attack_warning(); + uint t = 1 << T; bvector p, g, r, cksum; uint i, j; @@ -352,10 +370,10 @@ int pubkey::encrypt (const bvector & in, bvector & out, const bvector&errors) */ //some checks - if (!qd_sigs.width() ) return 1; + if (!qd_sigs.width()) return 1; if (qd_sigs.height() % t) return 1; - if (in.size() != plain_size() ) return 2; - if (errors.size() != cipher_size() ) return 2; + if (in.size() != plain_size()) return 2; + if (errors.size() != cipher_size()) return 2; uint blocks = qd_sigs.height() / t; cksum.resize (qd_sigs.height(), 0); @@ -385,7 +403,7 @@ int pubkey::encrypt (const bvector & in, bvector & out, const bvector&errors) //compute ciphertext out = in; - out.insert (out.end(), cksum.begin(), cksum.end() ); + out.insert (out.end(), cksum.begin(), cksum.end()); out.add (errors); return 0; @@ -399,7 +417,9 @@ int privkey::decrypt (const bvector & in, bvector & out) int privkey::decrypt (const bvector & in, bvector & out, bvector & errors) { - if (in.size() != cipher_size() ) return 2; + print_attack_warning(); + + if (in.size() != cipher_size()) return 2; polynomial synd; uint i, tmp; @@ -412,9 +432,9 @@ int privkey::decrypt (const bvector & in, bvector & out, bvector & errors) synd.resize (h_size, 0); for (i = 0; i < cipher_size(); ++i) if (in[i]) { tmp = fld.inv_square //g(Li)^{-2} - (g.eval (permuted_support[i], fld) ); + (g.eval (permuted_support[i], fld)); fld.add_mults (tmp, permuted_support[i], - synd.begin(), synd.end() ); + synd.begin(), synd.end()); } //decoding @@ -423,23 +443,23 @@ int privkey::decrypt (const bvector & in, bvector & out, bvector & errors) bool failed = false; bvector ev; - if (!evaluate_error_locator_trace (loc, ev, fld) ) + if (!evaluate_error_locator_trace (loc, ev, fld)) failed = true; out = in; - out.resize (plain_size() ); + out.resize (plain_size()); errors.clear(); errors.resize (cipher_size(), 0); //flip error positions of out. for (i = 0; i < ev.size(); ++i) if (ev[i]) { uint epos = support_pos[fld.inv (i)]; - if (epos == fld.n || epos >= cipher_size() ) { + if (epos == fld.n || epos >= cipher_size()) { //found unexpected/wrong support, die. failed = true; continue; } errors[epos] = 1; - if (epos < plain_size() ) + if (epos < plain_size()) out[epos] = !out[epos]; }