395 lines
9.3 KiB
C++
395 lines
9.3 KiB
C++
/*
|
|
* Copyright (c) 2012-2020 MIRACL UK Ltd.
|
|
*
|
|
* This file is part of MIRACL Core
|
|
* (see https://github.com/miracl/core).
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/* ECDH/ECIES/ECDSA API Functions */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
#include "ecdh_ZZZ.h"
|
|
|
|
using namespace XXX;
|
|
using namespace YYY;
|
|
|
|
#if CURVETYPE_ZZZ!=WEIERSTRASS
|
|
// Process a random BIG r by RFC7748 (for Montgomery & Edwards curves only)
|
|
static void RFC7748(BIG r)
|
|
{
|
|
int c,lg=0;
|
|
BIG t;
|
|
c=ZZZ::CURVE_Cof_I;
|
|
while (c!=1)
|
|
{
|
|
lg++;
|
|
c/=2;
|
|
}
|
|
int n=8*EGS_ZZZ-lg+1;
|
|
BIG_mod2m(r,n);
|
|
BIG_zero(t); BIG_inc(t,1); BIG_shl(t,n);
|
|
BIG_add(r,r,t);
|
|
c=BIG_lastbits(r,lg);
|
|
BIG_dec(r,c);
|
|
// printf("lg= %d n=%d\n",lg,n);
|
|
}
|
|
#endif
|
|
|
|
/* return 1 if S is in ranger 0 < S < order , else return 0 */
|
|
int ZZZ::ECP_IN_RANGE(octet* S)
|
|
{
|
|
BIG r,s;
|
|
BIG_rcopy(r, CURVE_Order);
|
|
BIG_fromBytes(s,S->val);
|
|
if (BIG_iszilch(s)) return 0;
|
|
if (BIG_comp(s,r)>=0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
/* Calculate a public/private EC GF(p) key pair. W=S.G mod EC(p),
|
|
* where S is the secret key and W is the public key
|
|
* and G is fixed generator.
|
|
* If RNG is NULL then the private key is provided externally in S
|
|
* otherwise it is generated randomly internally */
|
|
int ZZZ::ECP_KEY_PAIR_GENERATE(csprng *RNG, octet* S, octet *W)
|
|
{
|
|
BIG r, gx, gy, s;
|
|
ECP G;
|
|
int res = 0;
|
|
|
|
ECP_generator(&G);
|
|
BIG_rcopy(r, CURVE_Order);
|
|
|
|
if (RNG != NULL)
|
|
{
|
|
#if CURVETYPE_ZZZ!=WEIERSTRASS
|
|
BIG_random(s,RNG); // from random bytes
|
|
#else
|
|
BIG_randomnum(s, r, RNG); // Removes biases
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
BIG_fromBytes(s, S->val);
|
|
}
|
|
|
|
#if CURVETYPE_ZZZ!=WEIERSTRASS
|
|
RFC7748(s); // For Montgomery or Edwards, apply RFC7748 transformation
|
|
#endif
|
|
S->len = EGS_ZZZ;
|
|
BIG_toBytes(S->val, s);
|
|
|
|
ECP_clmul(&G, s, r);
|
|
ECP_toOctet(W, &G, false); // To use point compression on public keys, change to true
|
|
|
|
return res;
|
|
}
|
|
|
|
/* Validate public key */
|
|
int ZZZ::ECP_PUBLIC_KEY_VALIDATE(octet *W)
|
|
{
|
|
BIG q, r, wx, k;
|
|
ECP WP;
|
|
int valid, nb;
|
|
int res = 0;
|
|
|
|
BIG_rcopy(q, Modulus);
|
|
BIG_rcopy(r, CURVE_Order);
|
|
|
|
valid = ECP_fromOctet(&WP, W);
|
|
if (!valid) res = ECDH_INVALID_PUBLIC_KEY;
|
|
|
|
if (res == 0)
|
|
{
|
|
|
|
nb = BIG_nbits(q);
|
|
BIG_one(k);
|
|
BIG_shl(k, (nb + 4) / 2);
|
|
BIG_add(k, q, k);
|
|
BIG_sdiv(k, r); /* get co-factor */
|
|
while (BIG_parity(k) == 0)
|
|
{
|
|
ECP_dbl(&WP);
|
|
BIG_fshr(k, 1);
|
|
}
|
|
|
|
if (!BIG_isunity(k)) ECP_mul(&WP, k);
|
|
if (ECP_isinf(&WP)) res = ECDH_INVALID_PUBLIC_KEY;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */
|
|
// type = 0 is just x coordinate output
|
|
// type = 1 for standard compressed output
|
|
// type = 2 for standard uncompress output 04|x|y
|
|
int ZZZ::ECP_SVDP_DH(octet *S, octet *WD, octet *Z,int type)
|
|
{
|
|
BIG r, s, wx;
|
|
int valid;
|
|
ECP W;
|
|
int res = 0;
|
|
|
|
BIG_fromBytes(s, S->val);
|
|
valid = ECP_fromOctet(&W, WD);
|
|
|
|
if (!valid) res = ECDH_ERROR;
|
|
if (res == 0)
|
|
{
|
|
BIG_rcopy(r, CURVE_Order);
|
|
ECP_clmul(&W, s, r);
|
|
if (ECP_isinf(&W)) res = ECDH_ERROR;
|
|
else
|
|
{
|
|
#if CURVETYPE_ZZZ!=MONTGOMERY
|
|
if (type>0)
|
|
{
|
|
if (type==1) ECP_toOctet(Z,&W,true);
|
|
else ECP_toOctet(Z,&W,false);
|
|
return res;
|
|
}
|
|
else
|
|
ECP_get(wx, wx, &W);
|
|
#else
|
|
ECP_get(wx, &W);
|
|
#endif
|
|
}
|
|
Z->len = EFS_ZZZ;
|
|
BIG_toBytes(Z->val, wx);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
#if CURVETYPE_ZZZ!=MONTGOMERY
|
|
|
|
/* IEEE ECDSA Signature, C and D are signature on F using private key S */
|
|
int ZZZ::ECP_SP_DSA(int hlen, csprng *RNG, octet *K, octet *S, octet *F, octet *C, octet *D)
|
|
{
|
|
char h[128];
|
|
octet H = {0, sizeof(h), h};
|
|
|
|
BIG r, s, f, c, d, u, vx, w;
|
|
ECP G, V;
|
|
|
|
SPhash(MC_SHA2, hlen, &H, F);
|
|
|
|
ECP_generator(&G);
|
|
BIG_rcopy(r, CURVE_Order);
|
|
|
|
BIG_fromBytes(s, S->val);
|
|
|
|
int blen = H.len;
|
|
if (H.len > EGS_ZZZ) blen = EGS_ZZZ;
|
|
BIG_fromBytesLen(f, H.val, blen);
|
|
|
|
if (RNG != NULL)
|
|
{
|
|
do
|
|
{
|
|
BIG_randomnum(u, r, RNG);
|
|
BIG_randomnum(w, r, RNG); /* IMPORTANT - side channel masking to protect invmodp() */
|
|
|
|
ECP_copy(&V, &G);
|
|
ECP_clmul(&V, u, r);
|
|
|
|
ECP_get(vx, vx, &V);
|
|
|
|
BIG_copy(c, vx);
|
|
BIG_mod(c, r);
|
|
if (BIG_iszilch(c)) continue;
|
|
|
|
BIG_modmul(u, u, w, r);
|
|
|
|
BIG_invmodp(u, u, r);
|
|
BIG_modmul(d, s, c, r);
|
|
|
|
BIG_modadd(d, f, d, r);
|
|
BIG_modmul(d, d, w, r);
|
|
BIG_modmul(d, u, d, r);
|
|
|
|
}
|
|
while (BIG_iszilch(d));
|
|
}
|
|
else
|
|
{
|
|
BIG_fromBytes(u, K->val);
|
|
|
|
ECP_copy(&V, &G);
|
|
ECP_clmul(&V, u, r);
|
|
|
|
ECP_get(vx, vx, &V);
|
|
|
|
BIG_copy(c, vx);
|
|
BIG_mod(c, r);
|
|
if (BIG_iszilch(c)) return ECDH_ERROR;
|
|
|
|
BIG_invmodp(u, u, r);
|
|
BIG_modmul(d, s, c, r);
|
|
|
|
BIG_modadd(d, f, d, r);
|
|
BIG_modmul(d, u, d, r);
|
|
if (BIG_iszilch(d)) return ECDH_ERROR;
|
|
}
|
|
|
|
C->len = D->len = EGS_ZZZ;
|
|
|
|
BIG_toBytes(C->val, c);
|
|
BIG_toBytes(D->val, d);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */
|
|
int ZZZ::ECP_VP_DSA(int hlen, octet *W, octet *F, octet *C, octet *D)
|
|
{
|
|
char h[128];
|
|
octet H = {0, sizeof(h), h};
|
|
|
|
BIG r, wx, wy, f, c, d, h2;
|
|
int res = 0;
|
|
ECP G, WP;
|
|
int valid;
|
|
|
|
SPhash(MC_SHA2, hlen, &H, F);
|
|
|
|
ECP_generator(&G);
|
|
BIG_rcopy(r, CURVE_Order);
|
|
|
|
BIG_fromBytes(c, C->val);
|
|
BIG_fromBytes(d, D->val);
|
|
|
|
int blen = H.len;
|
|
if (blen > EGS_ZZZ) blen = EGS_ZZZ;
|
|
|
|
BIG_fromBytesLen(f, H.val, blen);
|
|
|
|
if (BIG_iszilch(c) || BIG_comp(c, r) >= 0 || BIG_iszilch(d) || BIG_comp(d, r) >= 0)
|
|
res = ECDH_ERROR;
|
|
|
|
if (res == 0)
|
|
{
|
|
BIG_invmodp(d, d, r);
|
|
BIG_modmul(f, f, d, r);
|
|
BIG_modmul(h2, c, d, r);
|
|
|
|
valid = ECP_fromOctet(&WP, W);
|
|
if (!valid) res = ECDH_ERROR;
|
|
else
|
|
{
|
|
ECP_mul2(&WP, &G, h2, f);
|
|
if (ECP_isinf(&WP)) res = ECDH_ERROR;
|
|
else
|
|
{
|
|
ECP_get(d, d, &WP);
|
|
BIG_mod(d, r);
|
|
if (BIG_comp(d, c) != 0) res = ECDH_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and produces ciphertext V,C,T */
|
|
void ZZZ::ECP_ECIES_ENCRYPT(int hlen, octet *P1, octet *P2, csprng *RNG, octet *W, octet *M, int tlen, octet *V, octet *C, octet *T)
|
|
{
|
|
|
|
int i, len;
|
|
char z[EFS_ZZZ], vz[3 * EFS_ZZZ + 1], k[2 * AESKEY_ZZZ], k1[AESKEY_ZZZ], k2[AESKEY_ZZZ], l2[8], u[EFS_ZZZ];
|
|
octet Z = {0, sizeof(z), z};
|
|
octet VZ = {0, sizeof(vz), vz};
|
|
octet K = {0, sizeof(k), k};
|
|
octet K1 = {0, sizeof(k1), k1};
|
|
octet K2 = {0, sizeof(k2), k2};
|
|
octet L2 = {0, sizeof(l2), l2};
|
|
octet U = {0, sizeof(u), u};
|
|
|
|
if (ECP_KEY_PAIR_GENERATE(RNG, &U, V) != 0) return;
|
|
if (ECP_SVDP_DH(&U, W, &Z,0) != 0) return;
|
|
|
|
OCT_copy(&VZ, V);
|
|
OCT_joctet(&VZ, &Z);
|
|
|
|
KDF2(MC_SHA2, hlen, &K, 2 * AESKEY_ZZZ, &VZ, P1);
|
|
|
|
K1.len = K2.len = AESKEY_ZZZ;
|
|
for (i = 0; i < AESKEY_ZZZ; i++)
|
|
{
|
|
K1.val[i] = K.val[i];
|
|
K2.val[i] = K.val[AESKEY_ZZZ + i];
|
|
}
|
|
|
|
AES_CBC_IV0_ENCRYPT(&K1, M, C);
|
|
|
|
OCT_jint(&L2, P2->len, 8);
|
|
|
|
len = C->len;
|
|
OCT_joctet(C, P2);
|
|
OCT_joctet(C, &L2);
|
|
HMAC(MC_SHA2, hlen, T, tlen, &K2, C);
|
|
C->len = len;
|
|
}
|
|
|
|
/* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */
|
|
int ZZZ::ECP_ECIES_DECRYPT(int hlen, octet *P1, octet *P2, octet *V, octet *C, octet *T, octet *U, octet *M)
|
|
{
|
|
|
|
int i, len;
|
|
char z[EFS_ZZZ], vz[3 * EFS_ZZZ + 1], k[2 * AESKEY_ZZZ], k1[AESKEY_ZZZ], k2[AESKEY_ZZZ], l2[8], tag[32];
|
|
octet Z = {0, sizeof(z), z};
|
|
octet VZ = {0, sizeof(vz), vz};
|
|
octet K = {0, sizeof(k), k};
|
|
octet K1 = {0, sizeof(k1), k1};
|
|
octet K2 = {0, sizeof(k2), k2};
|
|
octet L2 = {0, sizeof(l2), l2};
|
|
octet TAG = {0, sizeof(tag), tag};
|
|
|
|
if (ECP_SVDP_DH(U, V, &Z,0) != 0) return 0;
|
|
|
|
OCT_copy(&VZ, V);
|
|
OCT_joctet(&VZ, &Z);
|
|
|
|
KDF2(MC_SHA2, hlen, &K, 2 * AESKEY_ZZZ, &VZ, P1);
|
|
|
|
K1.len = K2.len = AESKEY_ZZZ;
|
|
for (i = 0; i < AESKEY_ZZZ; i++)
|
|
{
|
|
K1.val[i] = K.val[i];
|
|
K2.val[i] = K.val[AESKEY_ZZZ + i];
|
|
}
|
|
|
|
if (!AES_CBC_IV0_DECRYPT(&K1, C, M)) return 0;
|
|
|
|
OCT_jint(&L2, P2->len, 8);
|
|
|
|
len = C->len;
|
|
OCT_joctet(C, P2);
|
|
OCT_joctet(C, &L2);
|
|
HMAC(MC_SHA2, hlen, &TAG, T->len, &K2, C);
|
|
C->len = len;
|
|
|
|
if (!OCT_ncomp(T, &TAG, T->len)) return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|