[ ] Elliptic curve Menezes-Vanstone cryptosystem OpenSSL API |
//
// 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 MENEZESVANSTONE 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
#include
#include
//#include
#include rand.h>
#define OPENSSL_NO_EC2M
#include 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;
}