void mceliece_decrypt( secure_vector<byte>& plaintext, secure_vector<byte> & error_mask, const byte ciphertext[], size_t ciphertext_len, const McEliece_PrivateKey & key) { secure_vector<gf2m> error_pos; plaintext = mceliece_decrypt(error_pos, ciphertext, ciphertext_len, key); const size_t code_length = key.get_code_length(); secure_vector<byte> result((code_length+7)/8); for(auto&& pos : error_pos) { if(pos > code_length) { throw Invalid_Argument("error position larger than code size"); } result[pos / 8] |= (1 << (pos % 8)); } error_mask = result; }
secure_vector<byte> mceies_decrypt(const McEliece_PrivateKey& privkey, const byte ct[], size_t ct_len, const byte ad[], size_t ad_len, const std::string& algo) { try { McEliece_KEM_Decryptor kem_op(privkey); const size_t mce_code_bytes = (privkey.get_code_length() + 7) / 8; std::unique_ptr<AEAD_Mode> aead(get_aead(algo, DECRYPTION)); if(!aead) throw std::runtime_error("Unable to create AEAD instance '" + algo + "'"); const size_t nonce_len = aead->default_nonce_length(); if(ct_len < mce_code_bytes + nonce_len + aead->tag_size()) throw std::runtime_error("Input message too small to be valid"); const secure_vector<byte> mce_key = kem_op.decrypt(ct, mce_code_bytes); aead->set_key(aead_key(mce_key, *aead)); aead->set_associated_data(ad, ad_len); secure_vector<byte> pt(ct + mce_code_bytes + nonce_len, ct + ct_len); aead->start(&ct[mce_code_bytes], nonce_len); aead->finish(pt, 0); return pt; } catch(std::exception& e) { throw std::runtime_error("mce_decrypt failed: " + std::string(e.what())); } }
/** * @param p_err_pos_len must point to the available length of err_pos on input, the * function will set it to the actual number of errors returned in the err_pos * array */ secure_vector<byte> mceliece_decrypt( secure_vector<gf2m> & error_pos, const byte *ciphertext, u32bit ciphertext_len, const McEliece_PrivateKey & key) { u32bit dimension = key.get_dimension(); u32bit codimension = key.get_codimension(); u32bit t = key.get_goppa_polyn().get_degree(); polyn_gf2m syndrome_polyn(key.get_goppa_polyn().get_sp_field()); // init as zero polyn const unsigned unused_pt_bits = dimension % 8; const byte unused_pt_bits_mask = (1 << unused_pt_bits) - 1; if(ciphertext_len != (key.get_code_length()+7)/8) { throw Invalid_Argument("wrong size of McEliece ciphertext"); } u32bit cleartext_len = (key.get_message_word_bit_length()+7)/8; if(cleartext_len != bit_size_to_byte_size(dimension)) { throw Invalid_Argument("mce-decryption: wrong length of cleartext buffer"); } secure_vector<u32bit> syndrome_vec(bit_size_to_32bit_size(codimension)); matrix_arr_mul(key.get_H_coeffs(), key.get_code_length(), bit_size_to_32bit_size(codimension), ciphertext, syndrome_vec.data(), syndrome_vec.size()); secure_vector<byte> syndrome_byte_vec(bit_size_to_byte_size(codimension)); u32bit syndrome_byte_vec_size = syndrome_byte_vec.size(); for(u32bit i = 0; i < syndrome_byte_vec_size; i++) { syndrome_byte_vec[i] = syndrome_vec[i/4] >> (8* (i % 4)); } syndrome_polyn = polyn_gf2m(t-1, syndrome_byte_vec.data(), bit_size_to_byte_size(codimension), key.get_goppa_polyn().get_sp_field()); syndrome_polyn.get_degree(); error_pos = goppa_decode(syndrome_polyn, key.get_goppa_polyn(), key.get_sqrtmod(), key.get_Linv()); u32bit nb_err = error_pos.size(); secure_vector<byte> cleartext(cleartext_len); copy_mem(cleartext.data(), ciphertext, cleartext_len); for(u32bit i = 0; i < nb_err; i++) { gf2m current = error_pos[i]; if(current >= cleartext_len * 8) { // an invalid position, this shouldn't happen continue; } cleartext[current / 8] ^= (1 << (current % 8)); } if(unused_pt_bits) { cleartext[cleartext_len - 1] &= unused_pt_bits_mask; } return cleartext; }