// // DESCRIPTION 'EC Menezes-Vanstone cryptosystem functions openssl/Linux' // COMPILER 'gcc (GCC) 4.8.2' // FILE 'ecmv.h' // AUTHOR "Nick Korepanov" // Linux-3.10.104, glibc-2.17, OpenSSL 1.0.1u // ECC-192/224/256 // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // Author of this program can be contacted by electronic mail // korepanovnd@gmail.com // Copyright (c) 2017 Nick Korepanov. All rights reserved. // This product includes software developed by the OpenSSL Project // for use in the OpenSSL Toolkit. (http://www.openssl.org/) // COMPUTER SECURITY AND CRYPTOGRAPHY, ALAN G. KONHEIM // Published by John Wiley & Sons, Inc., Hoboken, New Jersey, 2007 // Library of Congress Cataloging-in-Publication Data: // Konheim, Alan G., 1934– // Computer security & cryptography / by Alan G. Konheim. // p. cm. // Includes bibliographical references and index. // ISBN-13: 978-0-471-94783-7 // ISBN-10: 0-471-94783-0 // 1. Computer security. 2. Cryptography. I. Title. // QA76.9.A25K638 2007 // 005.8--dc22 2006049338 // 15.9 THE MENEZES–VANSTONE ELLIPTIC CURVE CRYPTOSYSTEM, p. 443 // Another very significant source - "A Weakness of Menezes-Vanstone Cryptosystem", Klaus Kiefer, member of research group of prof. J. Buchmann, 1997 // Shortly, this work show ability of "known plain text attack (KPTA)", with probability O(1/p) of false detection. // What does it mean? If we encrypt 128-bit session key, for success KPTA we must search in 2^128 combinations of session key ... // Known plaintext attack for EC MV cryptosystem // Curve E(p,a,b) known from public key, // y0, y1, y2 - ciphertext // random select 1 < x1 < p and 1< x2 < p // calculate inversion a=inv(x1)(mod p), b=inv(x2)(mod p) // c1=a*y1(mod p), c2=b*y2(mod p) // if C(c1,c2) is point of curve E, x1 and x2 is plaintext with error probability O(1/p) // z=((c1)^3 + a*c1 + b)(mod p) // if (z^((p-1)/2))(mod p) == 1 there are 2 points (c1,+-c2) in curve E(p,a,b) //#include <stdio.h> #include <stdlib.h> #include <string.h> //#include <unistd.h> #include <openssl/rand.h> #define OPENSSL_NO_EC2M #include <openssl/ec.h> #define FORMATBIN 1 #define FORMATHEX 0 struct BinFmt192 // binary format of ECMV encrypted block, EC key = 192 bits { unsigned char y0[1+192/4]; // 2*24 byte BIGNUM + 1 header byte unsigned char z1; unsigned char y1[192/8]; // 24 bytes BIGNUM unsigned char z2; unsigned char y2[192/8]; // 24 bytes BIGNUM unsigned char z3; }; // size = 100 bytes struct BinFmt224 // binary format of ECMV encrypted block, EC key = 224 bits { unsigned char y0[1+224/4]; // 2*28 byte BIGNUM + 1 header byte unsigned char z1; unsigned char y1[224/8]; // 28 bytes BIGNUM unsigned char z2; unsigned char y2[224/8]; // 28 bytes BIGNUM unsigned char z3; }; // size = 116 bytes struct BinFmt256 // binary format of ECMV encrypted block, EC key = 256 bits { unsigned char y0[1+256/4]; // 2*32 byte BIGNUM + 1 header byte unsigned char z1; unsigned char y1[256/8]; // 32 bytes BIGNUM unsigned char z2; unsigned char y2[256/8]; // 32 bytes BIGNUM unsigned char z3; }; // size = 132 bytes // Encrypt plaintext of length len with public EC key pubkey // and store ciphertext in chipher = y0 (point), y1 (bignum), y2 (bignum) // return error code, 0 if all OK // Error codes: /* * 1 // no curve in key? * 2 // wrong plaintext has odd length * 3 // plaintext too long for this key * 8 // binary format of encrypted block not defined for this key length * 4 // internal error: ks is wrong, error in do-while * 5 // internal error: error in EC_POINT_mul y0=ks*g * 6 // internal error: error in EC_POINT_mul z=ks*q * 7 // internal error: error EC_POINT_get_affine_coordinates_GFp * errors 4,5,6,7 lead to memory leak :( * */ // hex format: // Encrypted text consist of 3 hex strings, each is ending with '\n'=0x0A // First string has '04' header and two times longer than second and third // length of encrypted block = 2*4*bits/8 + 5 = bits + 5 bytes, where 'bits' is length of EC key in bits // Plaintext data MUST be of even length in bytes and not longer than 2*bits/8 = bits/4 bytes // bin format: // Encrypted text is binary block consist of 3 binary elements, each is ending with NULL=0x00 byte // First element has 0x04 header and two times longer than second and third // length of encrypted block in binary form = 4*bits/8 + 4 = bits/2 + 4 bytes, where 'bits' is length of EC key in bits // In this example I used 192,224,256 bit EC keys and binary form for other key length don't supported :( int EC_MV_pubkey_encrypt(unsigned char *cipher, EC_KEY* pubkey, unsigned char* plaintext, size_t len, int format); // Decrypt with private EC key privkey ciphertext in cipher = y0 (point), y1 (bignum), y2 (bignum) // and store result in plaintext // return error code, 0 if all OK /* Error codes: * 1 // no curve in key? * 8 // unknown format of ECMV encrypted block * 9 // binary format of encrypted block not defined for this key length * 10 // wrong format of binary encrypted block * 2 // invalid hex point y0 representation * 3,4 // wrong format of HEX encrypted data * 11 // point y0 is not on curve * 6 // internal error: error in EC_POINT_mul z=ks*q * 7 // internal error: error EC_POINT_get_affine_coordinates_GFp * errors 2,3,4,11,6,7 lead to memory leak :( * */ int EC_MV_privkey_decrypt(unsigned char* cipher, EC_KEY *privkey, unsigned char* plaintext);
// // DESCRIPTION 'EC Menezes-Vanstone cryptosystem functions openssl/Linux' // COMPILER 'gcc (GCC) 4.8.2' // FILE 'ecmv.c' // AUTHOR "Nick Korepanov" // Linux-3.10.104, glibc-2.17, OpenSSL 1.0.1u // ECC-192/224/256 // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // Author of this program can be contacted by electronic mail // korepanovnd@gmail.com // Copyright (c) 2017 Nick Korepanov. All rights reserved. // This product includes software developed by the OpenSSL Project // for use in the OpenSSL Toolkit. (http://www.openssl.org/) #include "ecmv.h" int EC_MV_pubkey_encrypt(unsigned char *cipher, EC_KEY* pubkey, unsigned char* plaintext, size_t len, int format) { const EC_GROUP *curve; // curve, q and g are part of pubkey, it was allocated and free with pubkey const EC_POINT *q; EC_POINT *y0, *z; BIGNUM *p, *a, *b, *ks, *o1, *z1, *z2, *y1, *y2, *x1, *x2, *ord; int bits, i=0, err; unsigned char buffer[250]; //size_t length; BN_CTX *ctx; curve=EC_KEY_get0_group(pubkey); if(curve) bits = EC_GROUP_get_degree(curve); else return 1; // no curve in key? if(len%2) return 2; // wrong plaintext has odd length if(len > 2*bits/8) return 3; // plaintext too long for this key if( !(bits == 192 || bits == 224 || bits == 256) && format) return 8; // binary format of encrypted block not defined for this key length //prepare bignums p=BN_new(); a=BN_new(); b=BN_new(); ks=BN_new(); o1=BN_new(); z1=BN_new(); z2=BN_new(); y1=BN_new(); y2=BN_new(); x1=BN_new(); x2=BN_new(); ord=BN_new(); ctx=BN_CTX_new(); //prepare points //q=EC_POINT_new(curve); g=EC_POINT_new(curve); y0=EC_POINT_new(curve); z=EC_POINT_new(curve); // split plaintext at two parts, and assign it to BIGNUMs BN_bin2bn(plaintext, len/2, x1); BN_bin2bn(plaintext+len/2, len/2, x2); // get public key q q=EC_KEY_get0_public_key(pubkey); // get generator point g //g=EC_GROUP_get0_generator(curve); // get order of g EC_GROUP_get_order(curve, ord, ctx ); // get prime p EC_GROUP_get_curve_GFp(curve, p, a, b, ctx ); BN_sub(o1, ord, BN_value_one()); // o1=ord-1 do { if( i>= 10) break; // make secret session key ks > 1 and ks < (o-1) RAND_bytes(buffer, bits/8); BN_bin2bn(buffer, bits/8, ks); i++; } while( BN_cmp(BN_value_one(), ks) >=0 || BN_cmp(o1,ks) <=0 ); if(i>=10) return 4; // ks is wrong, error in do-while // y0=ks*g err=EC_POINT_mul(curve, y0, ks, NULL, NULL, ctx ); if(err == 0) return 5; // error in EC_POINT_mul y0=ks*g // z=ks*q err=EC_POINT_mul(curve, z, NULL, q, ks, ctx ); if(err == 0) return 6; // error in EC_POINT_mul z=ks*q // get z1,z2 = Z(z1,z2) err=EC_POINT_get_affine_coordinates_GFp(curve, z, z1, z2, ctx ); if(err == 0) return 7; //error EC_POINT_get_affine_coordinates_GFp //y1 = z1*x1(modulo p) //y2 = z2*x2(modulo p) BN_mod_mul(y1, z1, x1, p, ctx); BN_mod_mul(y2, z2, x2, p, ctx); /* if bits=192, 24 bytes per every BIGNUM, point contains 2 Bignum + 1 byte header */ if(format) { // bin format if(bits == 192) { struct BinFmt192 *out; out=(struct BinFmt192 *)cipher; EC_POINT_point2oct(curve, y0, POINT_CONVERSION_UNCOMPRESSED, (unsigned char*)&out->y0, sizeof(out->y0), ctx); BN_bn2bin(y1, (unsigned char*)&out->y1); BN_bn2bin(y2, (unsigned char*)&out->y2); out->z1=out->z2=out->z3=0; } if(bits == 224) { struct BinFmt224 *out; out=(struct BinFmt224 *)cipher; EC_POINT_point2oct(curve, y0, POINT_CONVERSION_UNCOMPRESSED, (unsigned char*)&out->y0, sizeof(out->y0), ctx); BN_bn2bin(y1, (unsigned char*)&out->y1); BN_bn2bin(y2, (unsigned char*)&out->y2); out->z1=out->z2=out->z3=0; } if(bits == 256) { struct BinFmt256 *out; out=(struct BinFmt256 *)cipher; EC_POINT_point2oct(curve, y0, POINT_CONVERSION_UNCOMPRESSED, (unsigned char*)&out->y0, sizeof(out->y0), ctx); BN_bn2bin(y1, (unsigned char*)&out->y1); BN_bn2bin(y2, (unsigned char*)&out->y2); out->z1=out->z2=out->z3=0; } } else { // hex format strcpy((char*)cipher, EC_POINT_point2hex(curve, y0, POINT_CONVERSION_UNCOMPRESSED, ctx)); strcat((char*)cipher, "\n"); strcat((char*)cipher, BN_bn2hex(y1)); strcat((char*)cipher, "\n"); strcat((char*)cipher, BN_bn2hex(y2)); strcat((char*)cipher, "\n"); } // free points //EC_POINT_free(q); EC_POINT_free(g); EC_POINT_free(y0); EC_POINT_clear_free(z); BN_CTX_free(ctx); BN_clear(ks); BN_clear(x1); BN_clear(x2); BN_clear(z1); BN_clear(z2); //free bignums BN_free(p); BN_free(a); BN_free(b); BN_free(ks); BN_free(o1); BN_free(z1); BN_free(z2); BN_free(y1); BN_free(y2); BN_free(x1); BN_free(x2); BN_free(ord); return 0; } int EC_MV_privkey_decrypt(unsigned char* cipher, EC_KEY *privkey, unsigned char* plaintext) { const EC_GROUP *curve; // curve, d are part of privkey, it was allocated and free with privkey const BIGNUM *d; EC_POINT *y0, *z; BIGNUM *p, *a, *b, *z1, *z2, *y1, *y2, *x1, *x2; int err, bits, format; unsigned char *ptr; BN_CTX *ctx; ctx=BN_CTX_new(); curve=EC_KEY_get0_group(privkey); if(!curve) return 1; // no curve in key? bits = EC_GROUP_get_degree(curve); if( cipher[0] == 0x04 ) format=FORMATBIN; if( cipher[0] == 0x30 ) format=FORMATHEX; if(cipher[0] != 0x04 && cipher[0] != 0x30) return 8; // unknown format of ECMV encrypted block if( !(bits == 192 || bits == 224 || bits == 256) && format) return 9; // binary format of encrypted block not defined for this key length if(format && bits == 192 && (cipher[48+1] || cipher[48+1+24+1] || cipher[48+1+24+1+24+1] )) return 10; //wrong format of binary encrypted block if(format && bits == 224 && (cipher[56+1] || cipher[56+1+28+1] || cipher[56+1+28+1+28+1] )) return 10; //wrong format of binary encrypted block if(format && bits == 256 && (cipher[64+1] || cipher[64+1+32+1] || cipher[64+1+32+1+32+1] )) return 10; //wrong format of binary encrypted block //prepare bignums p=BN_new(); a=BN_new(); b=BN_new(); z1=BN_new(); z2=BN_new(); y1=BN_new(); y2=BN_new(); x1=BN_new(); x2=BN_new(); //prepare points y0=EC_POINT_new(curve); z=EC_POINT_new(curve); // get private key d d=EC_KEY_get0_private_key(privkey); // get prime p EC_GROUP_get_curve_GFp(curve, p, a, b, ctx); if(format) { if(bits == 192) { struct BinFmt192 *in; in=(struct BinFmt192 *)cipher; EC_POINT_oct2point(curve, y0, (const unsigned char *)&in->y0, sizeof(in->y0), ctx); BN_bin2bn((const unsigned char *)&in->y1, sizeof(in->y1), y1); BN_bin2bn((const unsigned char *)&in->y2, sizeof(in->y2), y2); } if(bits == 224) { struct BinFmt224 *in; in=(struct BinFmt224 *)cipher; EC_POINT_oct2point(curve, y0, (const unsigned char *)&in->y0, sizeof(in->y0), ctx); BN_bin2bn((const unsigned char *)&in->y1, sizeof(in->y1), y1); BN_bin2bn((const unsigned char *)&in->y2, sizeof(in->y2), y2); } if(bits == 256) { struct BinFmt256 *in; in=(struct BinFmt256 *)cipher; EC_POINT_oct2point(curve, y0, (const unsigned char *)&in->y0, sizeof(in->y0), ctx); BN_bin2bn((const unsigned char *)&in->y1, sizeof(in->y1), y1); BN_bin2bn((const unsigned char *)&in->y2, sizeof(in->y2), y2); } } else { // read y0 ptr=cipher; y0=EC_POINT_hex2point(curve, (const char *)ptr, y0, ctx); if(y0 == NULL) return 2; //invalid hex point representation //read y1,y2 ptr=strchr((const char *)ptr,'\n'); if(ptr == NULL) return 3; //wrong format of encrypted data ptr++; BN_hex2bn(&y1, (const char *)ptr); ptr=strchr((const char *)ptr,'\n'); if(ptr == NULL) return 4; //wrong format of encrypted data ptr++; BN_hex2bn(&y2, (const char *)ptr); } if( !EC_POINT_is_on_curve(curve, (const EC_POINT *)y0, ctx) ) return 11; // point is not on curve // z=d*y0=d*ks*g=ks*q err=EC_POINT_mul(curve, z, NULL, y0, d, ctx ); if(err == 0) return 6; // error in EC_POINT_mul z=ks*q // get z1,z2 = Z(z1,z2) err=EC_POINT_get_affine_coordinates_GFp(curve, z, z1, z2, ctx ); if(err == 0) return 7; //error EC_POINT_get_affine_coordinates_GFp // a=inv(z1)(mod p) BN_mod_inverse(a, z1, p, ctx); // b=inv(z2)(mod p) BN_mod_inverse(b, z2, p, ctx); //x1 = a*y1(modulo p) //x2 = b*y2(modulo p) BN_mod_mul(x1, a, y1, p, ctx); BN_mod_mul(x2, b, y2, p, ctx); // decode plaintext from two parts BN_bn2bin(x1, plaintext); BN_bn2bin(x2, plaintext+BN_num_bytes(x1)); // free points EC_POINT_free(y0); EC_POINT_clear_free(z); BN_CTX_free(ctx); BN_clear(x1); BN_clear(x2); BN_clear(z1); BN_clear(z2); BN_clear(a); BN_clear(b); //free bignums BN_free(p); BN_free(a); BN_free(b); BN_free(z1); BN_free(z2); BN_free(y1); BN_free(y2); BN_free(x1); BN_free(x2); return 0; }
Source: https://habr.com/ru/post/332928/
All Articles