<div dir="ltr">this patch has been test in my env, it look okay for me.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jul 9, 2020 at 4:42 PM Tianjia Zhang <<a href="mailto:tianjia.zhang@linux.alibaba.com">tianjia.zhang@linux.alibaba.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This new module implement the SM2 public key algorithm. It was<br>
published by State Encryption Management Bureau, China.<br>
List of specifications for SM2 elliptic curve public key cryptography:<br>
<br>
* GM/T 0003.1-2012<br>
* GM/T 0003.2-2012<br>
* GM/T 0003.3-2012<br>
* GM/T 0003.4-2012<br>
* GM/T 0003.5-2012<br>
<br>
IETF: <a href="https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02" rel="noreferrer" target="_blank">https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02</a><br>
oscca: <a href="http://www.oscca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml" rel="noreferrer" target="_blank">http://www.oscca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml</a><br>
scctc: <a href="http://www.gmbz.org.cn/main/bzlb.html" rel="noreferrer" target="_blank">http://www.gmbz.org.cn/main/bzlb.html</a><br>
<br>
Signed-off-by: Tianjia Zhang <<a href="mailto:tianjia.zhang@linux.alibaba.com" target="_blank">tianjia.zhang@linux.alibaba.com</a>><br>
---<br>
 crypto/Kconfig           |  17 ++<br>
 crypto/Makefile          |   8 +<br>
 crypto/sm2.c             | 473 +++++++++++++++++++++++++++++++++++++++<br>
 crypto/sm2signature.asn1 |   4 +<br>
 include/crypto/sm2.h     |  25 +++<br>
 5 files changed, 527 insertions(+)<br>
 create mode 100644 crypto/sm2.c<br>
 create mode 100644 crypto/sm2signature.asn1<br>
 create mode 100644 include/crypto/sm2.h<br>
<br>
diff --git a/crypto/Kconfig b/crypto/Kconfig<br>
index 091c0a0bbf26..de330d658758 100644<br>
--- a/crypto/Kconfig<br>
+++ b/crypto/Kconfig<br>
@@ -260,6 +260,23 @@ config CRYPTO_ECRDSA<br>
          standard algorithms (called GOST algorithms). Only signature verification<br>
          is implemented.<br>
<br>
+config CRYPTO_SM2<br>
+       tristate "SM2 algorithm"<br>
+       select CRYPTO_SM3<br>
+       select CRYPTO_AKCIPHER<br>
+       select CRYPTO_MANAGER<br>
+       select MPILIB<br>
+       select ASN1<br>
+       help<br>
+         Generic implementation of the SM2 public key algorithm. It was<br>
+         published by State Encryption Management Bureau, China.<br>
+         as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012.<br>
+<br>
+         References:<br>
+         <a href="https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02" rel="noreferrer" target="_blank">https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02</a><br>
+         <a href="http://www.oscca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml" rel="noreferrer" target="_blank">http://www.oscca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml</a><br>
+         <a href="http://www.gmbz.org.cn/main/bzlb.html" rel="noreferrer" target="_blank">http://www.gmbz.org.cn/main/bzlb.html</a><br>
+<br>
 config CRYPTO_CURVE25519<br>
        tristate "Curve25519 algorithm"<br>
        select CRYPTO_KPP<br>
diff --git a/crypto/Makefile b/crypto/Makefile<br>
index 4ca12b6044f7..b279483fba50 100644<br>
--- a/crypto/Makefile<br>
+++ b/crypto/Makefile<br>
@@ -42,6 +42,14 @@ rsa_generic-y += rsa_helper.o<br>
 rsa_generic-y += rsa-pkcs1pad.o<br>
 obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o<br>
<br>
+$(obj)/sm2signature.asn1.o: $(obj)/sm2signature.asn1.c $(obj)/sm2signature.asn1.h<br>
+$(obj)/sm2.o: $(obj)/sm2signature.asn1.h<br>
+<br>
+sm2_generic-y += sm2signature.asn1.o<br>
+sm2_generic-y += sm2.o<br>
+<br>
+obj-$(CONFIG_CRYPTO_SM2) += sm2_generic.o<br>
+<br>
 crypto_acompress-y := acompress.o<br>
 crypto_acompress-y += scompress.o<br>
 obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o<br>
diff --git a/crypto/sm2.c b/crypto/sm2.c<br>
new file mode 100644<br>
index 000000000000..86da175bcda6<br>
--- /dev/null<br>
+++ b/crypto/sm2.c<br>
@@ -0,0 +1,473 @@<br>
+/* SPDX-License-Identifier: GPL-2.0-or-later */<br>
+/*<br>
+ * SM2 asymmetric public-key algorithm<br>
+ * as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012 SM2 and<br>
+ * described at <a href="https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02" rel="noreferrer" target="_blank">https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02</a><br>
+ *<br>
+ * Copyright (c) 2020, Alibaba Group.<br>
+ * Authors: Tianjia Zhang <<a href="mailto:tianjia.zhang@linux.alibaba.com" target="_blank">tianjia.zhang@linux.alibaba.com</a>><br>
+ */<br>
+<br>
+#include <linux/module.h><br>
+#include <linux/mpi.h><br>
+#include <crypto/internal/akcipher.h><br>
+#include <crypto/akcipher.h><br>
+#include <crypto/hash.h><br>
+#include <crypto/sm3_base.h><br>
+#include <crypto/rng.h><br>
+#include <crypto/sm2.h><br>
+#include "sm2signature.asn1.h"<br>
+<br>
+#define MPI_NBYTES(m)   ((mpi_get_nbits(m) + 7) / 8)<br>
+<br>
+struct ecc_domain_parms {<br>
+       const char *desc;           /* Description of the curve.  */<br>
+       unsigned int nbits;         /* Number of bits.  */<br>
+       unsigned int fips:1; /* True if this is a FIPS140-2 approved curve */<br>
+<br>
+       /* The model describing this curve.  This is mainly used to select<br>
+        * the group equation.<br>
+        */<br>
+       enum gcry_mpi_ec_models model;<br>
+<br>
+       /* The actual ECC dialect used.  This is used for curve specific<br>
+        * optimizations and to select encodings etc.<br>
+        */<br>
+       enum ecc_dialects dialect;<br>
+<br>
+       const char *p;              /* The prime defining the field.  */<br>
+       const char *a, *b;          /* The coefficients.  For Twisted Edwards<br>
+                                    * Curves b is used for d.  For Montgomery<br>
+                                    * Curves (a,b) has ((A-2)/4,B^-1).<br>
+                                    */<br>
+       const char *n;              /* The order of the base point.  */<br>
+       const char *g_x, *g_y;      /* Base point.  */<br>
+       unsigned int h;             /* Cofactor.  */<br>
+};<br>
+<br>
+static const struct ecc_domain_parms sm2_ecp = {<br>
+       .desc = "sm2p256v1",<br>
+       .nbits = 256,<br>
+       .fips = 0,<br>
+       .model = MPI_EC_WEIERSTRASS,<br>
+       .dialect = ECC_DIALECT_STANDARD,<br>
+       .p   = "0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff",<br>
+       .a   = "0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc",<br>
+       .b   = "0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93",<br>
+       .n   = "0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123",<br>
+       .g_x = "0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7",<br>
+       .g_y = "0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0",<br>
+       .h = 1<br>
+};<br>
+<br>
+static int sm2_ec_ctx_init(struct mpi_ec_ctx *ec)<br>
+{<br>
+       const struct ecc_domain_parms *ecp = &sm2_ecp;<br>
+       MPI p, a, b;<br>
+       MPI x, y;<br>
+       int rc = -EINVAL;<br>
+<br>
+       p = mpi_scanval(ecp->p);<br>
+       a = mpi_scanval(ecp->a);<br>
+       b = mpi_scanval(ecp->b);<br>
+       if (!p || !a || !b)<br>
+               goto free_p;<br>
+<br>
+       x = mpi_scanval(ecp->g_x);<br>
+       y = mpi_scanval(ecp->g_y);<br>
+       if (!x || !y)<br>
+               goto free;<br>
+<br>
+       /* mpi_ec_setup_elliptic_curve */<br>
+       ec->G = mpi_point_new(0);<br>
+       if (!ec->G)<br>
+               goto free;<br>
+<br>
+       mpi_set(ec->G->x, x);<br>
+       mpi_set(ec->G->y, y);<br>
+       mpi_set_ui(ec->G->z, 1);<br>
+<br>
+       ec->n = mpi_scanval(ecp->n);<br>
+       if (!ec->n) {<br>
+               mpi_point_release(ec->G);<br>
+               goto free;<br>
+       }<br>
+<br>
+       ec->h = ecp->h;<br>
+       ec->name = ecp->desc;<br>
+       mpi_ec_init(ec, ecp->model, ecp->dialect, 0, p, a, b);<br>
+<br>
+       rc = 0;<br>
+<br>
+free:<br>
+       mpi_free(x);<br>
+       mpi_free(y);<br>
+free_p:<br>
+       mpi_free(p);<br>
+       mpi_free(a);<br>
+       mpi_free(b);<br>
+<br>
+       return rc;<br>
+}<br>
+<br>
+static void sm2_ec_ctx_deinit(struct mpi_ec_ctx *ec)<br>
+{<br>
+       mpi_free(ec->n);<br>
+       mpi_point_release(ec->G);<br>
+<br>
+       mpi_ec_deinit(ec);<br>
+<br>
+       memset(ec, 0, sizeof(*ec));<br>
+}<br>
+<br>
+static int sm2_ec_ctx_reset(struct mpi_ec_ctx *ec)<br>
+{<br>
+       sm2_ec_ctx_deinit(ec);<br>
+       return sm2_ec_ctx_init(ec);<br>
+}<br>
+<br>
+/* RESULT must have been initialized and is set on success to the<br>
+ * point given by VALUE.<br>
+ */<br>
+static int sm2_ecc_os2ec(MPI_POINT result, MPI value)<br>
+{<br>
+       int rc;<br>
+       size_t n;<br>
+       const unsigned char *buf;<br>
+       unsigned char *buf_memory;<br>
+       MPI x, y;<br>
+<br>
+       n = (mpi_get_nbits(value)+7)/8;<br>
+       buf_memory = kmalloc(n, GFP_KERNEL);<br>
+       rc = mpi_print(GCRYMPI_FMT_USG, buf_memory, n, &n, value);<br>
+       if (rc) {<br>
+               kfree(buf_memory);<br>
+               return rc;<br>
+       }<br>
+       buf = buf_memory;<br>
+<br>
+       if (n < 1) {<br>
+               kfree(buf_memory);<br>
+               return -EINVAL;<br>
+       }<br>
+       if (*buf != 4) {<br>
+               kfree(buf_memory);<br>
+               return -EINVAL; /* No support for point compression.  */<br>
+       }<br>
+       if (((n-1)%2)) {<br>
+               kfree(buf_memory);<br>
+               return -EINVAL;<br>
+       }<br>
+       n = (n-1)/2;<br>
+       x = mpi_read_raw_data(buf + 1, n);<br>
+       if (!x) {<br>
+               kfree(buf_memory);<br>
+               return -ENOMEM;<br>
+       }<br>
+       y = mpi_read_raw_data(buf + 1 + n, n);<br>
+       kfree(buf_memory);<br>
+       if (!y) {<br>
+               mpi_free(x);<br>
+               return -ENOMEM;<br>
+       }<br>
+<br>
+       mpi_normalize(x);<br>
+       mpi_normalize(y);<br>
+<br>
+       mpi_set(result->x, x);<br>
+       mpi_set(result->y, y);<br>
+       mpi_set_ui(result->z, 1);<br>
+<br>
+       mpi_free(x);<br>
+       mpi_free(y);<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+struct sm2_signature_ctx {<br>
+       MPI sig_r;<br>
+       MPI sig_s;<br>
+};<br>
+<br>
+int sm2_get_signature_r(void *context, size_t hdrlen, unsigned char tag,<br>
+                               const void *value, size_t vlen)<br>
+{<br>
+       struct sm2_signature_ctx *sig = context;<br>
+<br>
+       if (!value || !vlen)<br>
+               return -EINVAL;<br>
+<br>
+       sig->sig_r = mpi_read_raw_data(value, vlen);<br>
+       if (!sig->sig_r)<br>
+               return -ENOMEM;<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+int sm2_get_signature_s(void *context, size_t hdrlen, unsigned char tag,<br>
+                               const void *value, size_t vlen)<br>
+{<br>
+       struct sm2_signature_ctx *sig = context;<br>
+<br>
+       if (!value || !vlen)<br>
+               return -EINVAL;<br>
+<br>
+       sig->sig_s = mpi_read_raw_data(value, vlen);<br>
+       if (!sig->sig_s)<br>
+               return -ENOMEM;<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static int sm2_z_digest_update(struct shash_desc *desc,<br>
+                       MPI m, unsigned int pbytes)<br>
+{<br>
+       static const unsigned char zero[32];<br>
+       unsigned char *in;<br>
+       unsigned int inlen;<br>
+<br>
+       in = mpi_get_buffer(m, &inlen, NULL);<br>
+       if (!in)<br>
+               return -EINVAL;<br>
+<br>
+       if (inlen < pbytes) {<br>
+               /* padding with zero */<br>
+               crypto_sm3_update(desc, zero, pbytes - inlen);<br>
+               crypto_sm3_update(desc, in, inlen);<br>
+       } else if (inlen > pbytes) {<br>
+               /* skip the starting zero */<br>
+               crypto_sm3_update(desc, in + inlen - pbytes, pbytes);<br>
+       } else {<br>
+               crypto_sm3_update(desc, in, inlen);<br>
+       }<br>
+<br>
+       kfree(in);<br>
+       return 0;<br>
+}<br>
+<br>
+static int sm2_z_digest_update_point(struct shash_desc *desc,<br>
+                       MPI_POINT point, struct mpi_ec_ctx *ec, unsigned int pbytes)<br>
+{<br>
+       MPI x, y;<br>
+       int ret = -EINVAL;<br>
+<br>
+       x = mpi_new(0);<br>
+       y = mpi_new(0);<br>
+<br>
+       if (!mpi_ec_get_affine(x, y, point, ec) &&<br>
+               !sm2_z_digest_update(desc, x, pbytes) &&<br>
+               !sm2_z_digest_update(desc, y, pbytes))<br>
+               ret = 0;<br>
+<br>
+       mpi_free(x);<br>
+       mpi_free(y);<br>
+       return ret;<br>
+}<br>
+<br>
+int sm2_compute_z_digest(struct crypto_akcipher *tfm,<br>
+                       const unsigned char *id, size_t id_len,<br>
+                       unsigned char dgst[SM3_DIGEST_SIZE])<br>
+{<br>
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);<br>
+       uint16_t bits_len;<br>
+       unsigned char entl[2];<br>
+       SHASH_DESC_ON_STACK(desc, NULL);<br>
+       unsigned int pbytes;<br>
+<br>
+       if (id_len > (USHRT_MAX / 8) || !ec->Q)<br>
+               return -EINVAL;<br>
+<br>
+       bits_len = (uint16_t)(id_len * 8);<br>
+       entl[0] = bits_len >> 8;<br>
+       entl[1] = bits_len & 0xff;<br>
+<br>
+       pbytes = MPI_NBYTES(ec->p);<br>
+<br>
+       /* ZA = H256(ENTLA | IDA | a | b | xG | yG | xA | yA) */<br>
+       sm3_base_init(desc);<br>
+       crypto_sm3_update(desc, entl, 2);<br>
+       crypto_sm3_update(desc, id, id_len);<br>
+<br>
+       if (sm2_z_digest_update(desc, ec->a, pbytes) ||<br>
+               sm2_z_digest_update(desc, ec->b, pbytes) ||<br>
+               sm2_z_digest_update_point(desc, ec->G, ec, pbytes) ||<br>
+               sm2_z_digest_update_point(desc, ec->Q, ec, pbytes))<br>
+               return -EINVAL;<br>
+<br>
+       crypto_sm3_finup(desc, NULL, 0, dgst);<br>
+       return 0;<br>
+}<br>
+EXPORT_SYMBOL(sm2_compute_z_digest);<br>
+<br>
+static int _sm2_verify(struct mpi_ec_ctx *ec, MPI hash, MPI sig_r, MPI sig_s)<br>
+{<br>
+       int rc = -EINVAL;<br>
+       struct gcry_mpi_point sG, tP;<br>
+       MPI t = NULL;<br>
+       MPI x1 = NULL, y1 = NULL;<br>
+<br>
+       mpi_point_init(&sG);<br>
+       mpi_point_init(&tP);<br>
+       x1 = mpi_new(0);<br>
+       y1 = mpi_new(0);<br>
+       t = mpi_new(0);<br>
+<br>
+       /* r, s in [1, n-1] */<br>
+       if (mpi_cmp_ui(sig_r, 1) < 0 || mpi_cmp(sig_r, ec->n) > 0 ||<br>
+               mpi_cmp_ui(sig_s, 1) < 0 || mpi_cmp(sig_s, ec->n) > 0) {<br>
+               goto leave;<br>
+       }<br>
+<br>
+       /* t = (r + s) % n, t == 0 */<br>
+       mpi_addm(t, sig_r, sig_s, ec->n);<br>
+       if (mpi_cmp_ui(t, 0) == 0)<br>
+               goto leave;<br>
+<br>
+       /* sG + tP = (x1, y1) */<br>
+       rc = -EBADMSG;<br>
+       mpi_ec_mul_point(&sG, sig_s, ec->G, ec);<br>
+       mpi_ec_mul_point(&tP, t, ec->Q, ec);<br>
+       mpi_ec_add_points(&sG, &sG, &tP, ec);<br>
+       if (mpi_ec_get_affine(x1, y1, &sG, ec))<br>
+               goto leave;<br>
+<br>
+       /* R = (e + x1) % n */<br>
+       mpi_addm(t, hash, x1, ec->n);<br>
+<br>
+       /* check R == r */<br>
+       rc = -EKEYREJECTED;<br>
+       if (mpi_cmp(t, sig_r))<br>
+               goto leave;<br>
+<br>
+       rc = 0;<br>
+<br>
+leave:<br>
+       mpi_point_free_parts(&sG);<br>
+       mpi_point_free_parts(&tP);<br>
+       mpi_free(x1);<br>
+       mpi_free(y1);<br>
+       mpi_free(t);<br>
+<br>
+       return rc;<br>
+}<br>
+<br>
+static int sm2_verify(struct akcipher_request *req)<br>
+{<br>
+       struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);<br>
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);<br>
+       unsigned char *buffer;<br>
+       struct sm2_signature_ctx sig;<br>
+       MPI hash;<br>
+       int ret;<br>
+<br>
+       if (unlikely(!ec->Q))<br>
+               return -EINVAL;<br>
+<br>
+       buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL);<br>
+       if (!buffer)<br>
+               return -ENOMEM;<br>
+<br>
+       sg_pcopy_to_buffer(req->src,<br>
+                       sg_nents_for_len(req->src, req->src_len + req->dst_len),<br>
+                       buffer, req->src_len + req->dst_len, 0);<br>
+<br>
+       sig.sig_r = NULL;<br>
+       sig.sig_s = NULL;<br>
+       ret = asn1_ber_decoder(&sm2signature_decoder, &sig, buffer, req->src_len);<br>
+       if (ret)<br>
+               goto error;<br>
+<br>
+       ret = -ENOMEM;<br>
+       hash = mpi_read_raw_data(buffer + req->src_len, req->dst_len);<br>
+       if (!hash)<br>
+               goto error;<br>
+<br>
+       ret = _sm2_verify(ec, hash, sig.sig_r, sig.sig_s);<br>
+<br>
+       mpi_free(hash);<br>
+error:<br>
+       mpi_free(sig.sig_r);<br>
+       mpi_free(sig.sig_s);<br>
+       kfree(buffer);<br>
+       return ret;<br>
+}<br>
+<br>
+static int sm2_set_pub_key(struct crypto_akcipher *tfm, const void *key,<br>
+                                               unsigned int keylen)<br>
+{<br>
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);<br>
+       MPI a;<br>
+       int rc;<br>
+<br>
+       rc = sm2_ec_ctx_reset(ec);<br>
+       if (rc)<br>
+               return rc;<br>
+<br>
+       ec->Q = mpi_point_new(0);<br>
+       if (!ec->Q)<br>
+               return -ENOMEM;<br>
+<br>
+       /* include the uncompressed flag '0x04' */<br>
+       rc = -ENOMEM;<br>
+       a = mpi_read_raw_data(key, keylen);<br>
+       if (!a)<br>
+               goto error;<br>
+<br>
+       mpi_normalize(a);<br>
+       rc = sm2_ecc_os2ec(ec->Q, a);<br>
+       mpi_free(a);<br>
+       if (rc)<br>
+               goto error;<br>
+<br>
+       return 0;<br>
+<br>
+error:<br>
+       mpi_point_release(ec->Q);<br>
+       ec->Q = NULL;<br>
+       return rc;<br>
+}<br>
+<br>
+static unsigned int sm2_max_size(struct crypto_akcipher *tfm)<br>
+{<br>
+       /* Unlimited max size */<br>
+       return PAGE_SIZE;<br>
+}<br>
+<br>
+static void sm2_exit_tfm(struct crypto_akcipher *tfm)<br>
+{<br>
+       struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);<br>
+<br>
+       mpi_ec_deinit(ec);<br>
+}<br>
+<br>
+static struct akcipher_alg sm2 = {<br>
+       .verify = sm2_verify,<br>
+       .set_pub_key = sm2_set_pub_key,<br>
+       .max_size = sm2_max_size,<br>
+       .exit = sm2_exit_tfm,<br>
+       .base = {<br>
+               .cra_name = "sm2",<br>
+               .cra_driver_name = "sm2-generic",<br>
+               .cra_priority = 100,<br>
+               .cra_module = THIS_MODULE,<br>
+               .cra_ctxsize = sizeof(struct mpi_ec_ctx),<br>
+       },<br>
+};<br>
+<br>
+static int sm2_init(void)<br>
+{<br>
+       return crypto_register_akcipher(&sm2);<br>
+}<br>
+<br>
+static void sm2_exit(void)<br>
+{<br>
+       crypto_unregister_akcipher(&sm2);<br>
+}<br>
+<br>
+subsys_initcall(sm2_init);<br>
+module_exit(sm2_exit);<br>
+<br>
+MODULE_LICENSE("GPL");<br>
+MODULE_AUTHOR("Tianjia Zhang <<a href="mailto:tianjia.zhang@linux.alibaba.com" target="_blank">tianjia.zhang@linux.alibaba.com</a>>");<br>
+MODULE_DESCRIPTION("SM2 generic algorithm");<br>
+MODULE_ALIAS_CRYPTO("sm2-generic");<br>
diff --git a/crypto/sm2signature.asn1 b/crypto/sm2signature.asn1<br>
new file mode 100644<br>
index 000000000000..ab8c0b754d21<br>
--- /dev/null<br>
+++ b/crypto/sm2signature.asn1<br>
@@ -0,0 +1,4 @@<br>
+Sm2Signature ::= SEQUENCE {<br>
+       sig_r   INTEGER ({ sm2_get_signature_r }),<br>
+       sig_s   INTEGER ({ sm2_get_signature_s })<br>
+}<br>
diff --git a/include/crypto/sm2.h b/include/crypto/sm2.h<br>
new file mode 100644<br>
index 000000000000..af452556dcd4<br>
--- /dev/null<br>
+++ b/include/crypto/sm2.h<br>
@@ -0,0 +1,25 @@<br>
+/* SPDX-License-Identifier: GPL-2.0-or-later */<br>
+/*<br>
+ * sm2.h - SM2 asymmetric public-key algorithm<br>
+ * as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012 SM2 and<br>
+ * described at <a href="https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02" rel="noreferrer" target="_blank">https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02</a><br>
+ *<br>
+ * Copyright (c) 2020, Alibaba Group.<br>
+ * Written by Tianjia Zhang <<a href="mailto:tianjia.zhang@linux.alibaba.com" target="_blank">tianjia.zhang@linux.alibaba.com</a>><br>
+ */<br>
+<br>
+#ifndef _CRYPTO_SM2_H<br>
+#define _CRYPTO_SM2_H<br>
+<br>
+#include <crypto/sm3.h><br>
+#include <crypto/akcipher.h><br>
+<br>
+/* The default user id as specified in GM/T 0009-2012 */<br>
+#define SM2_DEFAULT_USERID "1234567812345678"<br>
+#define SM2_DEFAULT_USERID_LEN 16<br>
+<br>
+extern int sm2_compute_z_digest(struct crypto_akcipher *tfm,<br>
+                       const unsigned char *id, size_t id_len,<br>
+                       unsigned char dgst[SM3_DIGEST_SIZE]);<br>
+<br>
+#endif /* _CRYPTO_SM2_H */<br>
-- <br>
2.17.1<br>
<br>
</blockquote></div>