[PATCH 1/2] Add elliptic curve SM2 implementation.
Tianjia Zhang
tianjia.zhang at linux.alibaba.com
Mon Jan 20 04:42:24 CET 2020
* configure.ac (enabled_pubkey_ciphers): Add ecc-sm2.
* cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add ecc-sm2.c.
* cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist,
_gcry_pk_util_preparse_sigval): Add sm2 flags.
* cipher/ecc.c: Support ecc-sm2.
* cipher/ecc-common.h: Add declarations for ecc-sm2.
* cipher/ecc-sm2.c: New.
* src/cipher.h: Define PUBKEY_FLAG_SM2.
--
Signed-off-by: Tianjia Zhang <tianjia.zhang at linux.alibaba.com>
---
cipher/Makefile.am | 2 +-
cipher/ecc-common.h | 12 +
cipher/ecc-sm2.c | 566 +++++++++++++++++++++++++++++++++++++++++++
cipher/ecc.c | 53 +++-
cipher/pubkey-util.c | 7 +
configure.ac | 3 +-
src/cipher.h | 1 +
7 files changed, 630 insertions(+), 14 deletions(-)
create mode 100644 cipher/ecc-sm2.c
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 020a9616..10a5ab62 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -87,7 +87,7 @@ EXTRA_libcipher_la_SOURCES = \
dsa.c \
elgamal.c \
ecc.c ecc-curves.c ecc-misc.c ecc-common.h \
- ecc-ecdh.c ecc-ecdsa.c ecc-eddsa.c ecc-gost.c \
+ ecc-ecdh.c ecc-ecdsa.c ecc-eddsa.c ecc-gost.c ecc-sm2.c \
idea.c \
gost28147.c gost.h \
gostr3411-94.c \
diff --git a/cipher/ecc-common.h b/cipher/ecc-common.h
index 7fbc950a..b8b7c763 100644
--- a/cipher/ecc-common.h
+++ b/cipher/ecc-common.h
@@ -125,4 +125,16 @@ gpg_err_code_t _gcry_ecc_gost_verify (gcry_mpi_t input, mpi_ec_t ec,
gcry_mpi_t r, gcry_mpi_t s);
+/*-- ecc-sm2.c --*/
+gpg_err_code_t _gcry_ecc_sm2_encrypt (gcry_sexp_t *r_ciph,
+ gcry_mpi_t input, mpi_ec_t ec);
+gpg_err_code_t _gcry_ecc_sm2_decrypt (gcry_sexp_t *r_plain,
+ gcry_sexp_t data_list, mpi_ec_t ec);
+gpg_err_code_t _gcry_ecc_sm2_sign (gcry_mpi_t input, mpi_ec_t ec,
+ gcry_mpi_t r, gcry_mpi_t s,
+ int flags, int hashalgo);
+gpg_err_code_t _gcry_ecc_sm2_verify (gcry_mpi_t input, mpi_ec_t ec,
+ gcry_mpi_t r, gcry_mpi_t s);
+
+
#endif /*GCRY_ECC_COMMON_H*/
diff --git a/cipher/ecc-sm2.c b/cipher/ecc-sm2.c
new file mode 100644
index 00000000..a6341132
--- /dev/null
+++ b/cipher/ecc-sm2.c
@@ -0,0 +1,566 @@
+/* ecc-sm2.c - Elliptic Curve SM2 implementation
+ * Copyright (C) 2020 Tianjia Zhang
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "bithelp.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "context.h"
+#include "ec-context.h"
+#include "pubkey-internal.h"
+#include "ecc-common.h"
+
+#define MPI_NBYTES(m) ((mpi_get_nbits(m) + 7) / 8)
+
+
+/* Key derivation function from X9.63/SECG */
+static gpg_err_code_t
+kdf_x9_63 (int algo, const void *in, size_t inlen, void *out, size_t outlen)
+{
+ gpg_err_code_t rc;
+ gcry_md_hd_t hd;
+ int mdlen;
+ u32 counter = 1;
+ u32 counter_be;
+ unsigned char *dgst;
+ unsigned char *pout = out;
+ size_t rlen = outlen;
+ size_t len;
+
+ rc = _gcry_md_open (&hd, algo, 0);
+ if (rc)
+ return rc;
+
+ mdlen = _gcry_md_get_algo_dlen (algo);
+
+ while (rlen > 0)
+ {
+ counter_be = be_bswap32 (counter); /* cpu_to_be32 */
+ counter++;
+
+ _gcry_md_write (hd, in, inlen);
+ _gcry_md_write (hd, &counter_be, sizeof(counter_be));
+
+ dgst = _gcry_md_read (hd, algo);
+ if (dgst == NULL)
+ {
+ rc = GPG_ERR_DIGEST_ALGO;
+ break;
+ }
+
+ len = mdlen < rlen ? mdlen : rlen; /* min(mdlen, rlen) */
+ memcpy (pout, dgst, len);
+ rlen -= len;
+ pout += len;
+
+ _gcry_md_reset (hd);
+ }
+
+ _gcry_md_close (hd);
+ return rc;
+}
+
+
+/* _gcry_ecc_sm2_encrypt description:
+ * input:
+ * data[0] : octet string
+ * output: A new S-expression with the parameters:
+ * a: c1 : generated ephemeral public key (kG)
+ * b: c3 : Hash(x2 || IN || y2)
+ * c: c2 : cipher
+ *
+ * sm2_decrypt description:
+ * in contrast to encrypt
+ */
+gpg_err_code_t
+_gcry_ecc_sm2_encrypt (gcry_sexp_t *r_ciph, gcry_mpi_t input, mpi_ec_t ec)
+{
+ gpg_err_code_t rc;
+ const int algo = GCRY_MD_SM3;
+ gcry_md_hd_t md = NULL;
+ int mdlen;
+ unsigned char *dgst;
+ gcry_mpi_t k = NULL;
+ mpi_point_struct kG, kP;
+ gcry_mpi_t x1, y1;
+ gcry_mpi_t x2, y2;
+ gcry_mpi_t x2y2 = NULL;
+ unsigned char *in = NULL;
+ unsigned int inlen;
+ unsigned char *raw;
+ unsigned int rawlen;
+ unsigned char *cipher = NULL;
+ int i;
+
+ point_init (&kG);
+ point_init (&kP);
+ x1 = mpi_new (0);
+ y1 = mpi_new (0);
+ x2 = mpi_new (0);
+ y2 = mpi_new (0);
+
+ in = _gcry_mpi_get_buffer (input, 0, &inlen, NULL);
+ if (!in)
+ {
+ rc = gpg_err_code_from_syserror ();
+ goto leave;
+ }
+
+ cipher = xtrymalloc (inlen);
+ if (!cipher)
+ {
+ rc = gpg_err_code_from_syserror ();
+ goto leave;
+ }
+
+ /* rand k in [1, n-1] */
+ k = _gcry_dsa_gen_k (ec->n, GCRY_VERY_STRONG_RANDOM);
+
+ /* [k]G = (x1, y1) */
+ _gcry_mpi_ec_mul_point (&kG, k, ec->G, ec);
+ if (_gcry_mpi_ec_get_affine (x1, y1, &kG, ec))
+ {
+ if (DBG_CIPHER)
+ log_debug ("Bad check: kG can not be a Point at Infinity!\n");
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
+
+ /* [k]P = (x2, y2) */
+ _gcry_mpi_ec_mul_point (&kP, k, ec->Q, ec);
+ if (_gcry_mpi_ec_get_affine (x2, y2, &kP, ec))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
+
+ /* t = KDF(x2 || y2, klen) */
+ x2y2 = _gcry_mpi_ec_ec2os (&kP, ec);
+ raw = mpi_get_opaque (x2y2, &rawlen);
+ rawlen = (rawlen + 7) / 8;
+
+ /* skip the prefix '0x04' */
+ raw += 1;
+ rawlen -= 1;
+ rc = kdf_x9_63 (algo, raw, rawlen, cipher, inlen);
+ if (rc)
+ goto leave;
+
+ /* cipher = t xor in */
+ for (i = 0; i < inlen; i++)
+ cipher[i] ^= in[i];
+
+ /* hash(x2 || IN || y2) */
+ mdlen = _gcry_md_get_algo_dlen (algo);
+ rc = _gcry_md_open (&md, algo, 0);
+ if (rc)
+ goto leave;
+ _gcry_md_write (md, raw, MPI_NBYTES(x2));
+ _gcry_md_write (md, in, inlen);
+ _gcry_md_write (md, raw + MPI_NBYTES(x2), MPI_NBYTES(y2));
+ dgst = _gcry_md_read (md, algo);
+ if (dgst == NULL)
+ {
+ rc = GPG_ERR_DIGEST_ALGO;
+ goto leave;
+ }
+
+ if (!rc)
+ {
+ gcry_mpi_t c1;
+ gcry_mpi_t c3;
+ gcry_mpi_t c2;
+
+ c3 = mpi_new (0);
+ c2 = mpi_new (0);
+
+ c1 = _gcry_ecc_ec2os (x1, y1, ec->p);
+ _gcry_mpi_set_opaque_copy (c3, dgst, mdlen * 8);
+ _gcry_mpi_set_opaque_copy (c2, cipher, inlen * 8);
+
+ rc = sexp_build (r_ciph, NULL,
+ "(enc-val(flags sm2)(sm2(a%M)(b%M)(c%M)))",
+ c1, c3, c2);
+
+ mpi_free (c1);
+ mpi_free (c3);
+ mpi_free (c2);
+ }
+
+leave:
+ _gcry_md_close (md);
+ mpi_free (x2y2);
+ mpi_free (k);
+
+ point_free (&kG);
+ point_free (&kP);
+ mpi_free (x1);
+ mpi_free (y1);
+ mpi_free (x2);
+ mpi_free (y2);
+
+ xfree (cipher);
+ xfree (in);
+
+ return rc;
+}
+
+
+gpg_err_code_t
+_gcry_ecc_sm2_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t data_list, mpi_ec_t ec)
+{
+ gpg_err_code_t rc;
+ gcry_mpi_t data_c1 = NULL;
+ gcry_mpi_t data_c3 = NULL;
+ gcry_mpi_t data_c2 = NULL;
+
+ /*
+ * Extract the data.
+ */
+ rc = sexp_extract_param (data_list, NULL, "/a/b/c",
+ &data_c1, &data_c3, &data_c2, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ {
+ log_printmpi ("ecc_decrypt d_c1", data_c1);
+ log_printmpi ("ecc_decrypt d_c3", data_c3);
+ log_printmpi ("ecc_decrypt d_c2", data_c2);
+ }
+
+ {
+ const int algo = GCRY_MD_SM3;
+ gcry_md_hd_t md = NULL;
+ int mdlen;
+ unsigned char *dgst;
+ mpi_point_struct c1;
+ mpi_point_struct kP;
+ gcry_mpi_t x2, y2;
+ gcry_mpi_t x2y2 = NULL;
+ unsigned char *in = NULL;
+ unsigned int inlen;
+ unsigned char *plain = NULL;
+ unsigned char *raw;
+ unsigned int rawlen;
+ unsigned char *c3 = NULL;
+ unsigned int c3_len;
+ int i;
+
+ point_init (&c1);
+ point_init (&kP);
+ x2 = mpi_new (0);
+ y2 = mpi_new (0);
+
+ in = mpi_get_opaque (data_c2, &inlen);
+ inlen = (inlen + 7) / 8;
+ plain = xtrymalloc (inlen);
+ if (!plain)
+ {
+ rc = gpg_err_code_from_syserror ();
+ goto leave_main;
+ }
+
+ rc = _gcry_ecc_os2ec (&c1, data_c1);
+ if (rc)
+ goto leave_main;
+
+ if (!_gcry_mpi_ec_curve_point (&c1, ec))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave_main;
+ }
+
+ /* [d]C1 = (x2, y2), C1 = [k]G */
+ _gcry_mpi_ec_mul_point (&kP, ec->d, &c1, ec);
+ if (_gcry_mpi_ec_get_affine (x2, y2, &kP, ec))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave_main;
+ }
+
+ /* t = KDF(x2 || y2, inlen) */
+ x2y2 = _gcry_mpi_ec_ec2os (&kP, ec);
+ raw = mpi_get_opaque (x2y2, &rawlen);
+ rawlen = (rawlen + 7) / 8;
+ /* skip the prefix '0x04' */
+ raw += 1;
+ rawlen -= 1;
+ rc = kdf_x9_63 (algo, raw, rawlen, plain, inlen);
+ if (rc)
+ goto leave_main;
+
+ /* plain = C2 xor t */
+ for (i = 0; i < inlen; i++)
+ plain[i] ^= in[i];
+
+ /* Hash(x2 || IN || y2) == C3 */
+ mdlen = _gcry_md_get_algo_dlen (algo);
+ rc = _gcry_md_open (&md, algo, 0);
+ if (rc)
+ goto leave_main;
+ _gcry_md_write (md, raw, MPI_NBYTES(x2));
+ _gcry_md_write (md, plain, inlen);
+ _gcry_md_write (md, raw + MPI_NBYTES(x2), MPI_NBYTES(y2));
+ dgst = _gcry_md_read (md, algo);
+ if (dgst == NULL)
+ {
+ memset (plain, 0, inlen);
+ rc = GPG_ERR_DIGEST_ALGO;
+ goto leave_main;
+ }
+ c3 = mpi_get_opaque (data_c3, &c3_len);
+ c3_len = (c3_len + 7) / 8;
+ if (c3_len != mdlen || memcmp (dgst, c3, c3_len) != 0)
+ {
+ memset (plain, 0, inlen);
+ rc = GPG_ERR_INV_DATA;
+ goto leave_main;
+ }
+
+ if (!rc)
+ {
+ gcry_mpi_t r;
+
+ r = mpi_new (inlen * 8);
+ _gcry_mpi_set_buffer (r, plain, inlen, 0);
+
+ rc = sexp_build (r_plain, NULL, "(value %m)", r);
+
+ mpi_free (r);
+ }
+
+ leave_main:
+ _gcry_md_close (md);
+ mpi_free (x2y2);
+ xfree (plain);
+
+ point_free (&c1);
+ point_free (&kP);
+ mpi_free (x2);
+ mpi_free (y2);
+ }
+
+ leave:
+ _gcry_mpi_release (data_c1);
+ _gcry_mpi_release (data_c3);
+ _gcry_mpi_release (data_c2);
+
+ return rc;
+}
+
+
+/* Compute an SM2 signature.
+ * Return the signature struct (r,s) from the message hash. The caller
+ * must have allocated R and S.
+ */
+gpg_err_code_t
+_gcry_ecc_sm2_sign (gcry_mpi_t input, mpi_ec_t ec,
+ gcry_mpi_t r, gcry_mpi_t s,
+ int flags, int hashalgo)
+{
+ gpg_err_code_t rc = 0;
+ int extraloops = 0;
+ gcry_mpi_t hash;
+ const void *abuf;
+ unsigned int abits, qbits;
+ gcry_mpi_t tmp = NULL;
+ gcry_mpi_t k = NULL;
+ gcry_mpi_t rk = NULL;
+ mpi_point_struct kG;
+ gcry_mpi_t x1;
+
+ if (DBG_CIPHER)
+ log_mpidump ("sm2 sign hash ", input);
+
+ qbits = mpi_get_nbits (ec->n);
+
+ /* Convert the INPUT into an MPI if needed. */
+ rc = _gcry_dsa_normalize_hash (input, &hash, qbits);
+ if (rc)
+ return rc;
+
+ point_init (&kG);
+ x1 = mpi_new (0);
+ rk = mpi_new (0);
+ tmp = mpi_new (0);
+
+ for (;;)
+ {
+ /* rand k in [1, n-1] */
+ if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo)
+ {
+ /* Use Pornin's method for deterministic DSA. If this
+ flag is set, it is expected that HASH is an opaque
+ MPI with the to be signed hash. That hash is also
+ used as h1 from 3.2.a. */
+ if (!mpi_is_opaque (input))
+ {
+ rc = GPG_ERR_CONFLICT;
+ goto leave;
+ }
+
+ abuf = mpi_get_opaque (input, &abits);
+ rc = _gcry_dsa_gen_rfc6979_k (&k, ec->n, ec->d,
+ abuf, (abits+7)/8,
+ hashalgo, extraloops);
+ if (rc)
+ goto leave;
+ extraloops++;
+ }
+ else
+ k = _gcry_dsa_gen_k (ec->n, GCRY_VERY_STRONG_RANDOM);
+
+ _gcry_dsa_modify_k (k, ec->n, qbits);
+
+ /* [k]G = (x1, y1) */
+ _gcry_mpi_ec_mul_point (&kG, k, ec->G, ec);
+ if (_gcry_mpi_ec_get_affine (x1, NULL, &kG, ec))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
+
+ /* r = (e + x1) % n */
+ mpi_addm (r, hash, x1, ec->n);
+
+ /* r != 0 && r + k != n */
+ if (mpi_cmp_ui (r, 0) == 0)
+ continue;
+ mpi_add (rk, r, k);
+ if (mpi_cmp (rk, ec->n) == 0)
+ continue;
+
+ /* s = ((d + 1)^-1 * (k - rd)) % n */
+ mpi_addm (s, ec->d, GCRYMPI_CONST_ONE, ec->n);
+ mpi_invm (s, s, ec->n);
+ mpi_mulm (tmp, r, ec->d, ec->n);
+ mpi_subm (tmp, k, tmp, ec->n);
+ mpi_mulm (s, s, tmp, ec->n);
+
+ /* s != 0 */
+ if (mpi_cmp_ui (s, 0) == 0)
+ continue;
+
+ break; /* Okay */
+ }
+
+ if (DBG_CIPHER)
+ {
+ log_mpidump ("sm2 sign result r ", r);
+ log_mpidump ("sm2 sign result s ", s);
+ }
+
+leave:
+ point_free (&kG);
+ mpi_free (k);
+ mpi_free (x1);
+ mpi_free (rk);
+ mpi_free (tmp);
+
+ if (hash != input)
+ mpi_free (hash);
+
+ return rc;
+}
+
+
+/* Verify an SM2 signature.
+ * Check if R and S verifies INPUT.
+ */
+gpg_err_code_t
+_gcry_ecc_sm2_verify (gcry_mpi_t input, mpi_ec_t ec,
+ gcry_mpi_t r, gcry_mpi_t s)
+{
+ gpg_err_code_t err = 0;
+ gcry_mpi_t hash = NULL;
+ gcry_mpi_t t = NULL;
+ mpi_point_struct sG, tP;
+ gcry_mpi_t x1, y1;
+ unsigned int nbits;
+
+ /* r, s within [1, n-1] */
+ if (mpi_cmp_ui (r, 1) < 0 || mpi_cmp (r, ec->n) > 0)
+ return GPG_ERR_BAD_SIGNATURE;
+ if (mpi_cmp_ui (s, 1) < 0 || mpi_cmp (s, ec->n) > 0)
+ return GPG_ERR_BAD_SIGNATURE;
+
+ nbits = mpi_get_nbits (ec->n);
+ err = _gcry_dsa_normalize_hash (input, &hash, nbits);
+ if (err)
+ return err;
+
+ point_init (&sG);
+ point_init (&tP);
+ x1 = mpi_new (0);
+ y1 = mpi_new (0);
+ t = mpi_new (0);
+
+ /* t = (r + s) % n, t != 0 */
+ mpi_addm (t, r, s, ec->n);
+ if (mpi_cmp_ui (t, 0) == 0)
+ {
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+
+ /* sG + tP = (x1, y1) */
+ _gcry_mpi_ec_mul_point (&sG, s, ec->G, ec);
+ _gcry_mpi_ec_mul_point (&tP, t, ec->Q, ec);
+ _gcry_mpi_ec_add_points (&sG, &sG, &tP, ec);
+ if (_gcry_mpi_ec_get_affine (x1, y1, &sG, ec))
+ {
+ err = GPG_ERR_INV_DATA;
+ goto leave;
+ }
+
+ /* R = (e + x1) % n */
+ mpi_addm (t, hash, x1, ec->n);
+
+ /* check R == r */
+ if (mpi_cmp (t, r))
+ {
+ if (DBG_CIPHER)
+ {
+ log_mpidump (" R", t);
+ log_mpidump (" r", r);
+ log_mpidump (" s", s);
+ }
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+ if (DBG_CIPHER)
+ log_debug ("sm2 verify: Accepted\n");
+
+ leave:
+ point_free (&sG);
+ point_free (&tP);
+ mpi_free (x1);
+ mpi_free (y1);
+ mpi_free (t);
+ if (hash != input)
+ mpi_free (hash);
+
+ return err;
+}
diff --git a/cipher/ecc.c b/cipher/ecc.c
index 1195f5ec..49c2c0f6 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -69,6 +69,7 @@ static const char *ecc_names[] =
"ecdh",
"eddsa",
"gost",
+ "sm2",
NULL,
};
@@ -723,6 +724,14 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
rc = sexp_build (r_sig, NULL,
"(sig-val(gost(r%M)(s%M)))", sig_r, sig_s);
}
+ else if ((ctx.flags & PUBKEY_FLAG_SM2))
+ {
+ rc = _gcry_ecc_sm2_sign (data, ec, sig_r, sig_s,
+ ctx.flags, ctx.hash_algo);
+ if (!rc)
+ rc = sexp_build (r_sig, NULL,
+ "(sig-val(sm2(r%M)(s%M)))", sig_r, sig_s);
+ }
else
{
rc = _gcry_ecc_ecdsa_sign (data, ec, sig_r, sig_s,
@@ -811,6 +820,10 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
{
rc = _gcry_ecc_gost_verify (data, ec, sig_r, sig_s);
}
+ else if ((sigflags & PUBKEY_FLAG_SM2))
+ {
+ rc = _gcry_ecc_sm2_verify (data, ec, sig_r, sig_s);
+ }
else
{
rc = _gcry_ecc_ecdsa_verify (data, ec, sig_r, sig_s);
@@ -918,6 +931,13 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
goto leave;
}
+ if ((ctx.flags & PUBKEY_FLAG_SM2))
+ {
+ /* All encryption will be done, return it. */
+ rc = _gcry_ecc_sm2_encrypt (r_ciph, data, ec);
+ goto leave;
+ }
+
/* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */
{
mpi_point_struct R; /* Result that we return. */
@@ -1041,18 +1061,6 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
(nbits = ecc_get_nbits (keyparms)));
- /*
- * Extract the data.
- */
- rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx);
- if (rc)
- goto leave;
- rc = sexp_extract_param (l1, NULL, "/e", &data_e, NULL);
- if (rc)
- goto leave;
- if (DBG_CIPHER)
- log_printmpi ("ecc_decrypt d_e", data_e);
-
/*
* Extract the key.
*/
@@ -1066,6 +1074,27 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
goto leave;
}
+ /*
+ * Extract the data.
+ */
+ rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx);
+ if (rc)
+ goto leave;
+ if ((ctx.flags & PUBKEY_FLAG_SM2))
+ {
+ /* All decryption will be done, return it. */
+ rc = _gcry_ecc_sm2_decrypt (r_plain, l1, ec);
+ goto leave;
+ }
+ else
+ {
+ rc = sexp_extract_param (l1, NULL, "/e", &data_e, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printmpi ("ecc_decrypt d_e", data_e);
+ }
+
if (ec->dialect == ECC_DIALECT_SAFECURVE || (flags & PUBKEY_FLAG_DJB_TWEAK))
enable_specific_point_validation = 1;
else
diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
index 4a6bf462..c52185de 100644
--- a/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -81,6 +81,11 @@ _gcry_pk_util_parse_flaglist (gcry_sexp_t list,
encoding = PUBKEY_ENC_RAW;
flags |= PUBKEY_FLAG_RAW_FLAG; /* Explicitly given. */
}
+ else if (!memcmp (s, "sm2", 3))
+ {
+ encoding = PUBKEY_ENC_RAW;
+ flags |= PUBKEY_FLAG_SM2 | PUBKEY_FLAG_RAW_FLAG;
+ }
else if (!igninvflag)
rc = GPG_ERR_INV_FLAG;
break;
@@ -429,6 +434,8 @@ _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names,
*r_eccflags = PUBKEY_FLAG_EDDSA;
if (!strcmp (name, "gost"))
*r_eccflags = PUBKEY_FLAG_GOST;
+ if (!strcmp (name, "sm2"))
+ *r_eccflags = PUBKEY_FLAG_SM2;
}
*r_parms = l2;
diff --git a/configure.ac b/configure.ac
index 4d4fb49a..e45452ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2546,7 +2546,8 @@ LIST_MEMBER(ecc, $enabled_pubkey_ciphers)
if test "$found" = "1" ; then
GCRYPT_PUBKEY_CIPHERS="$GCRYPT_PUBKEY_CIPHERS \
ecc.lo ecc-curves.lo ecc-misc.lo \
- ecc-ecdh.lo ecc-ecdsa.lo ecc-eddsa.lo ecc-gost.lo"
+ ecc-ecdh.lo ecc-ecdsa.lo ecc-eddsa.lo ecc-gost.lo \
+ ecc-sm2.lo"
AC_DEFINE(USE_ECC, 1, [Defined if this module should be included])
fi
diff --git a/src/cipher.h b/src/cipher.h
index 5aac19f1..1fe50890 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -42,6 +42,7 @@
#define PUBKEY_FLAG_GOST (1 << 13)
#define PUBKEY_FLAG_NO_KEYTEST (1 << 14)
#define PUBKEY_FLAG_DJB_TWEAK (1 << 15)
+#define PUBKEY_FLAG_SM2 (1 << 16)
enum pk_operation
--
2.17.1
More information about the Gcrypt-devel
mailing list