SM2

From Crypto++ Wiki
Jump to navigation Jump to search

SM2 is a four-part standard for public key algorithms specified by China. This page will show you how to use SM2 classes and supply field notes when cutting-in some SM2 algorithms. The notes are significant because we lack some information.

The information is missing because (1) we don't have access to some documents (paywall?), (2) some documents are written in Chinese (we are fluent English), (3) English documents are incomplete (like draft-shen-sm2-ecdsa), and (4) the reference implementation has some unexpected features (bugs?).

Related pages are SM3 and SM4, which are the library's implementation of the Chinese hash and block cipher.

Field Notes

The following details some of our field notes during our cut-in of SM2. All the commands below were run form the root directory of the reference code after cloning. The URL for the reference code is https://github.com/guanzhi/GmSSL.git.

Information

The information and documents we had access to:

gmssl Test Program

The gmssl test program seems to be the main output artifact from the reference implementation. It appears to be the openssl program with a different name. To build it:

$ git clone https://github.com/guanzhi/GmSSL.git
$ cd GmSSL

$ ./config
...

$ make -j 8

Don't bother with make test since it results in a bunch of failures.

Once built here are the locations of output artifacts:

GmSSL$ find . -name gmssl
./go/gmssl
./apps/gmssl

GmSSL$ find . -name 'libcrypto*'
./libcrypto.a
./util/libcrypto.num
./libcrypto.so.1.1
./libcrypto.pc
./libcrypto.so

GmSSL$ find . -name 'libssl*'
./libssl.so.1.1
./util/libssl.num
./libssl.pc
./libssl.a
./libssl.so

To run the program you have to twiddle with library paths:

$ LD_LIBRARY_PATH=. apps/gmssl version
GmSSL 2.0 - OpenSSL 1.1.0d  26 Jan 2017

A script makes it easier to run the program without the LD_LIBRARY_PREFIX:

$ cat gmssl
#!/usr/bin/env bash

LD_LIBRARY_PATH=".:$LD_LIBRARY_PATH" OPENSSL_CONF="apps/openssl.cnf" apps/gmssl "$@"
$ chmod +x gmssl

Domain Parameters

It appears the primary or main domain parameters are the following.

p = FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
a = FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC
b = 28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93
n = FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123
Gx = 32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7
Gy = BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0

The parameter is listed SM2 Algorithms Parameters, and it surfaces under the gmssl test program for curve sm2p256v1:

$ LD_LIBRARY_PATH=. apps/gmssl ecparam -name sm2p256v1 -param_enc explicit -outform DER > params.der
$ dumpasn1
...
  0 224: SEQUENCE {
  3   1:   INTEGER 1
  6  44:   SEQUENCE {
  8   7:     OBJECT IDENTIFIER '1 2 840 10045 1 1'
 17  33:     INTEGER
       :       00 FF FF FF FE FF FF FF FF FF FF FF FF FF FF FF
       :       FF FF FF FF FF 00 00 00 00 FF FF FF FF FF FF FF
       :       FF
       :     }
 52  68:   SEQUENCE {
 54  32:     OCTET STRING
       :       FF FF FF FE FF FF FF FF FF FF FF FF FF FF FF FF
       :       FF FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FC
 88  32:     OCTET STRING
       :       28 E9 FA 9E 9D 9F 5E 34 4D 5A 9E 4B CF 65 09 A7
       :       F3 97 89 F5 15 AB 8F 92 DD BC BD 41 4D 94 0E 93
       :     }
122  65:   OCTET STRING
       :     04 32 C4 AE 2C 1F 19 81 19 5F 99 04 46 6A 39 C9
       :     94 8F E3 0B BF F2 66 0B E1 71 5A 45 89 33 4C 74
       :     C7 BC 37 36 A2 F4 F6 77 9C 59 BD CE E3 6B 69 21
       :     53 D0 A9 87 7C C6 2A 47 40 02 DF 32 E5 21 39 F0
       :     A0
189  33:   INTEGER
       :     00 FF FF FF FE FF FF FF FF FF FF FF FF FF FF FF
       :     FF 72 03 DF 6B 21 C6 05 2B 53 BB F4 09 39 D5 41
       :     23
224   1:   INTEGER 1
       :   }

sm2p256v1 OID

Based on domain parameter testing it looks we need to map two different OIDs to the parameters listed above. First, we need to map the OID for sm2encrypt_recommendedParameters, and second we need to map the OID for sm2p256v1.

We map both OIDs to the same parameter set in eccrypto.cpp. The library lacks the notion of an alias, so the parameters are duplicated. The compiler's string pooling should fold the parameters.

// this array must be sorted by OID
static const EcRecommendedParameters<ECP> rec[] = {
    EcRecommendedParameters<ECP>(ASN1::sm2p256v1(),
        "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF",
        "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC",
        "28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93",
        "04" "32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7"
             "BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0",
        "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123",
            1),
    EcRecommendedParameters<ECP>(ASN1::sm2encrypt_recommendedParameters(),
        "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF",
        "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC",
        "28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93",
        "04" "32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7"
             "BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0",
        "FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123",
        1),
    ...
};

The OIDs for other domain parameters and curves listed in Public Key Cryptographic Algorithm SM2 Based on Elliptic Curves seems to be missing.

gmssl OIDs

A complete list of NIDs and OIDs used by the test program can be found with:

$ grep -IR NID_sm2 | grep -E '*\.c'
java/GmSSL.c:   NID_sm2sign,
java/GmSSL.c:   case NID_sm2sign:
java/GmSSL.c:           if (!EVP_PKEY_CTX_set_ec_scheme(pkctx, OBJ_txt2nid(alg) == NID_sm2sign ?
java/GmSSL.c:           if (!EVP_PKEY_CTX_set_ec_scheme(pkctx, OBJ_txt2nid(alg) == NID_sm2sign ?
java/GmSSL.c:   NID_sm2encrypt_with_sm3,
java/GmSSL.c:   NID_sm2encrypt_with_sha1,
java/GmSSL.c:   NID_sm2encrypt_with_sha256,
java/GmSSL.c:   NID_sm2encrypt_with_sha512,
java/GmSSL.c:   case NID_sm2encrypt_with_sm3:
java/GmSSL.c:   case NID_sm2encrypt_with_sha1:
java/GmSSL.c:   case NID_sm2encrypt_with_sha256:
java/GmSSL.c:   case NID_sm2encrypt_with_sha512:
java/GmSSL.c:   NID_sm2exchange,
java/GmSSL.c:   case NID_sm2exchange:
ssl/t1_lib.c:    {NID_sm2p256v1, 128, TLS_CURVE_PRIME}, /* sm2p256v1 (30) */
ssl/t1_lib.c:        return NID_sm2p256v1;
ssl/t1_lib.c:                default_nid = NID_sm2sign_with_sm3;
ssl/t1_lib.c:                default_nid = NID_sm2sign_with_sm3;
ssl/statem/statem_lib.c:            (EC_KEY *)EVP_PKEY_get0(pk))) == NID_sm2p256v1) {
test/sm9test.c: int curve_id = NID_sm2p256v1; //FIXME
test/bfibetest.c:       int curve_id = NID_sm2p256v1;
test/bb1ibetest.c:      int curve_id = NID_sm2p256v1;//FIXME
crypto/ec/ec_curve.c:    {NID_sm2p256v1, &_EC_SM2_PRIME_256V1.h, 0,
crypto/gmapi/gmapi_skf_ec.c:    if (!(ret = EC_KEY_new_by_curve_name(NID_sm2p256v1))) {
crypto/gmapi/gmapi_skf_ec.c:    if (!(ret = EC_KEY_new_by_curve_name(NID_sm2p256v1))) {
crypto/gmapi/gmapi_skf_ec.c:    if (!(group = EC_GROUP_new_by_curve_name(NID_sm2p256v1))) {
crypto/gmapi/gmapi_skf_ec.c:    if (!(group = EC_GROUP_new_by_curve_name(NID_sm2p256v1))) {
crypto/gmapi/gmapi_sgd.c:       {NID_sm2sign, SGD_SM2_1},
crypto/gmapi/gmapi_sgd.c:       {NID_sm2exchange, SGD_SM2_2},
crypto/gmapi/gmapi_sgd.c:       {NID_sm2encrypt, SGD_SM2_3}
crypto/gmapi/gmapi_sdf_ec.c:    if (!(ret = EC_KEY_new_by_curve_name(NID_sm2p256v1))) {
crypto/gmapi/gmapi_sdf_ec.c:    if (!(ret = EC_KEY_new_by_curve_name(NID_sm2p256v1))) {
crypto/gmapi/gmapi_sdf_ec.c:    if (!(group = EC_GROUP_new_by_curve_name(NID_sm2p256v1))) {
crypto/gmapi/gmapi_sdf_ec.c:    if (!(group = EC_GROUP_new_by_curve_name(NID_sm2p256v1))
crypto/gmapi/gmapi_sdf_ec.c:    if (!(group = EC_GROUP_new_by_curve_name(NID_sm2p256v1))
crypto/evp/m_sm3.c:     NID_sm2sign_with_sm3,
apps/speed.c:        NID_sm2p256v1