Browse Source

add:支持国密SM2,SM3,SM4

陈旭东 3 years ago
parent
commit
60bd343f95
51 changed files with 11283 additions and 6 deletions
  1. 2 0
      bsp/linux/include/luat_conf_bsp.h
  2. 6 0
      components/SM/include/internal/ayconfig.h
  3. 76 0
      components/SM/include/internal/byteorder.h
  4. 90 0
      components/SM/include/internal/debug_utils.h
  5. 55 0
      components/SM/include/internal/openssl_aid.h
  6. 123 0
      components/SM/include/internal/ssl_random.h
  7. 16 0
      components/SM/include/internal/types.h
  8. 12 0
      components/SM/include/modes_lcl.h
  9. 430 0
      components/SM/include/openssl/modes.h
  10. 245 0
      components/SM/include/rsa/rsa_cloud.h
  11. 376 0
      components/SM/include/sm2/sm2.h
  12. 115 0
      components/SM/include/sm3/sm3.h
  13. 379 0
      components/SM/include/sm4/sm4.h
  14. 55 0
      components/SM/src/internal/openssl_aid.c
  15. 416 0
      components/SM/src/internal/ssl_random.c
  16. 154 0
      components/SM/src/modes/cbc128.c
  17. 431 0
      components/SM/src/modes/ccm128.c
  18. 198 0
      components/SM/src/modes/cfb128.c
  19. 226 0
      components/SM/src/modes/ctr128.c
  20. 522 0
      components/SM/src/modes/cts128.c
  21. 2302 0
      components/SM/src/modes/gcm128.c
  22. 204 0
      components/SM/src/modes/gcmf.c
  23. 567 0
      components/SM/src/modes/ocb128.c
  24. 73 0
      components/SM/src/modes/ofb128.c
  25. 330 0
      components/SM/src/modes/wrap128.c
  26. 156 0
      components/SM/src/modes/xts128.c
  27. 489 0
      components/SM/src/rsa/rsa_cloud.c
  28. 1051 0
      components/SM/src/sm2/sm2.c
  29. 303 0
      components/SM/src/sm3/sm3.c
  30. 63 0
      components/SM/src/sm4/sm4_cbc.c
  31. 57 0
      components/SM/src/sm4/sm4_cfb.c
  32. 104 0
      components/SM/src/sm4/sm4_common.c
  33. 80 0
      components/SM/src/sm4/sm4_ctr.c
  34. 59 0
      components/SM/src/sm4/sm4_ecb.c
  35. 182 0
      components/SM/src/sm4/sm4_enc.c
  36. 71 0
      components/SM/src/sm4/sm4_enc_nblks.c
  37. 47 0
      components/SM/src/sm4/sm4_gcm.c
  38. 30 0
      components/SM/src/sm4/sm4_gcmf.c
  39. 124 0
      components/SM/src/sm4/sm4_lcl.h
  40. 58 0
      components/SM/src/sm4/sm4_ofb.c
  41. 220 0
      components/SM/src/sm4/sm4_setkey.c
  42. 91 0
      components/SM/src/sm4/sm4_wrap.c
  43. 85 0
      components/SM/src/sm4/sm4speed.c.bak
  44. 1 1
      components/mbedtls/include/mbedtls/config.h
  45. 3 1
      components/mbedtls/include/mbedtls/ecp.h
  46. 3 0
      components/mbedtls/library/ecp.c
  47. 61 4
      components/mbedtls/library/ecp_curves.c
  48. 59 0
      demo/sm/main.lua
  49. 1 0
      luat/include/luat_libs.h
  50. 479 0
      luat/modules/luat_lib_sm.c
  51. 3 0
      luat/modules/luat_lib_vmx.c

+ 2 - 0
bsp/linux/include/luat_conf_bsp.h

@@ -22,6 +22,8 @@
 #define LUAT_USE_CRYPTO 1
 #define LUAT_COMPILER_NOWEAK
 
+#define LUAT_USE_SM 1
+
 //#define LUAT_USE_LVGL 1
 #define LUAT_USE_LVGL_SDL2 1
 #define LUAT_USE_LCD_SDL2 1

+ 6 - 0
components/SM/include/internal/ayconfig.h

@@ -0,0 +1,6 @@
+#ifndef AYCONFIG_H
+#define AYCONFIG_H
+
+#define OPENSSL_NO_OCB
+
+#endif //AYCONFIG_H

+ 76 - 0
components/SM/include/internal/byteorder.h

@@ -0,0 +1,76 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#ifndef HEADER_BYTEORDER_H
+#define HEADER_BYTEORDER_H
+
+
+#ifdef CPU_BIGENDIAN
+
+#define cpu_to_be16(v) (v)
+#define cpu_to_be32(v) (v)
+#define be16_to_cpu(v) (v)
+#define be32_to_cpu(v) (v)
+
+#else
+
+#define cpu_to_le16(v) (v)
+#define cpu_to_le32(v) (v)
+#define le16_to_cpu(v) (v)
+#define le32_to_cpu(v) (v)
+
+#define cpu_to_be16(v) (((v)<< 8) | ((v)>>8))
+#define cpu_to_be32(v) (((v)>>24) | (((v)>>8)&0xff00) | (((v)<<8)&0xff0000) | ((v)<<24))
+#define be16_to_cpu(v) cpu_to_be16(v)
+#define be32_to_cpu(v) cpu_to_be32(v)
+
+#endif
+
+#endif
+

+ 90 - 0
components/SM/include/internal/debug_utils.h

@@ -0,0 +1,90 @@
+/*
+ * @Author: Weijie Li 
+ * @Date: 2017-11-24 10:05:18 
+ * @Last Modified by: Weijie Li
+ * @Last Modified time: 2017-11-28 10:58:49
+ */
+
+
+
+#ifndef AISINOSSL_INTERNAL_DEBUG_UTILS_H_
+#define AISINOSSL_INTERNAL_DEBUG_UTILS_H_
+
+#include <stdio.h>
+
+
+static char hexchars[] ="0123456789ABCDEF";
+
+#define DUMP(d, len) \
+        DumpPointer(d, len, __FILE__, __LINE__)
+
+#define DUMPPINFO(d, len, info) \
+        DumpPointerInfo(d, len, __FILE__, __LINE__, info)
+
+static void DumpPointer(const uint8_t *d, int len, char _file[], int _line) {
+    printf("dump <%s,%d>: %d\n", _file, _line, len);
+    size_t i;
+    for (i = 0; i < len; i++) {
+        printf("%02X", (*d++));
+    }
+    printf("\n");
+}
+
+static void DumpPointerInfo(const uint8_t *d, int len, char _file[], int _line, char info[]) {
+    printf("[%s] dump <%s,%d>: %d\n", info, _file, _line, len);
+    size_t i;
+    for (i = 0; i < len; i++) {
+        printf("%02X", (*d++));
+    }
+    printf("\n");
+}
+
+
+/**
+ * Hexify(in, out, len):
+ * Convert ${len} bytes from ${in} into hexadecimal, writing the resulting
+ * 2 * ${len} bytes to ${out}; and append a NUL byte.
+ */
+static void Hexify(const uint8_t *in, char *out, size_t len) {
+    char * p = out;
+    size_t i;
+    
+    for (i = 0; i < len; i++) {
+        *p++ = hexchars[in[i] >> 4];
+        *p++ = hexchars[in[i] & 0x0f];
+    }
+    *p = '\0';
+}
+
+/**
+ * UnHexify(in, out, len):
+ * Convert 2 * ${len} hexadecimal characters from ${in} to ${len} bytes
+ * and write them to ${out}.  This function will only fail if the input is
+ * not a sequence of hexadecimal characters.
+ */
+static int UnHexify(const char *in, uint8_t *out, size_t len) {
+    size_t i;
+    
+    /* Make sure we have at least 2 * ${len} hex characters. */
+    for (i = 0; i < 2 * len; i++) {
+        if ((in[i] == '\0') || (strchr(hexchars, in[i]) == NULL))
+            goto err0;
+    }
+    
+    for (i = 0; i < len; i++) {
+        out[i] = (strchr(hexchars, in[2 * i]) - hexchars) & 0x0f;
+        out[i] <<= 4;
+        out[i] += (strchr(hexchars, in[2 * i + 1]) - hexchars) & 0x0f;
+    }
+    
+    /* Success! */
+    return (0);
+    
+err0:
+    /* Bad input string. */
+    return (-1);
+}
+
+
+
+#endif /* AISINOSSL_INTERNAL_DEBUG_UTILS_H_ */

+ 55 - 0
components/SM/include/internal/openssl_aid.h

@@ -0,0 +1,55 @@
+#ifndef OPENSSL_AID_H
+#define OPENSSL_AID_H
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+void OPENSSL_cleanse(void *ptr, size_t len);
+
+/*
+ * CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal.
+ * It takes an amount of time dependent on |len|, but independent of the
+ * contents of |a| and |b|. Unlike memcmp, it cannot be used to put elements
+ * into a defined order as the return value when a != b is undefined, other
+ * than to be non-zero.
+ */
+int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len);
+
+void CRYPTO_free(void *ptr, const char *file, int line);
+
+void CRYPTO_clear_free(void *ptr, size_t num, const char *file, int line);
+
+void *CRYPTO_malloc(size_t num, const char *file, int line);
+
+
+
+#ifndef OPENSSL_FILE
+# ifdef OPENSSL_NO_FILENAMES
+#  define OPENSSL_FILE ""
+#  define OPENSSL_LINE 0
+# else
+#  define OPENSSL_FILE __FILE__
+#  define OPENSSL_LINE __LINE__
+# endif
+#endif
+
+// #  define OPENSSL_FILE __FILE__
+// #  define OPENSSL_LINE __LINE__
+
+
+# define OPENSSL_clear_free(addr, num) \
+        CRYPTO_clear_free(addr, num, OPENSSL_FILE, OPENSSL_LINE)
+# define OPENSSL_malloc(num) \
+        CRYPTO_malloc(num, OPENSSL_FILE, OPENSSL_LINE)
+
+# define OPENSSL_free(addr) \
+        CRYPTO_free(addr, OPENSSL_FILE, OPENSSL_LINE)
+
+# define OSSL_NELEM(x)    (sizeof(x)/sizeof((x)[0]))
+
+
+
+#endif //OPENSSL_AID_H

+ 123 - 0
components/SM/include/internal/ssl_random.h

@@ -0,0 +1,123 @@
+#ifndef HEADER_SSL_RANDOM_H
+#define HEADER_SSL_RANDOM_H
+
+/*
+Random Module
+
+Sample:
+ssl_random_context ctx;
+ssl_random_init(&ctx);
+ssl_random_seed(&ctx, NULL, 0);
+// ctx->drbg_ctx CAN BE USED TO hmac_drbg
+ssl_random_rand_int_array(&ctx, arr, 30);
+ssl_random_free(&ctx);
+
+*/
+
+#ifdef _WIN32
+#define _CRT_RAND_S
+#endif
+#include <stdlib.h>
+
+#include <time.h>
+#include <string.h>
+#include <openssl/modes.h>
+#include <mbedtls/md.h>
+#include <mbedtls/hmac_drbg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef ANDROID_VER
+#include <sys/system_properties.h>
+#include <android/sensor.h>
+#include <android/looper.h>
+#endif
+
+// Control HMAC-DRBG Hash Algorithm
+// Attention! Use #define to set it
+#ifndef RANDOM_HASH_ALGORITHM
+#define RANDOM_HASH_ALGORITHM MD_SM3
+#endif
+
+// SET ANDROID SENSOR
+// NOTE: https://developer.android.com/ndk/reference/group/sensor
+//#define ENABLE_SEED_ANDROID_SENSOR
+#define SEED_DEFAULT_SENSOR ASENSOR_TYPE_MAGNETIC_FIELD
+
+// SET iOS SENSOR
+// TODO: some bugs need be fixed (Issue #4)
+#define ENABLE_SEED_IOS_SENSOR
+
+// For Android test
+//#define _DEBUG_
+
+// static unsigned int SSLRandomContextCount = 0;
+
+// HMAC-DRBG Random Class
+typedef struct {
+    short isInitial;
+    short isSeeded;
+
+    unsigned char hashLen;
+    unsigned char *hash;
+
+    const mbedtls_md_info_t *md_info;     /*!<  Hash Type Info    */
+    mbedtls_md_context_t *md_ctx;         /*!<  MD Context        */
+    mbedtls_hmac_drbg_context *drbg_ctx;  /*!<  HMAC DRBG Context */
+} ssl_random_context;
+
+// Init Random Context
+int ssl_random_init(ssl_random_context *ctx);
+
+// Set or reset a seed
+int ssl_random_seed(void* rand_ctx, unsigned char *seed_buf, size_t buf_size);
+int ssl_random_seed_with_option(void *rand_ctx, unsigned char *seed_buf, size_t buf_size, int options);
+
+// Rand a list of Number
+int ssl_random_rand(void *rand_ctx, unsigned char *output, size_t size);
+
+// Rand a list of int32
+int ssl_random_rand_int_array(ssl_random_context *ctx, int *output, int count);
+
+// Rand a list of Uint32
+int ssl_random_rand_uint_array(ssl_random_context *ctx, unsigned int *output, int count);
+
+// Release random context
+void ssl_random_free(ssl_random_context *ctx);
+
+// Shuffle unsigned char array
+int ssl_random_shuffle_u8(u8 *list, int len);
+
+// Rand a list of int32 (if ctx==NULL, then init a global ctx)
+int ssl_random_list(ssl_random_context* ctx, int *list, int len);
+
+// ERROR define
+#define SSL_RANDOM_ERROR_HASH_ALGO_NOT_FOUND -0xF101
+#define SSL_RANDOM_ERROR_NOT_INITIAL -0xF102
+#define SSL_RANDOM_ERROR_NOT_SEEDED -0xF103
+#define SSL_RANDOM_ERROR_OUT_SIZE_TO_LARGE -0xF104
+#define SSL_RANDOM_ERROR_INVLIAD_SIZE -0xF105
+
+// OPTION define
+#define SSL_RANDOM_DISABLE_TIME 0x1
+#define SSL_RANDOM_DISABLE_URANDOM 0x2
+#define SSL_RANDOM_DISABLE_CPU_CYCLE 0x4
+#define SSL_RANDOM_DISABLE_RAND_S 0x8
+#define SSL_RANDOM_DISABLE_ANDROID_INFO 0x10
+#define SSL_RANDOM_DISABLE_ANDROID_SENSOR 0x20
+
+// OTHER define
+#define SSL_RANDOM_MAX_BYTES_COUNT 1024
+#define SSL_RANDOM_MAX_INT_COUNT (1024/4)
+
+// ------ UTIL ------
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 16 - 0
components/SM/include/internal/types.h

@@ -0,0 +1,16 @@
+#ifndef TYPES_H_
+#define TYPES_H_
+
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned long ULONG;
+typedef char          CHAR;
+typedef unsigned char BYTE;
+typedef unsigned int  uint32;
+typedef unsigned char uint8;
+typedef unsigned char byte;
+
+typedef unsigned short int uint16;
+
+typedef unsigned long long uint64;
+#endif

+ 12 - 0
components/SM/include/modes_lcl.h

@@ -0,0 +1,12 @@
+/*
+ * Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <internal/ayconfig.h>
+
+#include <openssl/modes.h>

+ 430 - 0
components/SM/include/openssl/modes.h

@@ -0,0 +1,430 @@
+/*
+ * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef HEADER_MODE_H
+#define HEADER_MODE_H
+
+#include <internal/ayconfig.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+typedef void (*block128_f) (const unsigned char in[16],
+                            unsigned char out[16], const void *key);
+
+typedef void (*cbc128_f) (const unsigned char *in, unsigned char *out,
+                          size_t len, const void *key,
+                          unsigned char ivec[16], int enc);
+
+typedef void (*ctr128_f) (const unsigned char *in, unsigned char *out,
+                          size_t blocks, const void *key,
+                          const unsigned char ivec[16]);
+
+typedef void (*ccm128_f) (const unsigned char *in, unsigned char *out,
+                          size_t blocks, const void *key,
+                          const unsigned char ivec[16],
+                          unsigned char cmac[16]);
+
+void ctr128_inc(unsigned char *counter);
+void ctr128_dec(unsigned char *ctr_buf);
+void ctr128_init(unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16]);
+
+
+void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16], block128_f block);
+void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16], block128_f block);
+
+void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16],
+                           unsigned char ecount_buf[16], unsigned int *num,
+                           block128_f block);
+
+void CRYPTO_ctr128_encrypt_ctr32(const unsigned char *in, unsigned char *out,
+                                 size_t len, const void *key,
+                                 unsigned char ivec[16],
+                                 unsigned char ecount_buf[16],
+                                 unsigned int *num, ctr128_f ctr);
+
+void CRYPTO_ofb128_encrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16], int *num,
+                           block128_f block);
+
+void CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16], int *num,
+                           int enc, block128_f block);
+void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
+                             size_t length, const void *key,
+                             unsigned char ivec[16], int *num,
+                             int enc, block128_f block);
+void CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out,
+                             size_t bits, const void *key,
+                             unsigned char ivec[16], int *num,
+                             int enc, block128_f block);
+
+size_t CRYPTO_cts128_encrypt_block(const unsigned char *in,
+                                   unsigned char *out, size_t len,
+                                   const void *key, unsigned char ivec[16],
+                                   block128_f block);
+size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
+                             size_t len, const void *key,
+                             unsigned char ivec[16], cbc128_f cbc);
+size_t CRYPTO_cts128_decrypt_block(const unsigned char *in,
+                                   unsigned char *out, size_t len,
+                                   const void *key, unsigned char ivec[16],
+                                   block128_f block);
+size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
+                             size_t len, const void *key,
+                             unsigned char ivec[16], cbc128_f cbc);
+
+size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in,
+                                       unsigned char *out, size_t len,
+                                       const void *key,
+                                       unsigned char ivec[16],
+                                       block128_f block);
+size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
+                                 size_t len, const void *key,
+                                 unsigned char ivec[16], cbc128_f cbc);
+size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in,
+                                       unsigned char *out, size_t len,
+                                       const void *key,
+                                       unsigned char ivec[16],
+                                       block128_f block);
+size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
+                                 size_t len, const void *key,
+                                 unsigned char ivec[16], cbc128_f cbc);
+
+typedef struct gcm128_context GCM128_CONTEXT;
+
+GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block);
+void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block);
+void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const unsigned char *iv,
+                         size_t len);
+int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const unsigned char *aad,
+                      size_t len);
+int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx,
+                          const unsigned char *in, unsigned char *out,
+                          size_t len);
+int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx,
+                          const unsigned char *in, unsigned char *out,
+                          size_t len);
+int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx,
+                                const unsigned char *in, unsigned char *out,
+                                size_t len, ctr128_f stream);
+int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx,
+                                const unsigned char *in, unsigned char *out,
+                                size_t len, ctr128_f stream);
+int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const unsigned char *tag,
+                         size_t len);
+void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len);
+void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx);
+
+/*
+*  Created on: 2017.10.18
+*      Author: lzj
+*
+*  encrypted file format:
+*
+*  MAGIC_TAG  : AYCF-SM4-GCM
+*  VERSION	  : 1
+*  TAG		    : cipher tag
+*  SIZE	      : plaintext size
+*  CONTENT	  : cipher text
+*
+*	how to use?  see the test function under below .check out!
+*/
+#define GCM_FILE_MAGIC_TAG "AYCF-SM4-GCM"
+#define GCM_FILE_MAGIC_TAG_LEN 12
+#define GCM_FILE_VERSION 1
+#define GCM_FILE_TAG_LEN 16
+#define GCM_FILE_MAX_BLOCK_LEN 128
+
+typedef struct {
+		GCM128_CONTEXT *gcm;
+		unsigned char tag[GCM_FILE_TAG_LEN];
+} gcmf_context;
+
+int gcmf_init(gcmf_context *ctx, void * key, block128_f block);
+int gcmf_free(gcmf_context *ctx);
+int gcmf_set_iv(gcmf_context *ctx, const unsigned char * iv, size_t len);
+int gcmf_encrypt_file(gcmf_context * ctx, char *infpath, char *outfpath);
+int gcmf_decrypt_file(gcmf_context * ctx, char *infpath, char *outfpath);
+
+typedef struct ccm128_context CCM128_CONTEXT;
+
+void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
+                        unsigned int M, unsigned int L, void *key,
+                        block128_f block);
+int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx, const unsigned char *nonce,
+                        size_t nlen, size_t mlen);
+void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx, const unsigned char *aad,
+                       size_t alen);
+int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx, const unsigned char *inp,
+                          unsigned char *out, size_t len);
+int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx, const unsigned char *inp,
+                          unsigned char *out, size_t len);
+int CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx, const unsigned char *inp,
+                                unsigned char *out, size_t len,
+                                ccm128_f stream);
+int CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx, const unsigned char *inp,
+                                unsigned char *out, size_t len,
+                                ccm128_f stream);
+size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len);
+
+typedef struct xts128_context XTS128_CONTEXT;
+
+int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx,
+                          const unsigned char iv[16],
+                          const unsigned char *inp, unsigned char *out,
+                          size_t len, int enc);
+
+size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
+                       unsigned char *out,
+                       const unsigned char *in, size_t inlen,
+                       block128_f block);
+
+size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
+                         unsigned char *out,
+                         const unsigned char *in, size_t inlen,
+                         block128_f block);
+size_t CRYPTO_128_wrap_pad(void *key, const unsigned char *icv,
+                           unsigned char *out, const unsigned char *in,
+                           size_t inlen, block128_f block);
+size_t CRYPTO_128_unwrap_pad(void *key, const unsigned char *icv,
+                             unsigned char *out, const unsigned char *in,
+                             size_t inlen, block128_f block);
+
+#ifndef OPENSSL_NO_OCB
+typedef struct ocb128_context OCB128_CONTEXT;
+
+typedef void (*ocb128_f) (const unsigned char *in, unsigned char *out,
+                          size_t blocks, const void *key,
+                          size_t start_block_num,
+                          unsigned char offset_i[16],
+                          const unsigned char L_[][16],
+                          unsigned char checksum[16]);
+
+OCB128_CONTEXT *CRYPTO_ocb128_new(void *keyenc, void *keydec,
+                                  block128_f encrypt, block128_f decrypt,
+                                  ocb128_f stream);
+int CRYPTO_ocb128_init(OCB128_CONTEXT *ctx, void *keyenc, void *keydec,
+                       block128_f encrypt, block128_f decrypt,
+                       ocb128_f stream);
+int CRYPTO_ocb128_copy_ctx(OCB128_CONTEXT *dest, OCB128_CONTEXT *src,
+                           void *keyenc, void *keydec);
+int CRYPTO_ocb128_setiv(OCB128_CONTEXT *ctx, const unsigned char *iv,
+                        size_t len, size_t taglen);
+int CRYPTO_ocb128_aad(OCB128_CONTEXT *ctx, const unsigned char *aad,
+                      size_t len);
+int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx, const unsigned char *in,
+                          unsigned char *out, size_t len);
+int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx, const unsigned char *in,
+                          unsigned char *out, size_t len);
+int CRYPTO_ocb128_finish(OCB128_CONTEXT *ctx, const unsigned char *tag,
+                         size_t len);
+int CRYPTO_ocb128_tag(OCB128_CONTEXT *ctx, unsigned char *tag, size_t len);
+void CRYPTO_ocb128_cleanup(OCB128_CONTEXT *ctx);
+#endif                          /* OPENSSL_NO_OCB */
+
+#ifdef  __cplusplus
+}
+#endif
+
+
+#ifndef AISINOSSL_MODES_LCL
+#define AISINOSSL_MODES_LCL
+
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
+typedef __int64 i64;
+typedef unsigned __int64 u64;
+# define U64(C) C##UI64
+#elif defined(__arch64__)
+typedef long i64;
+typedef unsigned long u64;
+# define U64(C) C##UL
+#else
+typedef long long i64;
+typedef unsigned long long u64;
+# define U64(C) C##ULL
+#endif
+
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+#define STRICT_ALIGNMENT 1
+#ifndef PEDANTIC
+# if defined(__i386)    || defined(__i386__)    || \
+     defined(__x86_64)  || defined(__x86_64__)  || \
+     defined(_M_IX86)   || defined(_M_AMD64)    || defined(_M_X64) || \
+     defined(__aarch64__)                       || \
+     defined(__s390__)  || defined(__s390x__)
+#  undef STRICT_ALIGNMENT
+# endif
+#endif
+
+#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
+# if defined(__GNUC__) && __GNUC__>=2
+#  if defined(__x86_64) || defined(__x86_64__)
+#   define BSWAP8(x) ({ u64 ret_=(x);                   \
+                        __asm__ ("bswapq %0  "              \
+                        : "+r"(ret_));   ret_;          })
+#   define BSWAP4(x) ({ u32 ret_=(x);                   \
+                        __asm__ ("bswapl %0 "               \
+                        : "+r"(ret_));   ret_;          })
+#  elif (defined(__i386) || defined(__i386__)) && !defined(I386_ONLY)
+#   define BSWAP8(x) ({ u32 lo_=(u64)(x)>>32,hi_=(x);   \
+                        asm ("bswapl %0; bswapl %1"     \
+                        : "+r"(hi_),"+r"(lo_));         \
+                        (u64)hi_<<32|lo_;               })
+#   define BSWAP4(x) ({ u32 ret_=(x);                   \
+                        asm ("bswapl %0"                \
+                        : "+r"(ret_));   ret_;          })
+#  elif defined(__aarch64__)
+#   define BSWAP8(x) ({ u64 ret_;                       \
+                        asm ("rev %0,%1"                \
+                        : "=r"(ret_) : "r"(x)); ret_;   })
+#   define BSWAP4(x) ({ u32 ret_;                       \
+                        asm ("rev %w0,%w1"              \
+                        : "=r"(ret_) : "r"(x)); ret_;   })
+#  elif (defined(__arm__) || defined(__arm)) && !defined(STRICT_ALIGNMENT)
+#   define BSWAP8(x) ({ u32 lo_=(u64)(x)>>32,hi_=(x);   \
+                        asm ("rev %0,%0; rev %1,%1"     \
+                        : "+r"(hi_),"+r"(lo_));         \
+                        (u64)hi_<<32|lo_;               })
+#   define BSWAP4(x) ({ u32 ret_;                       \
+                        asm ("rev %0,%1"                \
+                        : "=r"(ret_) : "r"((u32)(x)));  \
+                        ret_;                           })
+#  endif
+# elif defined(_MSC_VER)
+#  if _MSC_VER>=1300
+#   pragma intrinsic(_byteswap_uint64,_byteswap_ulong)
+#   define BSWAP8(x)    _byteswap_uint64((u64)(x))
+#   define BSWAP4(x)    _byteswap_ulong((u32)(x))
+#  elif defined(_M_IX86)
+__inline u32 _bswap4(u32 val)
+{
+	_asm mov eax, val _asm bswap eax
+}
+#   define BSWAP4(x)    _bswap4(x)
+#  endif
+# endif
+#endif
+#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT)
+# define GETU32(p)       BSWAP4(*(const u32 *)(p))
+# define PUTU32(p,v)     *(u32 *)(p) = BSWAP4(v)
+#else
+# define GETU32(p)       ((u32)(p)[0]<<24|(u32)(p)[1]<<16|(u32)(p)[2]<<8|(u32)(p)[3])
+# define PUTU32(p,v)     ((p)[0]=(u8)((v)>>24),(p)[1]=(u8)((v)>>16),(p)[2]=(u8)((v)>>8),(p)[3]=(u8)(v))
+#endif
+/*- GCM definitions */ typedef struct {
+	u64 hi, lo;
+} u128;
+
+#ifdef  TABLE_BITS
+# undef  TABLE_BITS
+#endif
+/*
+* Even though permitted values for TABLE_BITS are 8, 4 and 1, it should
+* never be set to 8 [or 1]. For further information see gcm128.c.
+*/
+#define TABLE_BITS 4
+
+struct gcm128_context {
+	/* Following 6 names follow names in GCM specification */
+	union {
+		u64 u[2];
+		u32 d[4];
+		u8 c[16];
+		size_t t[16 / sizeof(size_t)];
+	} Yi, EKi, EK0, len, Xi, H;
+	/*
+	* Relative position of Xi, H and pre-computed Htable is used in some
+	* assembler modules, i.e. don't change the order!
+	*/
+#if TABLE_BITS==8
+	u128 Htable[256];
+#else
+	u128 Htable[16];
+	void(*gmult) (u64 Xi[2], const u128 Htable[16]);
+	void(*ghash) (u64 Xi[2], const u128 Htable[16], const u8 *inp,
+		size_t len);
+#endif
+	unsigned int mres, ares;
+	block128_f block;
+	void *key;
+};
+
+struct xts128_context {
+	void *key1, *key2;
+	block128_f block1, block2;
+};
+
+struct ccm128_context {
+	union {
+		u64 u[2];
+		u8 c[16];
+	} nonce, cmac;
+	u64 blocks;
+	block128_f block;
+	void *key;
+};
+
+#ifndef OPENSSL_NO_OCB
+
+typedef union {
+	u64 a[2];
+	unsigned char c[16];
+} OCB_BLOCK;
+# define ocb_block16_xor(in1,in2,out) \
+    ( (out)->a[0]=(in1)->a[0]^(in2)->a[0], \
+      (out)->a[1]=(in1)->a[1]^(in2)->a[1] )
+# if STRICT_ALIGNMENT
+#  define ocb_block16_xor_misaligned(in1,in2,out) \
+    ocb_block_xor((in1)->c,(in2)->c,16,(out)->c)
+# else
+#  define ocb_block16_xor_misaligned ocb_block16_xor
+# endif
+
+struct ocb128_context {
+	/* Need both encrypt and decrypt key schedules for decryption */
+	block128_f encrypt;
+	block128_f decrypt;
+	void *keyenc;
+	void *keydec;
+	ocb128_f stream;    /* direction dependent */
+						/* Key dependent variables. Can be reused if key remains the same */
+	size_t l_index;
+	size_t max_l_index;
+	OCB_BLOCK l_star;
+	OCB_BLOCK l_dollar;
+	OCB_BLOCK *l;
+	/* Must be reset for each session */
+	u64 blocks_hashed;
+	u64 blocks_processed;
+	OCB_BLOCK tag;
+	OCB_BLOCK offset_aad;
+	OCB_BLOCK sum;
+	OCB_BLOCK offset;
+	OCB_BLOCK checksum;
+};
+#endif                          /* OPENSSL_NO_OCB */
+
+#endif /* AISINOSSL_MODES_LCL */
+
+#endif

+ 245 - 0
components/SM/include/rsa/rsa_cloud.h

@@ -0,0 +1,245 @@
+//
+// Created by bianq on 2017/9/11.
+//
+
+#ifndef AISINOSSL_RSA_CLOUD_H
+#define AISINOSSL_RSA_CLOUD_H
+
+#include <mbedtls/bignum.h>
+
+/**
+ * padding MBEDTLS_RSA_PKCS_V15
+ */
+
+#define MBEDTLS_ERR_RSA_CLOUD_SERVER_N_S_NULL                    -0x8080  /**< Bad input parameters to function  that server context n_S ==null. */
+#define MBEDTLS_ERR_RSA_CLOUD_BAD_INPUT_DATA                     -0X8100    /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_CLOUD_RSA_KEY_GEN_FAILED                     -0x8180  /**< Something failed during generation of a key. */
+#define MBEDTLS_ERR_CLOUD_RSA_KEY_SERVER_TRANSFORMATION_FAILED   -0x8200  /**< Something failed during verify mds. */
+#define MBEDTLS_ERR_CLOUD_RSA_KEY_SERVER_TRANSFORMATION_BAD_OUT   -0x8300  /**< out buffer too small. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * rand generater function
+ */
+typedef int (*f_rand)(void *, unsigned char *, size_t);
+
+/**
+ * public key
+ */
+typedef struct {
+	mbedtls_mpi N; /*!<  public modulus    */
+	mbedtls_mpi E; /*!<  public exponent   */
+} rsa_cloud_pk;
+
+/**
+ * private key
+ */
+typedef struct {
+	mbedtls_mpi N; /*!<  public modulus    */
+	mbedtls_mpi D; /*!<  private exponent  */
+} rsa_cloud_sk;
+
+/**
+ * rsa cloud context
+ */
+typedef struct {
+	int ver; /*!<  always 0          */
+	size_t len; /*!<  size(N) in chars  */
+	rsa_cloud_pk PK; /*!<  public  key        */
+	rsa_cloud_sk SK; /*!<  private  key       */
+	mbedtls_mpi P; /*!<  1st prime factor  */
+	mbedtls_mpi Q; /*!<  2nd prime factor  */
+
+} rsa_cloud_context;
+
+/**
+ * rsa cloud hsk context
+ */
+typedef struct {
+	mbedtls_mpi hd_A;
+	mbedtls_mpi hd_SA;
+	mbedtls_mpi n_A;
+
+} rsa_cloud_hsk_context;
+
+/**
+ * rsa cloud mds context
+ */
+typedef struct {
+	mbedtls_mpi q_;
+	mbedtls_mpi hd_SA;
+} rsa_cloud_mds_context;
+
+/**
+ * @brief               Initialization  the rsa context
+ *
+ * @param ctx           rsa context
+ */
+void rsa_cloud_init(rsa_cloud_context *ctx);
+
+/**
+ * @brief               free the rsa context
+ *
+ * @param ctx           rsa context
+ */
+void rsa_cloud_free(rsa_cloud_context *ctx);
+
+/**
+ * @brief               Initialization  the hsk context
+ *
+ * @param ctx           hsk context
+ */
+void rsa_cloud_hsk_init(rsa_cloud_hsk_context *ctx);
+
+/**
+ * @brief               free the hsk context
+ *
+ * @param ctx           hsk context
+ */
+void rsa_cloud_hsk_free(rsa_cloud_hsk_context *ctx);
+
+/**
+ * @brief               Initialization  the mds context
+ *
+ * @param ctx           mds context
+ */
+void rsa_cloud_mds_init(rsa_cloud_mds_context *ctx);
+
+/**
+ * @brief               free the mds context
+ *
+ * @param ctx           mds context
+ */
+void rsa_cloud_mds_free(rsa_cloud_mds_context *ctx);
+
+/**
+ * @brief               generate the server keypair
+ *
+ * @param ctx           server rsa context
+ *
+ * @param f_rng         rand function  (generate the q or p)
+ *
+ * @param p_rng         rand function param
+ *
+ * @param nbits         key size (note the size must bigger than 256 or be equal to 256)
+ *
+ * @param exponent      the e modulus
+ *
+ * @return              0 if successful
+ *                      otherwise a MBEDTLS_ERR_CLOUD_RSA_KEY_GEN_FAILED error code
+ */
+int
+rsa_cloud_gen_server_keypair(rsa_cloud_context *ctx, f_rand f_rng, void *p_rng,
+		unsigned int nbits, int exponent);
+/**
+ * @brief               generate the client keypair
+ *
+ * @param ctx           client rsa context
+ *
+ * @param pk_server     server public key
+ *
+ * @param f_rng         rand function  (generate the q or p)
+ *
+ * @param p_rng         rand function param
+ *
+ * @param nbits         key size (note the size must bigger than 256 or be equal to 256)
+ *
+ * @param exponent      the e modulus
+ *
+ * @return              0 if successful
+ *                      otherwise a MBEDTLS_ERR_CLOUD_RSA_KEY_GEN_FAILED,
+ *                      MBEDTLS_ERR_RSA_CLOUD_SERVER_N_S_NULL error code
+ */
+int rsa_cloud_gen_client_keypair(rsa_cloud_context *ctx,
+		const rsa_cloud_pk *pk_server, f_rand f_rng, void *p_rng,
+		unsigned int nbits, int exponent);
+/**
+ * @brief               generate a random number from 1 to range -1
+ *
+ * @param k             out,the random number
+ *
+ * @param range         random number range
+ *
+ *
+ * @return              0 if successful
+ *                      otherwise a MBEDTLS_ERR_MPI_ALLOC_FAILED error code
+ *                      if memory allocation failed
+ */
+int rsa_cloud_rand(mbedtls_mpi *k, const mbedtls_mpi *range);
+
+/**
+ * @brief               hide the key in client
+ *
+ * @param client        private key of client
+ *
+ * @param pk_server     public key of server
+ *
+ * @param hsk           out,hsk context
+ *
+ * @return              0 if successful
+ *                      otherwise a  MBEDTLS_ERR_MPI_XXX error code
+ */
+int
+rsa_cloud_key_hide(const rsa_cloud_sk *client, const rsa_cloud_pk *pk_server,
+		rsa_cloud_hsk_context *hsk);
+
+/**
+ * @brief               use hsk to encrypt the message and save to mds
+ *
+ * @param hsk           hsk context from key hide output
+ *
+ * @param message       the message
+ *
+ * @param msglen        message length
+ *
+ * @param mds           out,mds context
+ *
+ * @return              0 if successful
+ *                      otherwise a  MBEDTLS_ERR_MPI_XXX error code
+ */
+int rsa_cloud_md_sign(const rsa_cloud_hsk_context *hsk,const char *message,
+		size_t msglen, rsa_cloud_mds_context *mds);
+
+/**
+ * @brief               to verfiy mds in server
+ *
+ * @param client        public key of client
+ *
+ * @param server        private key of server
+ *
+ * @param mds           mds context
+ *
+ * @param message       the message
+ *
+ * @param msglen        message length
+ *
+ * @param out        	rsa signature
+ *
+ * @param outlen 	    out array length
+ *
+ * @param olen      	the signature byte length
+ *
+ * @return              0 if successful
+ *                      otherwise a MBEDTLS_ERR_CLOUD_RSA_KEY_SERVER_TRANSFORMATION_FAILED error code
+ */
+int rsa_cloud_transformation(const rsa_cloud_pk *client,
+		const rsa_cloud_sk *server, const rsa_cloud_mds_context *mds,
+		const char *message, size_t msglen, unsigned char *out,
+		size_t outlen, size_t *olen);
+/**
+ * @brief               just test and give a sample to show how to use the system
+ *
+ * @return              0 if successful
+ *                      otherwise is error
+ */
+#ifdef RSA_CLOUD_TEST
+int rsa_cloud_sefl_test_all();
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif //AISINOSSL_RSA_CLOUD_H

+ 376 - 0
components/SM/include/sm2/sm2.h

@@ -0,0 +1,376 @@
+//
+// Created by  lzj on 2017/8/15.
+//
+
+#ifndef LIBCRYPTO_SM2_H
+#define LIBCRYPTO_SM2_H
+
+#include <internal/ssl_random.h>
+#include <mbedtls/ecp.h>
+#include <stddef.h>
+
+
+/*
+ * sm2 Error codes
+ */
+#define MBEDTLS_ERR_SM2_BAD_INPUT_DATA                    -0x7080  /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_SM2_KEY_GEN_FAILED                    -0x7180  /**< Something failed during generation of a key. */
+#define MBEDTLS_ERR_SM2_KEY_CHECK_FAILED                  -0x7200  /**< Key failed to pass the library's validity check. */
+#define MBEDTLS_ERR_SM2_PUBLIC_FAILED                     -0x7280  /**< The public key operation failed. */
+#define MBEDTLS_ERR_SM2_PRIVATE_FAILED                    -0x7300  /**< The private key operation failed. */
+#define MBEDTLS_ERR_SM2_VERIFY_FAILED                     -0x7380  /**< The standard verification failed. */
+#define MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE                  -0x7400  /**< The output buffer for decryption is not large enough. */
+#define MBEDTLS_ERR_SM2_RNG_FAILED                        -0x7480  /**< The random generator failed to generate non-zeros. */
+#define MBEDTLS_ERR_SM2_ALLOC_FAILED                      -0x7500  /**< Failed to allocate memory. */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *
+ */
+typedef int (*get_rand_from_range)(mbedtls_mpi *k, mbedtls_mpi *range);
+
+/**
+ * \brief           sm2 context structure
+ */
+typedef struct {
+    mbedtls_ecp_group grp;      /*!<  elliptic curve used  group                 */
+    mbedtls_mpi d;              /*!<   secret value (private key)                */
+    mbedtls_ecp_point Pb;        /*!<   public value (public key)                 */
+} sm2_context;
+
+
+/**
+ * \brief           Initialize context set default group
+ *
+ * \param ctx       Context to initialize
+ *
+ * \return          0 if successful,
+ *                  MBEDTLS_ERR_MPI_XXX if initialization failed
+ *                  MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups
+ */
+int sm2_init(sm2_context *ctx);
+
+/**
+ * \brief           Free context
+ *
+ * \param ctx       Context to free
+ */
+void sm2_free(sm2_context *ctx);
+
+/**
+ * \brief           set private key by hex buf
+ *
+ * \param ctx       m2 context
+ *
+ * \param buf       private key hex buf
+ *
+ * \return          0 if successful,
+ *                  or a MBEDTLS_ERR_MPI_XXX error code.
+ */
+int sm2_read_string_private(sm2_context *ctx, const char *buf);
+
+/**
+ * \brief           set public key by hex buf of point
+ *
+ * \param ctx       m2 context
+ *
+ * \param x         point x hex buf
+ *
+ * \param y         point y hex buf
+ *
+ * \return          0 if successful,
+ *                  or a MBEDTLS_ERR_MPI_XXX error code.
+ */
+int sm2_read_string_public(sm2_context *ctx, const char *x, const char *y);
+
+/**
+ * \brief           Generate a  keypair.
+ *                  Raw function that only does the core computation.
+ *
+ * \param ctx       sm2 context (no-null)
+ *
+ * \param f_rng     RNG function  (generate the private key suggest the sm3 drbg)
+ *
+ * \param p_rng     RNG parameter
+ *
+ * \return          0 if successful,
+ *                  or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code
+ */
+int sm2_gen_keypair(sm2_context *ctx, int (*f_rng)(void *, unsigned char *, size_t),
+                    void *p_rng);
+
+/**
+ *
+ * \brief           set sm2 group by hex string param
+ *
+ * \param ctx       sm2 context
+ *
+ * \param p         p hex string buffer 64 word
+ *
+ * \param a         a hex string buffer 64 word
+ *
+ * \param b         b hex string buffer 64 word
+ *
+ * \param gx        gx hex string buffer 64 word
+ *
+ * \param gy        gy hex string buffer 64 word
+ *
+ * \param n         n hex string buffer 64 word
+ *
+ * \return          0 if successful, or a MBEDTLS_ERR_MPI_XXX error code
+ */
+int sm2_read_group_string(sm2_context *ctx, const char *p, const char *a, const char *b,
+                          const char *gx, const char *gy, const char *n);
+
+/**
+ * \brief           Check that an mbedtls_mpi is a valid private key for this curve
+ *
+ * \param ctx       sm2 context
+ *
+ * \return          0 if point is a valid private key,
+ *                  MBEDTLS_ERR_ECP_INVALID_KEY otherwise.
+ */
+int sm2_check_private(sm2_context *ctx);
+
+
+/**
+ * \brief           Check that an mbedtls_mpi_point is a valid public key for this curve
+ *
+ * \param ctx       sm2 context
+ *
+ * \return          0 if point is a valid private key,
+ *                  MBEDTLS_ERR_ECP_INVALID_KEY otherwise.
+ */
+int sm2_check_public(sm2_context *ctx);
+
+/**
+ * \brief           generate the message H(m`), with sm3;
+ *                  m` = Z || M
+ *
+ * \param ctx       sm2 context
+ *
+ * \param id        user id string
+ *
+ * \param idlen     id string length
+ *
+ * \param message   need digest message string
+ *
+ * \param msglen    message length
+ *
+ * \param out       result
+ *
+ * \return          0 if successful,otherwise
+ *                  MBEDTLS_ERR_SM2_ALLOC_FAILED,MBEDTLS_ERR_MPI_ALLOC_FAILED
+ *
+ */
+int sm2_z_generate(sm2_context *ctx, const char *id, size_t idlen, const char *message,
+                   size_t msglen, unsigned char *out);
+
+/**
+ * \brief           sm2 encrypt
+ *
+ * \param ctx       sm2 context
+ *
+ * \param buffer    bytes need to encrypt
+ *
+ * \param plen      string length
+ *
+ * \param out       cipher text in byte array (not hex string)
+ *
+ * \param max_out_len   out max length ,
+ *                  if the len smaller than olen the encrypt option will failed
+ *
+ * \param olen      the cipher length
+ *
+ * \param f_rng     RNG function
+ * \param p_rng     RNG parameter
+ *
+ * \return          0 if successful
+ *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
+ *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
+ *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
+ */
+int sm2_do_encrypt(sm2_context *ctx, const unsigned char *buffer, size_t plen,
+                   unsigned char *out, size_t max_out_len, size_t *olen,
+                   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
+
+/**
+ * \brief           sm2 decrypt
+ *
+ * \param ctx       sm2 context
+ *
+ * \param cipher    cipher text need to decrypt ;
+ *                  onte: the cipher are byte array ,them are not string
+ *                  if you input the string ,should transform the string to byte
+ *                  such as "120DEDF" is hex string, should make it to byte using the function you did
+ *                  hexString2byte.
+ *
+ * \param clen      the cipher byte length
+ *
+ * \param out       the message in byte (not hex string)
+ *
+ * \param max_out_len out max length ,
+ *                  if the len smaller than olen the decrypt option will failed
+ *
+ * \param olen      the out byte length
+ *
+ * \return          0 if successful
+ *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
+ *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
+ *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
+ */
+int sm2_do_decrypt(sm2_context *ctx, const unsigned char *cipher, size_t clen,
+                   unsigned char *out, size_t max_out_len, size_t *olen);
+
+
+/**
+ * \brief           sm2 sign byte (e)
+ *
+ * \param ctx       sm2 context
+ *
+ * \param dgst      the e in byte  (e = H(m))
+ *
+ * \param dgstlen   e length ,commonly is 32, that meaning 256 bits
+ *
+ * \param out       the (r,s) byte array ,which format is r||s. 64 word
+ *
+ * \param max_out_len out max length ,
+ *                  if the len smaller than olen the sign option will failed
+ *
+ * \param olen      the out byte array length commonly is 64 word
+ *
+ * \param f_rng     RNG function
+ * \param p_rng     RNG parameter
+ *
+ * \return          0 if successful
+ *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
+ *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
+ *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
+ */
+int sm2_do_sign(sm2_context *ctx, const unsigned char *dgst, size_t dgstlen,
+                unsigned char *out, size_t max_out_len, size_t *olen,
+                int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
+
+/**
+ * \brief           sm2 sign
+ *
+ * \param ctx       sm2 context
+ *
+ * \param id        user id such as user mail string
+ *
+ * \param idlen     id string length
+ *
+ * \param message   need sign message string
+ *
+ * \param msglen    message length
+ *
+ * \param out       the (r,s) byte array ,which format is r||s. 64 word
+ *
+ * \param max_out_len out max length ,
+ *                  if the len smaller than olen the sign option will failed
+ *
+ * \param olen      the out byte array length commonly is 64 word
+ *
+ * \param f_rng     RNG function
+ * \param p_rng     RNG parameter
+ *
+ * \return          0 if successful
+ *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
+ *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
+ *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
+ */
+int sm2_do_id_sign(sm2_context *ctx, const char *id, size_t idlen, const char *message,
+                   size_t msglen, unsigned char *out, size_t max_out_len, size_t *olen,
+                   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
+
+/**
+ *
+ * \brief           sm2 sign verify byte (e)
+ *
+ * \param ctx       sm2 context
+ *
+ * \param message   the e in byte  (e = H(m))
+ *
+ * \param msglen    e length ,commonly is 32 that meaning 256 bite
+ *
+ * \param dgst      need to verify byte array (not hex string)
+ *                  onte: the buff are byte array ,them are not string
+ *                  if you input the string ,should transform the string to byte
+ *                  such as "120DEDF" is hex string, should make it to byte using the function you did
+ *                  hexString2byte.
+ *
+ * \param dgstlen   dgst byte array length
+ *
+ * \return          0 if successful
+ *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
+ *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
+ *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
+ */
+int sm2_do_verify(sm2_context *ctx, const unsigned char *message, size_t msglen,
+                  const unsigned char *dgst, size_t dgstlen);
+
+/**
+ *
+ * \brief           sm2 sign verify
+ *
+ * \param ctx       sm2 context
+ *
+ * \param id        user id such as user mail string
+ *
+ * \param idlen     id string length
+ *
+ * \param message   received message string
+ *
+ * \param msglen    messgae string length
+ *
+ * \param dgst      need to verify byte array (not hex string)
+ *                  onte: the buff are byte array ,them are not string
+ *                  if you input the string ,should transform the string to byte
+ *                  such as "120DEDF" is hex string, should make it to byte using the function you did
+ *                  hexString2byte.
+ *
+ * \param dgstlen   dgst byte array length
+ *
+ * \return          0 if successful
+ *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
+ *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
+ *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
+ */
+
+int sm2_do_id_verify(sm2_context *ctx, const char *id, size_t idlen, const char *message,
+                     size_t msglen, const unsigned char *dgst, size_t dgstlen);
+
+/**
+ * \brief           sm2 context copy
+ *
+ * \param dst       dst sm2 context
+ *
+ * \param src       const src sm2 context
+ *
+ * \return         0 if successful
+ *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
+ *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
+ *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
+ */
+int sm2_copy(sm2_context *dst, const sm2_context *src);
+
+/**
+ * \brief           sm2 test
+ *
+ * \param verbose   0 is nothing ;
+ *                  1 is test encrypt and decrypt;
+ *                  2 is test sign and verify
+ *
+ * @return          0 if successful
+ */
+int mbedtls_sm2_self_test(int verbose);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //LIBCRYPTO_SM2_H

+ 115 - 0
components/SM/include/sm3/sm3.h

@@ -0,0 +1,115 @@
+/**
+ *
+ *
+ * \file        sm3.h
+ *
+ * \brief       this file is header file for sm3(chinese business Digital Digest).
+ *              and  compatible md framework.
+ *
+ * \anchor      lzj
+ *
+ * \date        2017/8/14
+ *
+ *
+ */
+
+
+#ifndef LIBCRYPTO_SM3_H
+#define LIBCRYPTO_SM3_H
+
+
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          SM3 context structure
+ */
+typedef struct {
+    uint32_t total[2];          /*!< number of bytes processed  */
+    uint32_t state[8];          /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+} sm3_context;
+
+
+/**
+ * \brief          Initialize SM3 context
+ *
+ * \param ctx      SM3 context to be initialized
+ */
+void sm3_init(sm3_context *ctx);
+
+/**
+ * \brief          Clear SM3 context
+ *
+ * \param ctx      SM3 context to be cleared
+ */
+void sm3_free(sm3_context *ctx);
+
+/**
+ * \brief          Clone (the state of) a SM3 context
+ *
+ * \param dst      The destination context
+ * \param src      The context to be cloned
+ */
+void sm3_clone(sm3_context *dst, const sm3_context *src);
+
+
+/**
+ * \brief          SM3 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void sm3_starts( sm3_context *ctx );
+
+
+/**
+ * \brief          SM3 process buffer
+ *
+ * \param ctx      SM3 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sm3_update(sm3_context *ctx, const unsigned char *input,
+                size_t ilen);
+
+/**
+ * \brief          SM3 final digest
+ *
+ * \param ctx      SM3 context
+ * \param output   SM3 checksum result
+ */
+void sm3_finish(sm3_context *ctx, unsigned char output[32]);
+
+/* Internal use */
+void sm3_process(sm3_context *ctx, const unsigned char block[64]);
+
+/**
+ * \brief          Output = SM3( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SM3 checksum result
+ */
+void sm3(const unsigned char *input, size_t ilen,
+         unsigned char output[32]);
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int sm3_self_test(int verbose);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif //LIBCRYPTO_SM3_H

+ 379 - 0
components/SM/include/sm4/sm4.h

@@ -0,0 +1,379 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#ifndef HEADER_SM4_H
+#define HEADER_SM4_H
+
+// #include <openssl/opensslconf.h>
+#ifndef NO_GMSSL
+
+# define SM4_ENCRYPT     1
+# define SM4_DECRYPT     0
+
+#define SM4_KEY_LENGTH		16
+#define SM4_BLOCK_SIZE		16
+#define SM4_IV_LENGTH		(SM4_BLOCK_SIZE)
+#define SM4_NUM_ROUNDS		32
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <openssl/modes.h>
+#include "stdlib.h"
+#include "stdio.h"
+
+//#define SIMPLE_EXTERNAL_ENCODINGS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct sm4_key_t {
+	uint32_t rk[SM4_NUM_ROUNDS];
+#ifdef SIMPLE_EXTERNAL_ENCODINGS
+    uint8_t G[SM4_NUM_ROUNDS+1][256];
+    uint8_t F[SM4_NUM_ROUNDS+1][256];
+#endif //SIMPLE_EXTERNAL_ENCODINGS
+} sm4_key_t;
+
+typedef struct sm4_key_t SM4_KEY;
+
+/**
+ sm4_set_encrypt_key
+
+ @param key SM4_KEY
+ @param user_key key
+ */
+void sm4_set_encrypt_key(sm4_key_t *key, const unsigned char *user_key);
+
+/**
+ sm4_set_decrypt_key
+
+ @param key SM4_KEY
+ @param user_key key
+ */
+void sm4_set_decrypt_key(sm4_key_t *key, const unsigned char *user_key);
+
+/**
+ sm4_encrypt
+
+ @param in in
+ @param out out
+ @param key SM4_KEY
+ */
+void sm4_encrypt(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
+#define sm4_decrypt(in,out,key)  sm4_encrypt(in,out,key)
+
+/**
+ sm4_encrypt_init
+
+ @param key SM4_KEY
+ */
+void sm4_encrypt_init(sm4_key_t *key);
+void sm4_encrypt_8blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
+void sm4_encrypt_16blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
+
+/**
+ sm4_ecb_encrypt
+
+ @param in in
+ @param out out
+ @param key key
+ @param enc 1 to SM4_ENCRYPT, 0 to SM4_DECRYPT
+ */
+void sm4_ecb_encrypt(const unsigned char *in, unsigned char *out,
+	const sm4_key_t *key, int enc);
+
+/**
+ sm4_cbc_encrypt
+
+ @param in in
+ @param out out
+ @param len byte size of in
+ @param key key
+ @param iv iv
+ @param enc 1 to SM4_ENCRYPT, 0 to SM4_DECRYPT
+ */
+void sm4_cbc_encrypt(const unsigned char *in, unsigned char *out,
+	size_t len, const sm4_key_t *key, unsigned char *iv, int enc);
+void sm4_cfb128_encrypt(const unsigned char *in, unsigned char *out,
+	size_t len, const sm4_key_t *key, unsigned char *iv, int *num, int enc);
+void sm4_ofb128_encrypt(const unsigned char *in, unsigned char *out,
+	size_t len, const sm4_key_t *key, unsigned char *iv, int *num);
+/**
+ sm4_ctr128_encrypt
+ The input encrypted as though 128bit counter mode is being used.  The
+ extra state information to record how much of the 128bit block we have
+ used is contained in *num, and the encrypted counter is kept in
+ ecount_buf.  Both *num and ecount_buf must be initialised with zeros
+ before the first call to sm4_ctr128_encrypt(). This algorithm assumes
+ that the counter is in the x lower bits of the IV (ivec), and that the
+ application has full control over overflow and the rest of the IV.  This
+ implementation takes NO responsibility for checking that the counter
+ doesn't overflow into the rest of the IV when incremented.
+
+ @param in in
+ @param out out
+ @param len byte size of in
+ @param key key
+ @param iv iv
+ @param ecount_buf extra state, must be initialised with zeros before the first call
+ @param num extra state, must be initialised with zeros before the first call
+ */
+void sm4_ctr128_encrypt(const unsigned char *in, unsigned char *out,
+	size_t len, const sm4_key_t *key, unsigned char *iv,
+	unsigned char ecount_buf[SM4_BLOCK_SIZE], unsigned int *num);
+
+/**
+ sm4_wrap_key
+
+ @param key key
+ @param iv iv
+ @param out out
+ @param in in
+ @param inlen byte size of in
+ @return 1 to successful, otherwise fault
+ */
+int sm4_wrap_key(sm4_key_t *key, const unsigned char *iv,
+	unsigned char *out, const unsigned char *in, unsigned int inlen);
+/**
+ sm4_unwrap_key
+
+ @param key key
+ @param iv iv
+ @param out out
+ @param in in
+ @param inlen byte size of in
+ @return 1 to successful, otherwise fault
+ */
+int sm4_unwrap_key(sm4_key_t *key, const unsigned char *iv,
+	unsigned char *out, const unsigned char *in, unsigned int inlen);
+
+typedef GCM128_CONTEXT SM4_GCM128_CONTEXT;
+
+/**
+ sm4_gcm128_init
+
+ @param ctx SM4_GCM128_CONTEXT
+ @param key SM4_KEY
+ */
+void sm4_gcm128_init(SM4_GCM128_CONTEXT *ctx, SM4_KEY *key);
+
+/**
+ sm4_gcm128_setiv
+
+ @param ctx SM4_GCM128_CONTEXT
+ @param ivec iv
+ @param len byte size of iv
+ */
+void sm4_gcm128_setiv(SM4_GCM128_CONTEXT *ctx, const unsigned char *ivec,
+                      size_t len);
+
+/**
+ addition message of gcm
+
+ @param ctx SM4_GCM128_CONTEXT
+ @param aad addition message
+ @param len byte size of aad
+ @return 1 to successful, otherwises fault
+ */
+int sm4_gcm128_aad(SM4_GCM128_CONTEXT *ctx, const unsigned char *aad,
+                    size_t len);
+
+/**
+ sm4_gcm128_encrypt
+
+ @param in in
+ @param out out
+ @param length byte size of in
+ @param ctx SM4_GCM128_CONTEXT
+ @param enc 1 to SM4_ENCRYPT, 0 to SM4_DECRYPT
+ @return 1 to successful, otherwises fault
+ */
+int sm4_gcm128_encrypt(const unsigned char *in, unsigned char *out,
+                        size_t length, SM4_GCM128_CONTEXT *ctx, const int enc);
+
+/**
+ get tag of sm4_gcm128
+
+ @param ctx SM4_GCM128_CONTEXT
+ @param tag memory for storage tag
+ @param len byte size of tag
+ */
+void sm4_gcm128_tag(SM4_GCM128_CONTEXT *ctx, unsigned char *tag,
+                    size_t len);
+
+/**
+ sm4_gcm128_finish
+
+ @param ctx SM4_GCM128_CONTEXT
+ @param tag memory for storage tag
+ @param len byte size of tag
+ @return 1 to successful, otherwises fault
+ */
+int sm4_gcm128_finish(SM4_GCM128_CONTEXT *ctx, const unsigned char *tag,
+                      size_t len);
+
+/**
+ release SM4_GCM128_CONTEXT
+
+ @param ctx SM4_GCM128_CONTEXT
+ */
+void sm4_gcm128_release(SM4_GCM128_CONTEXT *ctx);
+
+/*
+void sm4_avx2_encrypt_init(sm4_key_t *key);
+void sm4_avx2_encrypt_8blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
+void sm4_avx2_encrypt_16blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
+
+void sm4_knc_encrypt_init(sm4_key_t *key);
+void sm4_knc_encrypt_8blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
+void sm4_knc_encrypt_16blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
+
+#define SM4_EDE_KEY_LENGTH	32
+
+typedef struct {
+	sm4_key_t k1;
+	sm4_key_t k2;
+} sm4_ede_key_t;
+
+void sm4_ede_set_encrypt_key(sm4_ede_key_t *key, const unsigned char *user_key);
+void sm4_ede_set_decrypt_key(sm4_ede_key_t *key, const unsigned char *user_key);
+void sm4_ede_encrypt(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
+void sm4_ede_encrypt_8blocks(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
+void sm4_ede_encrypt_16blocks(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
+void sm4_ede_decrypt(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
+void sm4_ede_decrypt_8blocks(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
+void sm4_ede_decrypt_16blocks(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
+*/
+
+/**
+ * sm4 gcm file context
+ */
+typedef gcmf_context sm4_gcmf_context;
+
+/**
+ * init the sm4 gcm file context
+ *
+ * @param  ctx [in]		gcm file context
+ *
+ * @param  sm4_key [in]		sm4 key
+ *
+ * @return     [flag]		if successful o,otherwise failed
+ */
+int sm4_gcmf_init(sm4_gcmf_context *ctx, const SM4_KEY *sm4_key);
+
+/**
+ * gcm file context free
+ *
+ * @param  ctx [in]		gcm file context
+ *
+ * @return     [flag]		if successful o,otherwise failed
+ */
+int sm4_gcmf_free(sm4_gcmf_context *ctx);
+
+/**
+ * set sm4 iv param
+ *
+ * @param  ctx [in]		gcm file context
+ *
+ * @param  iv  [iv]		iv array
+ *
+ * @param  len [in]		iv array length
+ *
+ * @return     [flag]		if successful o,otherwise failed
+ */
+int sm4_gcmf_set_iv(sm4_gcmf_context *ctx, const unsigned char * iv, size_t len);
+
+
+/**
+ * encrypte file
+ *
+ * @param  ctx      [in]		gcm file context
+ *
+ * @param  infpath  [in]		plaintext file input path
+ *
+ * @param  outfpath [in]		cipher file output path
+ *
+ * @return          [fage]		if successful o,otherwise failed
+ */
+int sm4_gcmf_encrypt_file(sm4_gcmf_context * ctx, char *infpath, char *outfpath);
+
+
+/**
+ * decrypt file
+ *
+ * @param  ctx      [in]		gcm file context
+ *
+ * @param  infpath  [in]		cipher file input path
+ *
+ * @param  outfpath [in]		plaintext file output path
+ *
+ * @return          [flag]		if successful o,otherwise failed
+ */
+int sm4_gcmf_decrypt_file(sm4_gcmf_context * ctx, char *infpath, char *outfpath);
+
+//same as fucntion rfc3686_init
+//4Bytes nounce + 8bytes iv + 4bytes counter
+void sm4_ctr128_ctr_init(unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16]);
+
+///* increment counter (128-bit int) by 1 */
+void sm4_ctr128_ctr_inc(unsigned char *counter);
+
+/* decrement counter (128-bit int) by 1 */
+void sm4_ctr128_ctr_dec(unsigned char *counter);
+
+void sm4_ctr128_subctr(unsigned char *counter, const unsigned char *in, unsigned char *out,
+                        size_t length, const SM4_KEY *key);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif

+ 55 - 0
components/SM/src/internal/openssl_aid.c

@@ -0,0 +1,55 @@
+#include <internal/openssl_aid.h>
+#include <stdio.h>
+/*
+ * Pointer to memset is volatile so that compiler must de-reference
+ * the pointer and can't assume that it points to any function in
+ * particular (such as memset, which it then might further "optimize")
+ */
+typedef void *(*memset_t)(void *, int, size_t);
+
+static volatile memset_t memset_func = memset;
+
+void OPENSSL_cleanse(void *ptr, size_t len)
+{
+    memset_func(ptr, 0, len);
+}
+
+int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len)
+{
+    size_t i;
+    const volatile unsigned char *a = in_a;
+    const volatile unsigned char *b = in_b;
+    unsigned char x = 0;
+
+    for (i = 0; i < len; i++)
+        x |= a[i] ^ b[i];
+
+    return x;
+}
+
+void CRYPTO_free(void *str, const char *file, int line)
+{
+    printf("%s %d \n", file, line);
+    free(str);
+}
+
+void CRYPTO_clear_free(void *str, size_t num, const char *file, int line)
+{
+
+    if (str == NULL)
+        return;
+    if (num)
+        OPENSSL_cleanse(str, num);
+    CRYPTO_free(str, file, line);
+}
+
+void *CRYPTO_malloc(size_t num, const char *file, int line)
+{
+    void *ret = NULL;
+    if (num == 0)
+        return NULL;
+    printf("%s %d \n", file, line);
+    ret = malloc(num);
+
+    return ret;
+}

+ 416 - 0
components/SM/src/internal/ssl_random.c

@@ -0,0 +1,416 @@
+/*
+ * @Author: Weijie Li
+ * @Date: 2017-11-02 10:32:40
+ * @Last Modified by: Peiran Luo
+ * @Last Modified time: 2018-04-11 15:00:00
+ */
+
+#include <stdbool.h>
+#include <internal/ssl_random.h>
+#include <sm3/sm3.h>
+
+#if defined(ANDROID_VER) && defined(_DEBUG_)
+#include <android/log.h>
+#define LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "SSL_RANDOM", __VA_ARGS__)
+#else
+#define LOG(...)
+#endif
+
+//  Windows
+#ifdef _WIN32
+
+#include <intrin.h>
+uint64_t rdtsc()
+{
+	return __rdtsc();
+}
+
+//  Linux/GCC
+#else
+
+#ifdef ENABLE_RDTSC
+uint64_t rdtsc()
+{
+	unsigned int lo, hi;
+	__asm__ __volatile__("rdtsc"
+						 : "=a"(lo), "=d"(hi));
+	return ((uint64_t)hi << 32) | lo;
+}
+#endif
+
+#endif
+
+// Android
+#ifdef ANDROID_VER
+
+#ifdef ENABLE_SEED_ANDROID_SENSOR
+ASensorEventQueue *sensor_event_queue_;
+ASensorVector gravityData;
+
+int getAndroidSensorData(int fd, int events, void *data)
+{
+	ASensorEvent event;
+	while (sensor_event_queue_ && ASensorEventQueue_getEvents(sensor_event_queue_, &event, 1) > 0)
+	{
+		memcpy(&gravityData, &event.acceleration, sizeof(gravityData));
+		LOG("SENSOR: %f %f %f", gravityData.x, gravityData.y, gravityData.z);
+		break;
+	}
+	return 1;
+}
+#endif // END ENABLE_SEED_ANDROID_SENSOR
+
+#endif // END ANDROID_VER
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#if TARGET_OS_IOS == 1
+#include <objc/runtime.h>
+#include <objc/objc.h>
+#include <objc/message.h>
+#include <unistd.h>
+
+typedef struct
+{
+	double x;
+	double y;
+	double z;
+} PP;
+
+BOOL (*msgSend_bool)
+(id, SEL) = (BOOL(*)(id, SEL))objc_msgSend;
+
+#if defined(__arm64__)
+PP (*msgSend_pp)
+(id, SEL) = (PP(*)(id, SEL))objc_msgSend;
+#else
+PP (*msgSend_pp)
+(id, SEL) = (PP(*)(id, SEL))objc_msgSend_stret;
+#endif
+
+#endif
+
+#if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__) || defined(ANDROID_VER)
+static int read_file(const char *filename, unsigned char *buf, int size)
+{
+	FILE *fd = NULL;
+	int ret = 0;
+	fd = fopen(filename, "rb");
+	if (fd)
+	{
+		ret = fread(buf, size, 1, fd);
+		fclose(fd);
+	}
+	return ret;
+}
+#endif
+
+int ssl_random_init(ssl_random_context *ctx)
+{
+	// 0. Set MD Info
+	int ret;
+	ctx->md_info = mbedtls_md_info_from_type(RANDOM_HASH_ALGORITHM);
+	if (ctx->md_info == NULL)
+	{
+		return SSL_RANDOM_ERROR_HASH_ALGO_NOT_FOUND;
+	}
+
+	// 1. Init and Setup MD
+	ctx->md_ctx = (mbedtls_md_context_t *)malloc(sizeof(mbedtls_md_context_t));
+	mbedtls_md_init(ctx->md_ctx);
+
+	ret = mbedtls_md_setup(ctx->md_ctx, ctx->md_info, 0);
+	if (ret != 0)
+		return ret;
+
+	// 2. Init HMAC-DRBG
+	ctx->drbg_ctx = (mbedtls_hmac_drbg_context *)malloc(sizeof(mbedtls_hmac_drbg_context));
+	mbedtls_hmac_drbg_init(ctx->drbg_ctx);
+
+	// 3. Init Hash Buffer
+	ctx->hashLen = mbedtls_md_get_size(ctx->md_info);
+	ctx->hash = (unsigned char *)malloc(ctx->hashLen);
+	memset(ctx->hash, 0, ctx->hashLen);
+
+
+
+	// 4. Set isInitial
+	ctx->isInitial = 1;
+
+	return 0;
+}
+
+int ssl_random_seed(void *rand_ctx, unsigned char *seed_buf, size_t buf_size)
+{
+	return ssl_random_seed_with_option(rand_ctx, seed_buf, buf_size, 0);
+}
+
+int ssl_random_seed_with_option(void *rand_ctx, unsigned char *seed_buf, size_t buf_size, int options)
+{
+	int ret;
+	ssl_random_context *ctx = (ssl_random_context *)rand_ctx;
+	if (ctx->isInitial != 1)
+		return SSL_RANDOM_ERROR_NOT_INITIAL;
+
+	
+
+
+	// 0. Init MD
+	mbedtls_md_init(ctx->md_ctx);
+
+	ret = mbedtls_md_setup(ctx->md_ctx, ctx->md_info, 0);
+	if (ret)
+		return ret;
+
+	// 1. Set time() as seed
+	// General
+	if ((options & SSL_RANDOM_DISABLE_TIME) == 0)
+	{
+		time_t t = time(NULL);
+		mbedtls_md_update(ctx->md_ctx, (const unsigned char *)&t, sizeof(t));
+	}
+
+// 2. Set /dev/urandom as seed
+// FOR Linux/Unix
+#if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__) || defined(ANDROID_VER)
+	if ((options & SSL_RANDOM_DISABLE_URANDOM) == 0)
+	{
+		unsigned char urandomBuf[1024];
+
+		ret = read_file("/dev/urandom", urandomBuf, sizeof(urandomBuf));
+		if (ret)
+		{
+			mbedtls_md_update(ctx->md_ctx, urandomBuf, sizeof(urandomBuf));
+		}
+		LOG("URANDOM: %d ", ret);
+	}
+#endif
+
+// 3. Set CPU Cycle Count
+// FOR Windows
+#if defined(_WIN32)
+	if ((options & SSL_RANDOM_DISABLE_CPU_CYCLE) == 0)
+	{
+		unsigned long long cpuCycle = rdtsc();
+		mbedtls_md_update(ctx->md_ctx, (const unsigned char *)&cpuCycle, sizeof(cpuCycle));
+	}
+#endif
+
+// 4. Set rand_s
+// FOR Windows
+#if defined(_WIN32) && defined(_CRT_RAND_S)
+	if ((options & SSL_RANDOM_DISABLE_RAND_S) == 0)
+	{
+		int i;
+		unsigned int tmp;
+		for (i = 0; i < 5; i++)
+		{
+			if (rand_s(&tmp) != 0)
+				goto skipRandS;
+			mbedtls_md_update(ctx->md_ctx, (const unsigned char *)&tmp, sizeof(tmp));
+		}
+	}
+skipRandS:
+#endif
+
+// 5. Set Android Hardware Info
+#ifdef ANDROID_VER
+	if ((options & AISINOSSL_RANDOM_DISABLE_ANDROID_INFO) == 0)
+	{
+		char buf[PROP_VALUE_MAX];
+
+		__system_property_get("ro.build.version.release", buf);
+		mbedtls_md_update(ctx->md_ctx, (const unsigned char *)buf, strlen(buf));
+
+		__system_property_get("ro.hardware", buf);
+		mbedtls_md_update(ctx->md_ctx, (const unsigned char *)buf, strlen(buf));
+
+		__system_property_get("ro.serialno", buf);
+		mbedtls_md_update(ctx->md_ctx, (const unsigned char *)buf, strlen(buf));
+	}
+#endif // END ANDROID_VER
+
+// 6. Set Android sensor data as seed
+#if defined(ANDROID_VER) && defined(ENABLE_SEED_ANDROID_SENSOR)
+	if ((options & AISINOSSL_RANDOM_DISABLE_ANDROID_SENSOR) == 0)
+	{
+		mbedtls_md_update(ctx->md_ctx, (const unsigned char *)&gravityData, sizeof(gravityData));
+	}
+#endif // END defined(ANDROID_VER) && defined(ENABLE_SEED_ANDROID_SENSOR)
+
+#if defined(ENABLE_SEED_IOS_SENSOR) && TARGET_OS_IOS == 1
+
+	Class CMMotionManager = objc_getClass("CMMotionManager");
+	if (CMMotionManager)
+	{
+
+		SEL sel = sel_registerName("init");
+		id motionManager = class_createInstance(CMMotionManager, 0);
+		motionManager = objc_msgSend(motionManager, sel);
+
+		//acceleration
+		BOOL isAccelerometerAvailable = msgSend_bool(motionManager, sel_registerName("isAccelerometerAvailable"));
+		if (isAccelerometerAvailable)
+		{
+			objc_msgSend(motionManager, sel_registerName("startAccelerometerUpdates"));
+
+			BOOL isAccelerometerActive = NO;
+			while (!isAccelerometerActive)
+			{
+				isAccelerometerActive = msgSend_bool(motionManager, sel_registerName("isAccelerometerActive"));
+				sleep(1);
+			}
+			id accelerometerData = NULL;
+			while (!accelerometerData)
+				accelerometerData = objc_msgSend(motionManager, sel_registerName("accelerometerData"));
+			PP acceleration;
+			acceleration = msgSend_pp(accelerometerData, sel_registerName("acceleration"));
+			mbedtls_md_update(ctx->md_ctx, (const unsigned char *)&acceleration, sizeof(acceleration));
+#if defined(DEBUG)
+			printf("acceleration x:%lf y:%lf z:%lf\n", acceleration.x, acceleration.y, acceleration.z);
+#endif
+			objc_msgSend(motionManager, sel_registerName("stopAccelerometerUpdates"));
+		}
+
+		//rotation
+		BOOL isGyroAvailable = msgSend_bool(motionManager, sel_registerName("isGyroAvailable"));
+		if (isGyroAvailable)
+		{
+			objc_msgSend(motionManager, sel_registerName("startGyroUpdates"));
+			BOOL isGyroActive = NO;
+			while (!isGyroActive)
+			{
+				isGyroActive = msgSend_bool(motionManager, sel_registerName("isGyroActive"));
+				sleep(1);
+			}
+			id gyroData = NULL;
+			while (!gyroData)
+				gyroData = objc_msgSend(motionManager, sel_registerName("gyroData"));
+			PP rotationRate;
+			rotationRate = msgSend_pp(gyroData, sel_registerName("rotationRate"));
+			mbedtls_md_update(ctx->md_ctx, (const unsigned char *)&rotationRate, sizeof(rotationRate));
+#if defined(DEBUG)
+			printf("rotation x:%lf y:%lf z:%lf\n", rotationRate.x, rotationRate.y, rotationRate.z);
+#endif
+			objc_msgSend(motionManager, sel_registerName("stopGyroUpdates"));
+		}
+
+		//magnetic
+		BOOL isMagnetometerAvailable = msgSend_bool(motionManager, sel_registerName("isMagnetometerAvailable"));
+		if (isMagnetometerAvailable)
+		{
+			objc_msgSend(motionManager, sel_registerName("startMagnetometerUpdates"));
+			bool isMagnetometerActive = NO;
+			while (!isMagnetometerActive)
+			{
+				isMagnetometerActive = msgSend_bool(motionManager, sel_registerName("isMagnetometerActive"));
+				sleep(1);
+			}
+			id magnetometerData = NULL;
+			while (!magnetometerData)
+				magnetometerData = objc_msgSend(motionManager, sel_registerName("magnetometerData"));
+			PP magneticField;
+			magneticField = msgSend_pp(magnetometerData, sel_registerName("magneticField"));
+			mbedtls_md_update(ctx->md_ctx, (const unsigned char *)&magneticField, sizeof(magneticField));
+#if defined(DEBUG)
+			printf("magnetic x:%lf y:%lf z:%lf\n", magneticField.x, magneticField.y, magneticField.z);
+#endif
+			objc_msgSend(motionManager, sel_registerName("stopMagnetometerUpdates"));
+		}
+	}
+#endif
+
+	// Set Additional message
+	if (buf_size > 0 && seed_buf != NULL)
+	{
+		mbedtls_md_update(ctx->md_ctx, seed_buf, buf_size);
+	}
+
+	// Last, Finish hash
+	ret = mbedtls_md_finish(ctx->md_ctx, ctx->hash);
+	if (ret)
+		return ret;
+
+	// Set seed
+	mbedtls_hmac_drbg_seed_buf(ctx->drbg_ctx, ctx->md_info, ctx->hash, ctx->hashLen);
+
+	// Clear Seed Message
+	memset(ctx->hash, 0, ctx->hashLen);
+
+	ctx->isSeeded = 1;
+
+	return 0;
+}
+
+int ssl_random_rand(void *rand_ctx, unsigned char *output, size_t size)
+{
+	int ret;
+	ssl_random_context *ctx = (ssl_random_context *)rand_ctx;
+	if (ctx->isSeeded != 1)
+		return SSL_RANDOM_ERROR_NOT_SEEDED;
+
+	 ret = mbedtls_hmac_drbg_random(ctx->drbg_ctx, output, size);
+	switch (ret)
+	{
+	case MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG:
+		return SSL_RANDOM_ERROR_OUT_SIZE_TO_LARGE;
+	default:
+		return ret;
+	}
+}
+
+int ssl_random_rand_int_array(ssl_random_context *ctx, int *output, int count)
+{
+	return ssl_random_rand(ctx, (unsigned char *)output, count * sizeof(int));
+}
+
+int ssl_random_rand_uint_array(ssl_random_context *ctx, unsigned int *output, int count)
+{
+	return ssl_random_rand(ctx, (unsigned char *)output, count * sizeof(unsigned int));
+}
+
+void ssl_random_free(ssl_random_context *ctx)
+{
+	if (ctx->isInitial != 1)
+		return;
+
+	mbedtls_md_free(ctx->md_ctx);
+	free(ctx->md_ctx);
+
+	mbedtls_hmac_drbg_free(ctx->drbg_ctx);
+	free(ctx->drbg_ctx);
+
+	free(ctx->hash);
+
+
+	ctx->isInitial = 0;
+	ctx->isSeeded = 0;
+}
+
+int ssl_random_shuffle_u8(u8 *list, int len)
+{
+	unsigned int *randNumbers;
+
+	if (len <= 0)
+		return SSL_RANDOM_ERROR_INVLIAD_SIZE;
+	randNumbers = (unsigned int *)malloc((len + 10) * sizeof(unsigned int));
+
+	ssl_random_rand_int_array(NULL, (int *)randNumbers, len);
+
+	while (len > 0)
+	{
+		int r;
+		u8 tmp;
+		r = randNumbers[len] % len;
+		len--;
+		tmp = *(list + len);
+		*(list + len) = *(list + r);
+		*(list + r) = tmp;
+	}
+
+	free(randNumbers);
+	return 0;
+}
+

+ 154 - 0
components/SM/src/modes/cbc128.c

@@ -0,0 +1,154 @@
+/*
+ * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "modes_lcl.h"
+#include <string.h>
+
+#if !defined(STRICT_ALIGNMENT) && !defined(PEDANTIC)
+# define STRICT_ALIGNMENT 0
+#endif
+
+void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16], block128_f block)
+{
+    size_t n;
+    const unsigned char *iv = ivec;
+
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+    if (STRICT_ALIGNMENT &&
+        ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+        while (len >= 16) {
+            for (n = 0; n < 16; ++n)
+                out[n] = in[n] ^ iv[n];
+            (*block) (out, out, key);
+            iv = out;
+            len -= 16;
+            in += 16;
+            out += 16;
+        }
+    } else {
+        while (len >= 16) {
+            for (n = 0; n < 16; n += sizeof(size_t))
+                *(size_t *)(out + n) =
+                    *(size_t *)(in + n) ^ *(size_t *)(iv + n);
+            (*block) (out, out, key);
+            iv = out;
+            len -= 16;
+            in += 16;
+            out += 16;
+        }
+    }
+#endif
+    while (len) {
+        for (n = 0; n < 16 && n < len; ++n)
+            out[n] = in[n] ^ iv[n];
+        for (; n < 16; ++n)
+            out[n] = iv[n];
+        (*block) (out, out, key);
+        iv = out;
+        if (len <= 16)
+            break;
+        len -= 16;
+        in += 16;
+        out += 16;
+    }
+    memcpy(ivec, iv, 16);
+}
+
+void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16], block128_f block)
+{
+    size_t n;
+    union {
+        size_t t[16 / sizeof(size_t)];
+        unsigned char c[16];
+    } tmp;
+
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+    if (in != out) {
+        const unsigned char *iv = ivec;
+
+        if (STRICT_ALIGNMENT &&
+            ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+            while (len >= 16) {
+                (*block) (in, out, key);
+                for (n = 0; n < 16; ++n)
+                    out[n] ^= iv[n];
+                iv = in;
+                len -= 16;
+                in += 16;
+                out += 16;
+            }
+        } else if (16 % sizeof(size_t) == 0) { /* always true */
+            while (len >= 16) {
+                size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv;
+
+                (*block) (in, out, key);
+                for (n = 0; n < 16 / sizeof(size_t); n++)
+                    out_t[n] ^= iv_t[n];
+                iv = in;
+                len -= 16;
+                in += 16;
+                out += 16;
+            }
+        }
+        memcpy(ivec, iv, 16);
+    } else {
+        if (STRICT_ALIGNMENT &&
+            ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+            unsigned char c;
+            while (len >= 16) {
+                (*block) (in, tmp.c, key);
+                for (n = 0; n < 16; ++n) {
+                    c = in[n];
+                    out[n] = tmp.c[n] ^ ivec[n];
+                    ivec[n] = c;
+                }
+                len -= 16;
+                in += 16;
+                out += 16;
+            }
+        } else if (16 % sizeof(size_t) == 0) { /* always true */
+            while (len >= 16) {
+                size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec;
+                const size_t *in_t = (const size_t *)in;
+
+                (*block) (in, tmp.c, key);
+                for (n = 0; n < 16 / sizeof(size_t); n++) {
+                    c = in_t[n];
+                    out_t[n] = tmp.t[n] ^ ivec_t[n];
+                    ivec_t[n] = c;
+                }
+                len -= 16;
+                in += 16;
+                out += 16;
+            }
+        }
+    }
+#endif
+    while (len) {
+        unsigned char c;
+        (*block) (in, tmp.c, key);
+        for (n = 0; n < 16 && n < len; ++n) {
+            c = in[n];
+            out[n] = tmp.c[n] ^ ivec[n];
+            ivec[n] = c;
+        }
+        if (len <= 16) {
+            for (; n < 16; ++n)
+                ivec[n] = in[n];
+            break;
+        }
+        len -= 16;
+        in += 16;
+        out += 16;
+    }
+}

+ 431 - 0
components/SM/src/modes/ccm128.c

@@ -0,0 +1,431 @@
+/*
+ * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "modes_lcl.h"
+#include <string.h>
+
+/*
+ * First you setup M and L parameters and pass the key schedule. This is
+ * called once per session setup...
+ */
+void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
+                        unsigned int M, unsigned int L, void *key,
+                        block128_f block)
+{
+    memset(ctx->nonce.c, 0, sizeof(ctx->nonce.c));
+    ctx->nonce.c[0] = ((u8)(L - 1) & 7) | (u8)(((M - 2) / 2) & 7) << 3;
+    ctx->blocks = 0;
+    ctx->block = block;
+    ctx->key = key;
+}
+
+/* !!! Following interfaces are to be called *once* per packet !!! */
+
+/* Then you setup per-message nonce and pass the length of the message */
+int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx,
+                        const unsigned char *nonce, size_t nlen, size_t mlen)
+{
+    unsigned int L = ctx->nonce.c[0] & 7; /* the L parameter */
+
+    if (nlen < (14 - L))
+        return -1;              /* nonce is too short */
+
+    if (sizeof(mlen) == 8 && L >= 3) {
+        ctx->nonce.c[8] = (u8)(mlen >> (56 % (sizeof(mlen) * 8)));
+        ctx->nonce.c[9] = (u8)(mlen >> (48 % (sizeof(mlen) * 8)));
+        ctx->nonce.c[10] = (u8)(mlen >> (40 % (sizeof(mlen) * 8)));
+        ctx->nonce.c[11] = (u8)(mlen >> (32 % (sizeof(mlen) * 8)));
+    } else
+        ctx->nonce.u[1] = 0;
+
+    ctx->nonce.c[12] = (u8)(mlen >> 24);
+    ctx->nonce.c[13] = (u8)(mlen >> 16);
+    ctx->nonce.c[14] = (u8)(mlen >> 8);
+    ctx->nonce.c[15] = (u8)mlen;
+
+    ctx->nonce.c[0] &= ~0x40;   /* clear Adata flag */
+    memcpy(&ctx->nonce.c[1], nonce, 14 - L);
+
+    return 0;
+}
+
+/* Then you pass additional authentication data, this is optional */
+void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx,
+                       const unsigned char *aad, size_t alen)
+{
+    unsigned int i;
+    block128_f block = ctx->block;
+
+    if (alen == 0)
+        return;
+
+    ctx->nonce.c[0] |= 0x40;    /* set Adata flag */
+    (*block) (ctx->nonce.c, ctx->cmac.c, ctx->key), ctx->blocks++;
+
+    if (alen < (0x10000 - 0x100)) {
+        ctx->cmac.c[0] ^= (u8)(alen >> 8);
+        ctx->cmac.c[1] ^= (u8)alen;
+        i = 2;
+    } else if (sizeof(alen) == 8
+               && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) {
+        ctx->cmac.c[0] ^= 0xFF;
+        ctx->cmac.c[1] ^= 0xFF;
+        ctx->cmac.c[2] ^= (u8)(alen >> (56 % (sizeof(alen) * 8)));
+        ctx->cmac.c[3] ^= (u8)(alen >> (48 % (sizeof(alen) * 8)));
+        ctx->cmac.c[4] ^= (u8)(alen >> (40 % (sizeof(alen) * 8)));
+        ctx->cmac.c[5] ^= (u8)(alen >> (32 % (sizeof(alen) * 8)));
+        ctx->cmac.c[6] ^= (u8)(alen >> 24);
+        ctx->cmac.c[7] ^= (u8)(alen >> 16);
+        ctx->cmac.c[8] ^= (u8)(alen >> 8);
+        ctx->cmac.c[9] ^= (u8)alen;
+        i = 10;
+    } else {
+        ctx->cmac.c[0] ^= 0xFF;
+        ctx->cmac.c[1] ^= 0xFE;
+        ctx->cmac.c[2] ^= (u8)(alen >> 24);
+        ctx->cmac.c[3] ^= (u8)(alen >> 16);
+        ctx->cmac.c[4] ^= (u8)(alen >> 8);
+        ctx->cmac.c[5] ^= (u8)alen;
+        i = 6;
+    }
+
+    do {
+        for (; i < 16 && alen; ++i, ++aad, --alen)
+            ctx->cmac.c[i] ^= *aad;
+        (*block) (ctx->cmac.c, ctx->cmac.c, ctx->key), ctx->blocks++;
+        i = 0;
+    } while (alen);
+}
+
+/* Finally you encrypt or decrypt the message */
+
+/*
+ * counter part of nonce may not be larger than L*8 bits, L is not larger
+ * than 8, therefore 64-bit counter...
+ */
+static void ctr64_inc(unsigned char *counter)
+{
+    unsigned int n = 8;
+    u8 c;
+
+    counter += 8;
+    do {
+        --n;
+        c = counter[n];
+        ++c;
+        counter[n] = c;
+        if (c)
+            return;
+    } while (n);
+}
+
+int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx,
+                          const unsigned char *inp, unsigned char *out,
+                          size_t len)
+{
+    size_t n;
+    unsigned int i, L;
+    unsigned char flags0 = ctx->nonce.c[0];
+    block128_f block = ctx->block;
+    void *key = ctx->key;
+    union {
+        u64 u[2];
+        u8 c[16];
+    } scratch;
+
+    if (!(flags0 & 0x40))
+        (*block) (ctx->nonce.c, ctx->cmac.c, key), ctx->blocks++;
+
+    ctx->nonce.c[0] = L = flags0 & 7;
+    for (n = 0, i = 15 - L; i < 15; ++i) {
+        n |= ctx->nonce.c[i];
+        ctx->nonce.c[i] = 0;
+        n <<= 8;
+    }
+    n |= ctx->nonce.c[15];      /* reconstructed length */
+    ctx->nonce.c[15] = 1;
+
+    if (n != len)
+        return -1;              /* length mismatch */
+
+    ctx->blocks += ((len + 15) >> 3) | 1;
+    if (ctx->blocks > (U64(1) << 61))
+        return -2;              /* too much data */
+
+    while (len >= 16) {
+#if defined(STRICT_ALIGNMENT)
+        union {
+            u64 u[2];
+            u8 c[16];
+        } temp;
+
+        memcpy(temp.c, inp, 16);
+        ctx->cmac.u[0] ^= temp.u[0];
+        ctx->cmac.u[1] ^= temp.u[1];
+#else
+        ctx->cmac.u[0] ^= ((u64 *)inp)[0];
+        ctx->cmac.u[1] ^= ((u64 *)inp)[1];
+#endif
+        (*block) (ctx->cmac.c, ctx->cmac.c, key);
+        (*block) (ctx->nonce.c, scratch.c, key);
+        ctr64_inc(ctx->nonce.c);
+#if defined(STRICT_ALIGNMENT)
+        temp.u[0] ^= scratch.u[0];
+        temp.u[1] ^= scratch.u[1];
+        memcpy(out, temp.c, 16);
+#else
+        ((u64 *)out)[0] = scratch.u[0] ^ ((u64 *)inp)[0];
+        ((u64 *)out)[1] = scratch.u[1] ^ ((u64 *)inp)[1];
+#endif
+        inp += 16;
+        out += 16;
+        len -= 16;
+    }
+
+    if (len) {
+        for (i = 0; i < len; ++i)
+            ctx->cmac.c[i] ^= inp[i];
+        (*block) (ctx->cmac.c, ctx->cmac.c, key);
+        (*block) (ctx->nonce.c, scratch.c, key);
+        for (i = 0; i < len; ++i)
+            out[i] = scratch.c[i] ^ inp[i];
+    }
+
+    for (i = 15 - L; i < 16; ++i)
+        ctx->nonce.c[i] = 0;
+
+    (*block) (ctx->nonce.c, scratch.c, key);
+    ctx->cmac.u[0] ^= scratch.u[0];
+    ctx->cmac.u[1] ^= scratch.u[1];
+
+    ctx->nonce.c[0] = flags0;
+
+    return 0;
+}
+
+int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx,
+                          const unsigned char *inp, unsigned char *out,
+                          size_t len)
+{
+    size_t n;
+    unsigned int i, L;
+    unsigned char flags0 = ctx->nonce.c[0];
+    block128_f block = ctx->block;
+    void *key = ctx->key;
+    union {
+        u64 u[2];
+        u8 c[16];
+    } scratch;
+
+    if (!(flags0 & 0x40))
+        (*block) (ctx->nonce.c, ctx->cmac.c, key);
+
+    ctx->nonce.c[0] = L = flags0 & 7;
+    for (n = 0, i = 15 - L; i < 15; ++i) {
+        n |= ctx->nonce.c[i];
+        ctx->nonce.c[i] = 0;
+        n <<= 8;
+    }
+    n |= ctx->nonce.c[15];      /* reconstructed length */
+    ctx->nonce.c[15] = 1;
+
+    if (n != len)
+        return -1;
+
+    while (len >= 16) {
+#if defined(STRICT_ALIGNMENT)
+        union {
+            u64 u[2];
+            u8 c[16];
+        } temp;
+#endif
+        (*block) (ctx->nonce.c, scratch.c, key);
+        ctr64_inc(ctx->nonce.c);
+#if defined(STRICT_ALIGNMENT)
+        memcpy(temp.c, inp, 16);
+        ctx->cmac.u[0] ^= (scratch.u[0] ^= temp.u[0]);
+        ctx->cmac.u[1] ^= (scratch.u[1] ^= temp.u[1]);
+        memcpy(out, scratch.c, 16);
+#else
+        ctx->cmac.u[0] ^= (((u64 *)out)[0] = scratch.u[0] ^ ((u64 *)inp)[0]);
+        ctx->cmac.u[1] ^= (((u64 *)out)[1] = scratch.u[1] ^ ((u64 *)inp)[1]);
+#endif
+        (*block) (ctx->cmac.c, ctx->cmac.c, key);
+
+        inp += 16;
+        out += 16;
+        len -= 16;
+    }
+
+    if (len) {
+        (*block) (ctx->nonce.c, scratch.c, key);
+        for (i = 0; i < len; ++i)
+            ctx->cmac.c[i] ^= (out[i] = scratch.c[i] ^ inp[i]);
+        (*block) (ctx->cmac.c, ctx->cmac.c, key);
+    }
+
+    for (i = 15 - L; i < 16; ++i)
+        ctx->nonce.c[i] = 0;
+
+    (*block) (ctx->nonce.c, scratch.c, key);
+    ctx->cmac.u[0] ^= scratch.u[0];
+    ctx->cmac.u[1] ^= scratch.u[1];
+
+    ctx->nonce.c[0] = flags0;
+
+    return 0;
+}
+
+static void ctr64_add(unsigned char *counter, size_t inc)
+{
+    size_t n = 8, val = 0;
+
+    counter += 8;
+    do {
+        --n;
+        val += counter[n] + (inc & 0xff);
+        counter[n] = (unsigned char)val;
+        val >>= 8;              /* carry bit */
+        inc >>= 8;
+    } while (n && (inc || val));
+}
+
+int CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx,
+                                const unsigned char *inp, unsigned char *out,
+                                size_t len, ccm128_f stream)
+{
+    size_t n;
+    unsigned int i, L;
+    unsigned char flags0 = ctx->nonce.c[0];
+    block128_f block = ctx->block;
+    void *key = ctx->key;
+    union {
+        u64 u[2];
+        u8 c[16];
+    } scratch;
+
+    if (!(flags0 & 0x40))
+        (*block) (ctx->nonce.c, ctx->cmac.c, key), ctx->blocks++;
+
+    ctx->nonce.c[0] = L = flags0 & 7;
+    for (n = 0, i = 15 - L; i < 15; ++i) {
+        n |= ctx->nonce.c[i];
+        ctx->nonce.c[i] = 0;
+        n <<= 8;
+    }
+    n |= ctx->nonce.c[15];      /* reconstructed length */
+    ctx->nonce.c[15] = 1;
+
+    if (n != len)
+        return -1;              /* length mismatch */
+
+    ctx->blocks += ((len + 15) >> 3) | 1;
+    if (ctx->blocks > (U64(1) << 61))
+        return -2;              /* too much data */
+
+    if ((n = len / 16)) {
+        (*stream) (inp, out, n, key, ctx->nonce.c, ctx->cmac.c);
+        n *= 16;
+        inp += n;
+        out += n;
+        len -= n;
+        if (len)
+            ctr64_add(ctx->nonce.c, n / 16);
+    }
+
+    if (len) {
+        for (i = 0; i < len; ++i)
+            ctx->cmac.c[i] ^= inp[i];
+        (*block) (ctx->cmac.c, ctx->cmac.c, key);
+        (*block) (ctx->nonce.c, scratch.c, key);
+        for (i = 0; i < len; ++i)
+            out[i] = scratch.c[i] ^ inp[i];
+    }
+
+    for (i = 15 - L; i < 16; ++i)
+        ctx->nonce.c[i] = 0;
+
+    (*block) (ctx->nonce.c, scratch.c, key);
+    ctx->cmac.u[0] ^= scratch.u[0];
+    ctx->cmac.u[1] ^= scratch.u[1];
+
+    ctx->nonce.c[0] = flags0;
+
+    return 0;
+}
+
+int CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx,
+                                const unsigned char *inp, unsigned char *out,
+                                size_t len, ccm128_f stream)
+{
+    size_t n;
+    unsigned int i, L;
+    unsigned char flags0 = ctx->nonce.c[0];
+    block128_f block = ctx->block;
+    void *key = ctx->key;
+    union {
+        u64 u[2];
+        u8 c[16];
+    } scratch;
+
+    if (!(flags0 & 0x40))
+        (*block) (ctx->nonce.c, ctx->cmac.c, key);
+
+    ctx->nonce.c[0] = L = flags0 & 7;
+    for (n = 0, i = 15 - L; i < 15; ++i) {
+        n |= ctx->nonce.c[i];
+        ctx->nonce.c[i] = 0;
+        n <<= 8;
+    }
+    n |= ctx->nonce.c[15];      /* reconstructed length */
+    ctx->nonce.c[15] = 1;
+
+    if (n != len)
+        return -1;
+
+    if ((n = len / 16)) {
+        (*stream) (inp, out, n, key, ctx->nonce.c, ctx->cmac.c);
+        n *= 16;
+        inp += n;
+        out += n;
+        len -= n;
+        if (len)
+            ctr64_add(ctx->nonce.c, n / 16);
+    }
+
+    if (len) {
+        (*block) (ctx->nonce.c, scratch.c, key);
+        for (i = 0; i < len; ++i)
+            ctx->cmac.c[i] ^= (out[i] = scratch.c[i] ^ inp[i]);
+        (*block) (ctx->cmac.c, ctx->cmac.c, key);
+    }
+
+    for (i = 15 - L; i < 16; ++i)
+        ctx->nonce.c[i] = 0;
+
+    (*block) (ctx->nonce.c, scratch.c, key);
+    ctx->cmac.u[0] ^= scratch.u[0];
+    ctx->cmac.u[1] ^= scratch.u[1];
+
+    ctx->nonce.c[0] = flags0;
+
+    return 0;
+}
+
+size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len)
+{
+    unsigned int M = (ctx->nonce.c[0] >> 3) & 7; /* the M parameter */
+
+    M *= 2;
+    M += 2;
+    if (len < M)
+        return 0;
+    memcpy(tag, ctx->cmac.c, M);
+    return M;
+}

+ 198 - 0
components/SM/src/modes/cfb128.c

@@ -0,0 +1,198 @@
+/*
+ * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "modes_lcl.h"
+#include <string.h>
+
+/*
+ * The input and output encrypted as though 128bit cfb mode is being used.
+ * The extra state information to record how much of the 128bit block we have
+ * used is contained in *num;
+ */
+void CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16], int *num,
+                           int enc, block128_f block)
+{
+    unsigned int n;
+    size_t l = 0;
+
+    n = *num;
+
+    if (enc) {
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+        if (16 % sizeof(size_t) == 0) { /* always true actually */
+            do {
+                while (n && len) {
+                    *(out++) = ivec[n] ^= *(in++);
+                    --len;
+                    n = (n + 1) % 16;
+                }
+# if defined(STRICT_ALIGNMENT)
+                if (((size_t)in | (size_t)out | (size_t)ivec) %
+                    sizeof(size_t) != 0)
+                    break;
+# endif
+                while (len >= 16) {
+                    (*block) (ivec, ivec, key);
+                    for (; n < 16; n += sizeof(size_t)) {
+                        *(size_t *)(out + n) =
+                            *(size_t *)(ivec + n) ^= *(size_t *)(in + n);
+                    }
+                    len -= 16;
+                    out += 16;
+                    in += 16;
+                    n = 0;
+                }
+                if (len) {
+                    (*block) (ivec, ivec, key);
+                    while (len--) {
+                        out[n] = ivec[n] ^= in[n];
+                        ++n;
+                    }
+                }
+                *num = n;
+                return;
+            } while (0);
+        }
+        /* the rest would be commonly eliminated by x86* compiler */
+#endif
+        while (l < len) {
+            if (n == 0) {
+                (*block) (ivec, ivec, key);
+            }
+            out[l] = ivec[n] ^= in[l];
+            ++l;
+            n = (n + 1) % 16;
+        }
+        *num = n;
+    } else {
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+        if (16 % sizeof(size_t) == 0) { /* always true actually */
+            do {
+                while (n && len) {
+                    unsigned char c;
+                    *(out++) = ivec[n] ^ (c = *(in++));
+                    ivec[n] = c;
+                    --len;
+                    n = (n + 1) % 16;
+                }
+# if defined(STRICT_ALIGNMENT)
+                if (((size_t)in | (size_t)out | (size_t)ivec) %
+                    sizeof(size_t) != 0)
+                    break;
+# endif
+                while (len >= 16) {
+                    (*block) (ivec, ivec, key);
+                    for (; n < 16; n += sizeof(size_t)) {
+                        size_t t = *(size_t *)(in + n);
+                        *(size_t *)(out + n) = *(size_t *)(ivec + n) ^ t;
+                        *(size_t *)(ivec + n) = t;
+                    }
+                    len -= 16;
+                    out += 16;
+                    in += 16;
+                    n = 0;
+                }
+                if (len) {
+                    (*block) (ivec, ivec, key);
+                    while (len--) {
+                        unsigned char c;
+                        out[n] = ivec[n] ^ (c = in[n]);
+                        ivec[n] = c;
+                        ++n;
+                    }
+                }
+                *num = n;
+                return;
+            } while (0);
+        }
+        /* the rest would be commonly eliminated by x86* compiler */
+#endif
+        while (l < len) {
+            unsigned char c;
+            if (n == 0) {
+                (*block) (ivec, ivec, key);
+            }
+            out[l] = ivec[n] ^ (c = in[l]);
+            ivec[n] = c;
+            ++l;
+            n = (n + 1) % 16;
+        }
+        *num = n;
+    }
+}
+
+/*
+ * This expects a single block of size nbits for both in and out. Note that
+ * it corrupts any extra bits in the last byte of out
+ */
+static void cfbr_encrypt_block(const unsigned char *in, unsigned char *out,
+                               int nbits, const void *key,
+                               unsigned char ivec[16], int enc,
+                               block128_f block)
+{
+    int n, rem, num;
+    unsigned char ovec[16 * 2 + 1]; /* +1 because we dereference (but don't
+                                     * use) one byte off the end */
+
+    if (nbits <= 0 || nbits > 128)
+        return;
+
+    /* fill in the first half of the new IV with the current IV */
+    memcpy(ovec, ivec, 16);
+    /* construct the new IV */
+    (*block) (ivec, ivec, key);
+    num = (nbits + 7) / 8;
+    if (enc)                    /* encrypt the input */
+        for (n = 0; n < num; ++n)
+            out[n] = (ovec[16 + n] = in[n] ^ ivec[n]);
+    else                        /* decrypt the input */
+        for (n = 0; n < num; ++n)
+            out[n] = (ovec[16 + n] = in[n]) ^ ivec[n];
+    /* shift ovec left... */
+    rem = nbits % 8;
+    num = nbits / 8;
+    if (rem == 0)
+        memcpy(ivec, ovec + num, 16);
+    else
+        for (n = 0; n < 16; ++n)
+            ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem);
+
+    /* it is not necessary to cleanse ovec, since the IV is not secret */
+}
+
+/* N.B. This expects the input to be packed, MS bit first */
+void CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out,
+                             size_t bits, const void *key,
+                             unsigned char ivec[16], int *num,
+                             int enc, block128_f block)
+{
+    size_t n;
+    unsigned char c[1], d[1];
+    n = *num;
+
+    for (n = 0; n < bits; ++n) {
+        c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
+        cfbr_encrypt_block(c, d, 1, key, ivec, enc, block);
+        out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) |
+            ((d[0] & 0x80) >> (unsigned int)(n % 8));
+    }
+}
+
+void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
+                             size_t length, const void *key,
+                             unsigned char ivec[16], int *num,
+                             int enc, block128_f block)
+{
+    size_t n;
+    n = *num;
+    for (n = 0; n < length; ++n)
+        cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block);
+}

+ 226 - 0
components/SM/src/modes/ctr128.c

@@ -0,0 +1,226 @@
+/*
+ * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "modes_lcl.h"
+#include <string.h>
+
+/*
+ * NOTE: the IV/counter CTR mode is big-endian.  The code itself is
+ * endian-neutral.
+ */
+
+/* increment counter (128-bit int) by 1 */
+void ctr128_inc(unsigned char *counter)
+{
+    u32 n = 16, c = 1;
+
+    do {
+        --n;
+        c += counter[n];
+        counter[n] = (u8)c;
+        c >>= 8;
+    } while (n);
+}
+
+void ctr128_dec(unsigned char *ctr_buf){
+    if(!(ctr_buf[15]--)){
+        if(!(ctr_buf[14]--)){
+            if(!(ctr_buf[13]--)){
+                ctr_buf[12]--;
+            }
+        }
+    }
+}
+
+//same as fucntion rfc3686_init
+//4Bytes nounce + 8bytes iv + 4bytes counter
+void ctr128_init(unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16]){
+  memcpy(ctr_buf, nonce, 4);
+  memcpy(ctr_buf+4, iv, 8);
+  memset(ctr_buf+12, 0, 4);
+  ctr128_inc(ctr_buf);
+}
+
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+static void ctr128_inc_aligned(unsigned char *counter)
+{
+    size_t *data, c, d, n;
+    const union {
+        long one;
+        char little;
+    } is_endian = {
+        1
+    };
+
+    if (is_endian.little || ((size_t)counter % sizeof(size_t)) != 0) {
+        ctr128_inc(counter);
+        return;
+    }
+
+    data = (size_t *)counter;
+    c = 1;
+    n = 16 / sizeof(size_t);
+    do {
+        --n;
+        d = data[n] += c;
+        /* did addition carry? */
+        c = ((d - c) & ~d) >> (sizeof(size_t) * 8 - 1);
+    } while (n);
+}
+#endif
+
+/*
+ * The input encrypted as though 128bit counter mode is being used.  The
+ * extra state information to record how much of the 128bit block we have
+ * used is contained in *num, and the encrypted counter is kept in
+ * ecount_buf.  Both *num and ecount_buf must be initialised with zeros
+ * before the first call to CRYPTO_ctr128_encrypt(). This algorithm assumes
+ * that the counter is in the x lower bits of the IV (ivec), and that the
+ * application has full control over overflow and the rest of the IV.  This
+ * implementation takes NO responsibility for checking that the counter
+ * doesn't overflow into the rest of the IV when incremented.
+ */
+void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16],
+                           unsigned char ecount_buf[16], unsigned int *num,
+                           block128_f block)
+{
+    unsigned int n;
+    size_t l = 0;
+
+    n = *num;
+
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+    if (16 % sizeof(size_t) == 0) { /* always true actually */
+        do {
+            while (n && len) {
+                *(out++) = *(in++) ^ ecount_buf[n];
+                --len;
+                n = (n + 1) % 16;
+            }
+
+# if defined(STRICT_ALIGNMENT)
+            if (((size_t)in | (size_t)out | (size_t)ecount_buf)
+                % sizeof(size_t) != 0)
+                break;
+# endif
+            while (len >= 16) {
+                (*block) (ivec, ecount_buf, key);
+                ctr128_inc_aligned(ivec);
+                for (n = 0; n < 16; n += sizeof(size_t))
+                    *(size_t *)(out + n) =
+                        *(size_t *)(in + n) ^ *(size_t *)(ecount_buf + n);
+                len -= 16;
+                out += 16;
+                in += 16;
+                n = 0;
+            }
+            if (len) {
+                (*block) (ivec, ecount_buf, key);
+                ctr128_inc_aligned(ivec);
+                while (len--) {
+                    out[n] = in[n] ^ ecount_buf[n];
+                    ++n;
+                }
+            }
+            *num = n;
+            return;
+        } while (0);
+    }
+    /* the rest would be commonly eliminated by x86* compiler */
+#endif
+    while (l < len) {
+        if (n == 0) {
+            (*block) (ivec, ecount_buf, key);
+            ctr128_inc(ivec);
+        }
+        out[l] = in[l] ^ ecount_buf[n];
+        ++l;
+        n = (n + 1) % 16;
+    }
+
+    *num = n;
+}
+
+/* increment upper 96 bits of 128-bit counter by 1 */
+static void ctr96_inc(unsigned char *counter)
+{
+    u32 n = 12, c = 1;
+
+    do {
+        --n;
+        c += counter[n];
+        counter[n] = (u8)c;
+        c >>= 8;
+    } while (n);
+}
+
+void CRYPTO_ctr128_encrypt_ctr32(const unsigned char *in, unsigned char *out,
+                                 size_t len, const void *key,
+                                 unsigned char ivec[16],
+                                 unsigned char ecount_buf[16],
+                                 unsigned int *num, ctr128_f func)
+{
+    unsigned int n, ctr32;
+
+    n = *num;
+
+    while (n && len) {
+        *(out++) = *(in++) ^ ecount_buf[n];
+        --len;
+        n = (n + 1) % 16;
+    }
+    ctr32 = GETU32(ivec + 12);
+    while (len >= 16) {
+        size_t blocks = len / 16;
+        /*
+         * 1<<28 is just a not-so-small yet not-so-large number...
+         * Below condition is practically never met, but it has to
+         * be checked for code correctness.
+         */
+        if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28))
+            blocks = (1U << 28);
+        /*
+         * As (*func) operates on 32-bit counter, caller
+         * has to handle overflow. 'if' below detects the
+         * overflow, which is then handled by limiting the
+         * amount of blocks to the exact overflow point...
+         */
+        ctr32 += (u32)blocks;
+        if (ctr32 < blocks) {
+            blocks -= ctr32;
+            ctr32 = 0;
+        }
+        (*func) (in, out, blocks, key, ivec);
+        /* (*ctr) does not update ivec, caller does: */
+        PUTU32(ivec + 12, ctr32);
+        /* ... overflow was detected, propagate carry. */
+        if (ctr32 == 0)
+            ctr96_inc(ivec);
+        blocks *= 16;
+        len -= blocks;
+        out += blocks;
+        in += blocks;
+    }
+    if (len) {
+        memset(ecount_buf, 0, 16);
+        (*func) (ecount_buf, ecount_buf, 1, key, ivec);
+        ++ctr32;
+        PUTU32(ivec + 12, ctr32);
+        if (ctr32 == 0)
+            ctr96_inc(ivec);
+        while (len--) {
+            out[n] = in[n] ^ ecount_buf[n];
+            ++n;
+        }
+    }
+
+    *num = n;
+}

+ 522 - 0
components/SM/src/modes/cts128.c

@@ -0,0 +1,522 @@
+/*
+ * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "modes_lcl.h"
+#include <string.h>
+
+/*
+ * Trouble with Ciphertext Stealing, CTS, mode is that there is no
+ * common official specification, but couple of cipher/application
+ * specific ones: RFC2040 and RFC3962. Then there is 'Proposal to
+ * Extend CBC Mode By "Ciphertext Stealing"' at NIST site, which
+ * deviates from mentioned RFCs. Most notably it allows input to be
+ * of block length and it doesn't flip the order of the last two
+ * blocks. CTS is being discussed even in ECB context, but it's not
+ * adopted for any known application. This implementation provides
+ * two interfaces: one compliant with above mentioned RFCs and one
+ * compliant with the NIST proposal, both extending CBC mode.
+ */
+
+size_t CRYPTO_cts128_encrypt_block(const unsigned char *in,
+                                   unsigned char *out, size_t len,
+                                   const void *key, unsigned char ivec[16],
+                                   block128_f block)
+{
+    size_t residue, n;
+
+    if (len <= 16)
+        return 0;
+
+    if ((residue = len % 16) == 0)
+        residue = 16;
+
+    len -= residue;
+
+    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
+
+    in += len;
+    out += len;
+
+    for (n = 0; n < residue; ++n)
+        ivec[n] ^= in[n];
+    (*block) (ivec, ivec, key);
+    memcpy(out, out - 16, residue);
+    memcpy(out - 16, ivec, 16);
+
+    return len + residue;
+}
+
+size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in,
+                                       unsigned char *out, size_t len,
+                                       const void *key,
+                                       unsigned char ivec[16],
+                                       block128_f block)
+{
+    size_t residue, n;
+
+    if (len < 16)
+        return 0;
+
+    residue = len % 16;
+
+    len -= residue;
+
+    CRYPTO_cbc128_encrypt(in, out, len, key, ivec, block);
+
+    if (residue == 0)
+        return len;
+
+    in += len;
+    out += len;
+
+    for (n = 0; n < residue; ++n)
+        ivec[n] ^= in[n];
+    (*block) (ivec, ivec, key);
+    memcpy(out - 16 + residue, ivec, 16);
+
+    return len + residue;
+}
+
+size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
+                             size_t len, const void *key,
+                             unsigned char ivec[16], cbc128_f cbc)
+{
+    size_t residue;
+    union {
+        size_t align;
+        unsigned char c[16];
+    } tmp;
+
+    if (len <= 16)
+        return 0;
+
+    if ((residue = len % 16) == 0)
+        residue = 16;
+
+    len -= residue;
+
+    (*cbc) (in, out, len, key, ivec, 1);
+
+    in += len;
+    out += len;
+
+#if defined(CBC_HANDLES_TRUNCATED_IO)
+    memcpy(tmp.c, out - 16, 16);
+    (*cbc) (in, out - 16, residue, key, ivec, 1);
+    memcpy(out, tmp.c, residue);
+#else
+    memset(tmp.c, 0, sizeof(tmp));
+    memcpy(tmp.c, in, residue);
+    memcpy(out, out - 16, residue);
+    (*cbc) (tmp.c, out - 16, 16, key, ivec, 1);
+#endif
+    return len + residue;
+}
+
+size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
+                                 size_t len, const void *key,
+                                 unsigned char ivec[16], cbc128_f cbc)
+{
+    size_t residue;
+    union {
+        size_t align;
+        unsigned char c[16];
+    } tmp;
+
+    if (len < 16)
+        return 0;
+
+    residue = len % 16;
+
+    len -= residue;
+
+    (*cbc) (in, out, len, key, ivec, 1);
+
+    if (residue == 0)
+        return len;
+
+    in += len;
+    out += len;
+
+#if defined(CBC_HANDLES_TRUNCATED_IO)
+    (*cbc) (in, out - 16 + residue, residue, key, ivec, 1);
+#else
+    memset(tmp.c, 0, sizeof(tmp));
+    memcpy(tmp.c, in, residue);
+    (*cbc) (tmp.c, out - 16 + residue, 16, key, ivec, 1);
+#endif
+    return len + residue;
+}
+
+size_t CRYPTO_cts128_decrypt_block(const unsigned char *in,
+                                   unsigned char *out, size_t len,
+                                   const void *key, unsigned char ivec[16],
+                                   block128_f block)
+{
+    size_t residue, n;
+    union {
+        size_t align;
+        unsigned char c[32];
+    } tmp;
+
+    if (len <= 16)
+        return 0;
+
+    if ((residue = len % 16) == 0)
+        residue = 16;
+
+    len -= 16 + residue;
+
+    if (len) {
+        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
+        in += len;
+        out += len;
+    }
+
+    (*block) (in, tmp.c + 16, key);
+
+    memcpy(tmp.c, tmp.c + 16, 16);
+    memcpy(tmp.c, in + 16, residue);
+    (*block) (tmp.c, tmp.c, key);
+
+    for (n = 0; n < 16; ++n) {
+        unsigned char c = in[n];
+        out[n] = tmp.c[n] ^ ivec[n];
+        ivec[n] = c;
+    }
+    for (residue += 16; n < residue; ++n)
+        out[n] = tmp.c[n] ^ in[n];
+
+    return 16 + len + residue;
+}
+
+size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in,
+                                       unsigned char *out, size_t len,
+                                       const void *key,
+                                       unsigned char ivec[16],
+                                       block128_f block)
+{
+    size_t residue, n;
+    union {
+        size_t align;
+        unsigned char c[32];
+    } tmp;
+
+    if (len < 16)
+        return 0;
+
+    residue = len % 16;
+
+    if (residue == 0) {
+        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
+        return len;
+    }
+
+    len -= 16 + residue;
+
+    if (len) {
+        CRYPTO_cbc128_decrypt(in, out, len, key, ivec, block);
+        in += len;
+        out += len;
+    }
+
+    (*block) (in + residue, tmp.c + 16, key);
+
+    memcpy(tmp.c, tmp.c + 16, 16);
+    memcpy(tmp.c, in, residue);
+    (*block) (tmp.c, tmp.c, key);
+
+    for (n = 0; n < 16; ++n) {
+        unsigned char c = in[n];
+        out[n] = tmp.c[n] ^ ivec[n];
+        ivec[n] = in[n + residue];
+        tmp.c[n] = c;
+    }
+    for (residue += 16; n < residue; ++n)
+        out[n] = tmp.c[n] ^ tmp.c[n - 16];
+
+    return 16 + len + residue;
+}
+
+size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
+                             size_t len, const void *key,
+                             unsigned char ivec[16], cbc128_f cbc)
+{
+    size_t residue;
+    union {
+        size_t align;
+        unsigned char c[32];
+    } tmp;
+
+    if (len <= 16)
+        return 0;
+
+    if ((residue = len % 16) == 0)
+        residue = 16;
+
+    len -= 16 + residue;
+
+    if (len) {
+        (*cbc) (in, out, len, key, ivec, 0);
+        in += len;
+        out += len;
+    }
+
+    memset(tmp.c, 0, sizeof(tmp));
+    /*
+     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
+     */
+    (*cbc) (in, tmp.c, 16, key, tmp.c + 16, 0);
+
+    memcpy(tmp.c, in + 16, residue);
+#if defined(CBC_HANDLES_TRUNCATED_IO)
+    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
+#else
+    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
+    memcpy(out, tmp.c, 16 + residue);
+#endif
+    return 16 + len + residue;
+}
+
+size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
+                                 size_t len, const void *key,
+                                 unsigned char ivec[16], cbc128_f cbc)
+{
+    size_t residue;
+    union {
+        size_t align;
+        unsigned char c[32];
+    } tmp;
+
+    if (len < 16)
+        return 0;
+
+    residue = len % 16;
+
+    if (residue == 0) {
+        (*cbc) (in, out, len, key, ivec, 0);
+        return len;
+    }
+
+    len -= 16 + residue;
+
+    if (len) {
+        (*cbc) (in, out, len, key, ivec, 0);
+        in += len;
+        out += len;
+    }
+
+    memset(tmp.c, 0, sizeof(tmp));
+    /*
+     * this places in[16] at &tmp.c[16] and decrypted block at &tmp.c[0]
+     */
+    (*cbc) (in + residue, tmp.c, 16, key, tmp.c + 16, 0);
+
+    memcpy(tmp.c, in, residue);
+#if defined(CBC_HANDLES_TRUNCATED_IO)
+    (*cbc) (tmp.c, out, 16 + residue, key, ivec, 0);
+#else
+    (*cbc) (tmp.c, tmp.c, 32, key, ivec, 0);
+    memcpy(out, tmp.c, 16 + residue);
+#endif
+    return 16 + len + residue;
+}
+
+#if defined(SELFTEST)
+# include <stdio.h>
+# include <openssl/aes.h>
+
+/* test vectors from RFC 3962 */
+static const unsigned char test_key[16] = "chicken teriyaki";
+static const unsigned char test_input[64] =
+    "I would like the" " General Gau's C"
+    "hicken, please, " "and wonton soup.";
+static const unsigned char test_iv[16] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static const unsigned char vector_17[17] = {
+    0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
+    0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f,
+    0x97
+};
+
+static const unsigned char vector_31[31] = {
+    0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
+    0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
+    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5
+};
+
+static const unsigned char vector_32[32] = {
+    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
+    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84
+};
+
+static const unsigned char vector_47[47] = {
+    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+    0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
+    0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
+    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5
+};
+
+static const unsigned char vector_48[48] = {
+    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+    0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+    0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
+    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8
+};
+
+static const unsigned char vector_64[64] = {
+    0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+    0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+    0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+    0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
+    0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
+    0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
+    0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+    0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8
+};
+
+static AES_KEY encks, decks;
+
+void test_vector(const unsigned char *vector, size_t len)
+{
+    unsigned char iv[sizeof(test_iv)];
+    unsigned char cleartext[64], ciphertext[64];
+    size_t tail;
+
+    printf("vector_%d\n", len);
+    fflush(stdout);
+
+    if ((tail = len % 16) == 0)
+        tail = 16;
+    tail += 16;
+
+    /* test block-based encryption */
+    memcpy(iv, test_iv, sizeof(test_iv));
+    CRYPTO_cts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
+                                (block128_f) AES_encrypt);
+    if (memcmp(ciphertext, vector, len))
+        fprintf(stderr, "output_%d mismatch\n", len), exit(1);
+    if (memcmp(iv, vector + len - tail, sizeof(iv)))
+        fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
+
+    /* test block-based decryption */
+    memcpy(iv, test_iv, sizeof(test_iv));
+    CRYPTO_cts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
+                                (block128_f) AES_decrypt);
+    if (memcmp(cleartext, test_input, len))
+        fprintf(stderr, "input_%d mismatch\n", len), exit(2);
+    if (memcmp(iv, vector + len - tail, sizeof(iv)))
+        fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
+
+    /* test streamed encryption */
+    memcpy(iv, test_iv, sizeof(test_iv));
+    CRYPTO_cts128_encrypt(test_input, ciphertext, len, &encks, iv,
+                          (cbc128_f) AES_cbc_encrypt);
+    if (memcmp(ciphertext, vector, len))
+        fprintf(stderr, "output_%d mismatch\n", len), exit(3);
+    if (memcmp(iv, vector + len - tail, sizeof(iv)))
+        fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
+
+    /* test streamed decryption */
+    memcpy(iv, test_iv, sizeof(test_iv));
+    CRYPTO_cts128_decrypt(ciphertext, cleartext, len, &decks, iv,
+                          (cbc128_f) AES_cbc_encrypt);
+    if (memcmp(cleartext, test_input, len))
+        fprintf(stderr, "input_%d mismatch\n", len), exit(4);
+    if (memcmp(iv, vector + len - tail, sizeof(iv)))
+        fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
+}
+
+void test_nistvector(const unsigned char *vector, size_t len)
+{
+    unsigned char iv[sizeof(test_iv)];
+    unsigned char cleartext[64], ciphertext[64], nistvector[64];
+    size_t tail;
+
+    printf("nistvector_%d\n", len);
+    fflush(stdout);
+
+    if ((tail = len % 16) == 0)
+        tail = 16;
+
+    len -= 16 + tail;
+    memcpy(nistvector, vector, len);
+    /* flip two last blocks */
+    memcpy(nistvector + len, vector + len + 16, tail);
+    memcpy(nistvector + len + tail, vector + len, 16);
+    len += 16 + tail;
+    tail = 16;
+
+    /* test block-based encryption */
+    memcpy(iv, test_iv, sizeof(test_iv));
+    CRYPTO_nistcts128_encrypt_block(test_input, ciphertext, len, &encks, iv,
+                                    (block128_f) AES_encrypt);
+    if (memcmp(ciphertext, nistvector, len))
+        fprintf(stderr, "output_%d mismatch\n", len), exit(1);
+    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
+        fprintf(stderr, "iv_%d mismatch\n", len), exit(1);
+
+    /* test block-based decryption */
+    memcpy(iv, test_iv, sizeof(test_iv));
+    CRYPTO_nistcts128_decrypt_block(ciphertext, cleartext, len, &decks, iv,
+                                    (block128_f) AES_decrypt);
+    if (memcmp(cleartext, test_input, len))
+        fprintf(stderr, "input_%d mismatch\n", len), exit(2);
+    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
+        fprintf(stderr, "iv_%d mismatch\n", len), exit(2);
+
+    /* test streamed encryption */
+    memcpy(iv, test_iv, sizeof(test_iv));
+    CRYPTO_nistcts128_encrypt(test_input, ciphertext, len, &encks, iv,
+                              (cbc128_f) AES_cbc_encrypt);
+    if (memcmp(ciphertext, nistvector, len))
+        fprintf(stderr, "output_%d mismatch\n", len), exit(3);
+    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
+        fprintf(stderr, "iv_%d mismatch\n", len), exit(3);
+
+    /* test streamed decryption */
+    memcpy(iv, test_iv, sizeof(test_iv));
+    CRYPTO_nistcts128_decrypt(ciphertext, cleartext, len, &decks, iv,
+                              (cbc128_f) AES_cbc_encrypt);
+    if (memcmp(cleartext, test_input, len))
+        fprintf(stderr, "input_%d mismatch\n", len), exit(4);
+    if (memcmp(iv, nistvector + len - tail, sizeof(iv)))
+        fprintf(stderr, "iv_%d mismatch\n", len), exit(4);
+}
+
+int main()
+{
+    AES_set_encrypt_key(test_key, 128, &encks);
+    AES_set_decrypt_key(test_key, 128, &decks);
+
+    test_vector(vector_17, sizeof(vector_17));
+    test_vector(vector_31, sizeof(vector_31));
+    test_vector(vector_32, sizeof(vector_32));
+    test_vector(vector_47, sizeof(vector_47));
+    test_vector(vector_48, sizeof(vector_48));
+    test_vector(vector_64, sizeof(vector_64));
+
+    test_nistvector(vector_17, sizeof(vector_17));
+    test_nistvector(vector_31, sizeof(vector_31));
+    test_nistvector(vector_32, sizeof(vector_32));
+    test_nistvector(vector_47, sizeof(vector_47));
+    test_nistvector(vector_48, sizeof(vector_48));
+    test_nistvector(vector_64, sizeof(vector_64));
+
+    return 0;
+}
+#endif

+ 2302 - 0
components/SM/src/modes/gcm128.c

@@ -0,0 +1,2302 @@
+/*
+ * Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <internal/openssl_aid.h>
+#include "modes_lcl.h"
+#include <string.h>
+
+#if defined(BSWAP4) && defined(STRICT_ALIGNMENT)
+/* redefine, because alignment is ensured */
+# undef  GETU32
+# define GETU32(p)       BSWAP4(*(const u32 *)(p))
+# undef  PUTU32
+# define PUTU32(p,v)     *(u32 *)(p) = BSWAP4(v)
+#endif
+
+#define PACK(s)         ((size_t)(s)<<(sizeof(size_t)*8-16))
+#define REDUCE1BIT(V)   do { \
+        if (sizeof(size_t)==8) { \
+                u64 T = U64(0xe100000000000000) & (0-(V.lo&1)); \
+                V.lo  = (V.hi<<63)|(V.lo>>1); \
+                V.hi  = (V.hi>>1 )^T; \
+        } \
+        else { \
+                u32 T = 0xe1000000U & (0-(u32)(V.lo&1)); \
+                V.lo  = (V.hi<<63)|(V.lo>>1); \
+                V.hi  = (V.hi>>1 )^((u64)T<<32); \
+        } \
+} while(0)
+
+/*-
+ * Even though permitted values for TABLE_BITS are 8, 4 and 1, it should
+ * never be set to 8. 8 is effectively reserved for testing purposes.
+ * TABLE_BITS>1 are lookup-table-driven implementations referred to as
+ * "Shoup's" in GCM specification. In other words OpenSSL does not cover
+ * whole spectrum of possible table driven implementations. Why? In
+ * non-"Shoup's" case memory access pattern is segmented in such manner,
+ * that it's trivial to see that cache timing information can reveal
+ * fair portion of intermediate hash value. Given that ciphertext is
+ * always available to attacker, it's possible for him to attempt to
+ * deduce secret parameter H and if successful, tamper with messages
+ * [which is nothing but trivial in CTR mode]. In "Shoup's" case it's
+ * not as trivial, but there is no reason to believe that it's resistant
+ * to cache-timing attack. And the thing about "8-bit" implementation is
+ * that it consumes 16 (sixteen) times more memory, 4KB per individual
+ * key + 1KB shared. Well, on pros side it should be twice as fast as
+ * "4-bit" version. And for gcc-generated x86[_64] code, "8-bit" version
+ * was observed to run ~75% faster, closer to 100% for commercial
+ * compilers... Yet "4-bit" procedure is preferred, because it's
+ * believed to provide better security-performance balance and adequate
+ * all-round performance. "All-round" refers to things like:
+ *
+ * - shorter setup time effectively improves overall timing for
+ *   handling short messages;
+ * - larger table allocation can become unbearable because of VM
+ *   subsystem penalties (for example on Windows large enough free
+ *   results in VM working set trimming, meaning that consequent
+ *   malloc would immediately incur working set expansion);
+ * - larger table has larger cache footprint, which can affect
+ *   performance of other code paths (not necessarily even from same
+ *   thread in Hyper-Threading world);
+ *
+ * Value of 1 is not appropriate for performance reasons.
+ */
+#if     TABLE_BITS==8
+
+static void gcm_init_8bit(u128 Htable[256], u64 H[2])
+{
+    int i, j;
+    u128 V;
+
+    Htable[0].hi = 0;
+    Htable[0].lo = 0;
+    V.hi = H[0];
+    V.lo = H[1];
+
+    for (Htable[128] = V, i = 64; i > 0; i >>= 1) {
+        REDUCE1BIT(V);
+        Htable[i] = V;
+    }
+
+    for (i = 2; i < 256; i <<= 1) {
+        u128 *Hi = Htable + i, H0 = *Hi;
+        for (j = 1; j < i; ++j) {
+            Hi[j].hi = H0.hi ^ Htable[j].hi;
+            Hi[j].lo = H0.lo ^ Htable[j].lo;
+        }
+    }
+}
+
+static void gcm_gmult_8bit(u64 Xi[2], const u128 Htable[256])
+{
+    u128 Z = { 0, 0 };
+    const u8 *xi = (const u8 *)Xi + 15;
+    size_t rem, n = *xi;
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+    static const size_t rem_8bit[256] = {
+        PACK(0x0000), PACK(0x01C2), PACK(0x0384), PACK(0x0246),
+        PACK(0x0708), PACK(0x06CA), PACK(0x048C), PACK(0x054E),
+        PACK(0x0E10), PACK(0x0FD2), PACK(0x0D94), PACK(0x0C56),
+        PACK(0x0918), PACK(0x08DA), PACK(0x0A9C), PACK(0x0B5E),
+        PACK(0x1C20), PACK(0x1DE2), PACK(0x1FA4), PACK(0x1E66),
+        PACK(0x1B28), PACK(0x1AEA), PACK(0x18AC), PACK(0x196E),
+        PACK(0x1230), PACK(0x13F2), PACK(0x11B4), PACK(0x1076),
+        PACK(0x1538), PACK(0x14FA), PACK(0x16BC), PACK(0x177E),
+        PACK(0x3840), PACK(0x3982), PACK(0x3BC4), PACK(0x3A06),
+        PACK(0x3F48), PACK(0x3E8A), PACK(0x3CCC), PACK(0x3D0E),
+        PACK(0x3650), PACK(0x3792), PACK(0x35D4), PACK(0x3416),
+        PACK(0x3158), PACK(0x309A), PACK(0x32DC), PACK(0x331E),
+        PACK(0x2460), PACK(0x25A2), PACK(0x27E4), PACK(0x2626),
+        PACK(0x2368), PACK(0x22AA), PACK(0x20EC), PACK(0x212E),
+        PACK(0x2A70), PACK(0x2BB2), PACK(0x29F4), PACK(0x2836),
+        PACK(0x2D78), PACK(0x2CBA), PACK(0x2EFC), PACK(0x2F3E),
+        PACK(0x7080), PACK(0x7142), PACK(0x7304), PACK(0x72C6),
+        PACK(0x7788), PACK(0x764A), PACK(0x740C), PACK(0x75CE),
+        PACK(0x7E90), PACK(0x7F52), PACK(0x7D14), PACK(0x7CD6),
+        PACK(0x7998), PACK(0x785A), PACK(0x7A1C), PACK(0x7BDE),
+        PACK(0x6CA0), PACK(0x6D62), PACK(0x6F24), PACK(0x6EE6),
+        PACK(0x6BA8), PACK(0x6A6A), PACK(0x682C), PACK(0x69EE),
+        PACK(0x62B0), PACK(0x6372), PACK(0x6134), PACK(0x60F6),
+        PACK(0x65B8), PACK(0x647A), PACK(0x663C), PACK(0x67FE),
+        PACK(0x48C0), PACK(0x4902), PACK(0x4B44), PACK(0x4A86),
+        PACK(0x4FC8), PACK(0x4E0A), PACK(0x4C4C), PACK(0x4D8E),
+        PACK(0x46D0), PACK(0x4712), PACK(0x4554), PACK(0x4496),
+        PACK(0x41D8), PACK(0x401A), PACK(0x425C), PACK(0x439E),
+        PACK(0x54E0), PACK(0x5522), PACK(0x5764), PACK(0x56A6),
+        PACK(0x53E8), PACK(0x522A), PACK(0x506C), PACK(0x51AE),
+        PACK(0x5AF0), PACK(0x5B32), PACK(0x5974), PACK(0x58B6),
+        PACK(0x5DF8), PACK(0x5C3A), PACK(0x5E7C), PACK(0x5FBE),
+        PACK(0xE100), PACK(0xE0C2), PACK(0xE284), PACK(0xE346),
+        PACK(0xE608), PACK(0xE7CA), PACK(0xE58C), PACK(0xE44E),
+        PACK(0xEF10), PACK(0xEED2), PACK(0xEC94), PACK(0xED56),
+        PACK(0xE818), PACK(0xE9DA), PACK(0xEB9C), PACK(0xEA5E),
+        PACK(0xFD20), PACK(0xFCE2), PACK(0xFEA4), PACK(0xFF66),
+        PACK(0xFA28), PACK(0xFBEA), PACK(0xF9AC), PACK(0xF86E),
+        PACK(0xF330), PACK(0xF2F2), PACK(0xF0B4), PACK(0xF176),
+        PACK(0xF438), PACK(0xF5FA), PACK(0xF7BC), PACK(0xF67E),
+        PACK(0xD940), PACK(0xD882), PACK(0xDAC4), PACK(0xDB06),
+        PACK(0xDE48), PACK(0xDF8A), PACK(0xDDCC), PACK(0xDC0E),
+        PACK(0xD750), PACK(0xD692), PACK(0xD4D4), PACK(0xD516),
+        PACK(0xD058), PACK(0xD19A), PACK(0xD3DC), PACK(0xD21E),
+        PACK(0xC560), PACK(0xC4A2), PACK(0xC6E4), PACK(0xC726),
+        PACK(0xC268), PACK(0xC3AA), PACK(0xC1EC), PACK(0xC02E),
+        PACK(0xCB70), PACK(0xCAB2), PACK(0xC8F4), PACK(0xC936),
+        PACK(0xCC78), PACK(0xCDBA), PACK(0xCFFC), PACK(0xCE3E),
+        PACK(0x9180), PACK(0x9042), PACK(0x9204), PACK(0x93C6),
+        PACK(0x9688), PACK(0x974A), PACK(0x950C), PACK(0x94CE),
+        PACK(0x9F90), PACK(0x9E52), PACK(0x9C14), PACK(0x9DD6),
+        PACK(0x9898), PACK(0x995A), PACK(0x9B1C), PACK(0x9ADE),
+        PACK(0x8DA0), PACK(0x8C62), PACK(0x8E24), PACK(0x8FE6),
+        PACK(0x8AA8), PACK(0x8B6A), PACK(0x892C), PACK(0x88EE),
+        PACK(0x83B0), PACK(0x8272), PACK(0x8034), PACK(0x81F6),
+        PACK(0x84B8), PACK(0x857A), PACK(0x873C), PACK(0x86FE),
+        PACK(0xA9C0), PACK(0xA802), PACK(0xAA44), PACK(0xAB86),
+        PACK(0xAEC8), PACK(0xAF0A), PACK(0xAD4C), PACK(0xAC8E),
+        PACK(0xA7D0), PACK(0xA612), PACK(0xA454), PACK(0xA596),
+        PACK(0xA0D8), PACK(0xA11A), PACK(0xA35C), PACK(0xA29E),
+        PACK(0xB5E0), PACK(0xB422), PACK(0xB664), PACK(0xB7A6),
+        PACK(0xB2E8), PACK(0xB32A), PACK(0xB16C), PACK(0xB0AE),
+        PACK(0xBBF0), PACK(0xBA32), PACK(0xB874), PACK(0xB9B6),
+        PACK(0xBCF8), PACK(0xBD3A), PACK(0xBF7C), PACK(0xBEBE)
+    };
+
+    while (1) {
+        Z.hi ^= Htable[n].hi;
+        Z.lo ^= Htable[n].lo;
+
+        if ((u8 *)Xi == xi)
+            break;
+
+        n = *(--xi);
+
+        rem = (size_t)Z.lo & 0xff;
+        Z.lo = (Z.hi << 56) | (Z.lo >> 8);
+        Z.hi = (Z.hi >> 8);
+        if (sizeof(size_t) == 8)
+            Z.hi ^= rem_8bit[rem];
+        else
+            Z.hi ^= (u64)rem_8bit[rem] << 32;
+    }
+
+    if (is_endian.little) {
+# ifdef BSWAP8
+        Xi[0] = BSWAP8(Z.hi);
+        Xi[1] = BSWAP8(Z.lo);
+# else
+        u8 *p = (u8 *)Xi;
+        u32 v;
+        v = (u32)(Z.hi >> 32);
+        PUTU32(p, v);
+        v = (u32)(Z.hi);
+        PUTU32(p + 4, v);
+        v = (u32)(Z.lo >> 32);
+        PUTU32(p + 8, v);
+        v = (u32)(Z.lo);
+        PUTU32(p + 12, v);
+# endif
+    } else {
+        Xi[0] = Z.hi;
+        Xi[1] = Z.lo;
+    }
+}
+
+# define GCM_MUL(ctx,Xi)   gcm_gmult_8bit(ctx->Xi.u,ctx->Htable)
+
+#elif   TABLE_BITS==4
+
+static void gcm_init_4bit(u128 Htable[16], u64 H[2])
+{
+    u128 V;
+# if defined(OPENSSL_SMALL_FOOTPRINT)
+    int i;
+# endif
+
+    Htable[0].hi = 0;
+    Htable[0].lo = 0;
+    V.hi = H[0];
+    V.lo = H[1];
+
+# if defined(OPENSSL_SMALL_FOOTPRINT)
+    for (Htable[8] = V, i = 4; i > 0; i >>= 1) {
+        REDUCE1BIT(V);
+        Htable[i] = V;
+    }
+
+    for (i = 2; i < 16; i <<= 1) {
+        u128 *Hi = Htable + i;
+        int j;
+        for (V = *Hi, j = 1; j < i; ++j) {
+            Hi[j].hi = V.hi ^ Htable[j].hi;
+            Hi[j].lo = V.lo ^ Htable[j].lo;
+        }
+    }
+# else
+    Htable[8] = V;
+    REDUCE1BIT(V);
+    Htable[4] = V;
+    REDUCE1BIT(V);
+    Htable[2] = V;
+    REDUCE1BIT(V);
+    Htable[1] = V;
+    Htable[3].hi = V.hi ^ Htable[2].hi, Htable[3].lo = V.lo ^ Htable[2].lo;
+    V = Htable[4];
+    Htable[5].hi = V.hi ^ Htable[1].hi, Htable[5].lo = V.lo ^ Htable[1].lo;
+    Htable[6].hi = V.hi ^ Htable[2].hi, Htable[6].lo = V.lo ^ Htable[2].lo;
+    Htable[7].hi = V.hi ^ Htable[3].hi, Htable[7].lo = V.lo ^ Htable[3].lo;
+    V = Htable[8];
+    Htable[9].hi = V.hi ^ Htable[1].hi, Htable[9].lo = V.lo ^ Htable[1].lo;
+    Htable[10].hi = V.hi ^ Htable[2].hi, Htable[10].lo = V.lo ^ Htable[2].lo;
+    Htable[11].hi = V.hi ^ Htable[3].hi, Htable[11].lo = V.lo ^ Htable[3].lo;
+    Htable[12].hi = V.hi ^ Htable[4].hi, Htable[12].lo = V.lo ^ Htable[4].lo;
+    Htable[13].hi = V.hi ^ Htable[5].hi, Htable[13].lo = V.lo ^ Htable[5].lo;
+    Htable[14].hi = V.hi ^ Htable[6].hi, Htable[14].lo = V.lo ^ Htable[6].lo;
+    Htable[15].hi = V.hi ^ Htable[7].hi, Htable[15].lo = V.lo ^ Htable[7].lo;
+# endif
+# if defined(GHASH_ASM) && (defined(__arm__) || defined(__arm))
+    /*
+     * ARM assembler expects specific dword order in Htable.
+     */
+    {
+        int j;
+        const union {
+            long one;
+            char little;
+        } is_endian = { 1 };
+
+        if (is_endian.little)
+            for (j = 0; j < 16; ++j) {
+                V = Htable[j];
+                Htable[j].hi = V.lo;
+                Htable[j].lo = V.hi;
+        } else
+            for (j = 0; j < 16; ++j) {
+                V = Htable[j];
+                Htable[j].hi = V.lo << 32 | V.lo >> 32;
+                Htable[j].lo = V.hi << 32 | V.hi >> 32;
+            }
+    }
+# endif
+}
+
+# ifndef GHASH_ASM
+static const size_t rem_4bit[16] = {
+    PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460),
+    PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0),
+    PACK(0xE100), PACK(0xFD20), PACK(0xD940), PACK(0xC560),
+    PACK(0x9180), PACK(0x8DA0), PACK(0xA9C0), PACK(0xB5E0)
+};
+
+static void gcm_gmult_4bit(u64 Xi[2], const u128 Htable[16])
+{
+    u128 Z;
+    int cnt = 15;
+    size_t rem, nlo, nhi;
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+
+    nlo = ((const u8 *)Xi)[15];
+    nhi = nlo >> 4;
+    nlo &= 0xf;
+
+    Z.hi = Htable[nlo].hi;
+    Z.lo = Htable[nlo].lo;
+
+    while (1) {
+        rem = (size_t)Z.lo & 0xf;
+        Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+        Z.hi = (Z.hi >> 4);
+        if (sizeof(size_t) == 8)
+            Z.hi ^= rem_4bit[rem];
+        else
+            Z.hi ^= (u64)rem_4bit[rem] << 32;
+
+        Z.hi ^= Htable[nhi].hi;
+        Z.lo ^= Htable[nhi].lo;
+
+        if (--cnt < 0)
+            break;
+
+        nlo = ((const u8 *)Xi)[cnt];
+        nhi = nlo >> 4;
+        nlo &= 0xf;
+
+        rem = (size_t)Z.lo & 0xf;
+        Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+        Z.hi = (Z.hi >> 4);
+        if (sizeof(size_t) == 8)
+            Z.hi ^= rem_4bit[rem];
+        else
+            Z.hi ^= (u64)rem_4bit[rem] << 32;
+
+        Z.hi ^= Htable[nlo].hi;
+        Z.lo ^= Htable[nlo].lo;
+    }
+
+    if (is_endian.little) {
+#  ifdef BSWAP8
+        Xi[0] = BSWAP8(Z.hi);
+        Xi[1] = BSWAP8(Z.lo);
+#  else
+        u8 *p = (u8 *)Xi;
+        u32 v;
+        v = (u32)(Z.hi >> 32);
+        PUTU32(p, v);
+        v = (u32)(Z.hi);
+        PUTU32(p + 4, v);
+        v = (u32)(Z.lo >> 32);
+        PUTU32(p + 8, v);
+        v = (u32)(Z.lo);
+        PUTU32(p + 12, v);
+#  endif
+    } else {
+        Xi[0] = Z.hi;
+        Xi[1] = Z.lo;
+    }
+}
+
+#  if !defined(OPENSSL_SMALL_FOOTPRINT)
+/*
+ * Streamed gcm_mult_4bit, see CRYPTO_gcm128_[en|de]crypt for
+ * details... Compiler-generated code doesn't seem to give any
+ * performance improvement, at least not on x86[_64]. It's here
+ * mostly as reference and a placeholder for possible future
+ * non-trivial optimization[s]...
+ */
+static void gcm_ghash_4bit(u64 Xi[2], const u128 Htable[16],
+                           const u8 *inp, size_t len)
+{
+    u128 Z;
+    int cnt;
+    size_t rem, nlo, nhi;
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+
+#   if 1
+    do {
+        cnt = 15;
+        nlo = ((const u8 *)Xi)[15];
+        nlo ^= inp[15];
+        nhi = nlo >> 4;
+        nlo &= 0xf;
+
+        Z.hi = Htable[nlo].hi;
+        Z.lo = Htable[nlo].lo;
+
+        while (1) {
+            rem = (size_t)Z.lo & 0xf;
+            Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+            Z.hi = (Z.hi >> 4);
+            if (sizeof(size_t) == 8)
+                Z.hi ^= rem_4bit[rem];
+            else
+                Z.hi ^= (u64)rem_4bit[rem] << 32;
+
+            Z.hi ^= Htable[nhi].hi;
+            Z.lo ^= Htable[nhi].lo;
+
+            if (--cnt < 0)
+                break;
+
+            nlo = ((const u8 *)Xi)[cnt];
+            nlo ^= inp[cnt];
+            nhi = nlo >> 4;
+            nlo &= 0xf;
+
+            rem = (size_t)Z.lo & 0xf;
+            Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+            Z.hi = (Z.hi >> 4);
+            if (sizeof(size_t) == 8)
+                Z.hi ^= rem_4bit[rem];
+            else
+                Z.hi ^= (u64)rem_4bit[rem] << 32;
+
+            Z.hi ^= Htable[nlo].hi;
+            Z.lo ^= Htable[nlo].lo;
+        }
+#   else
+    /*
+     * Extra 256+16 bytes per-key plus 512 bytes shared tables
+     * [should] give ~50% improvement... One could have PACK()-ed
+     * the rem_8bit even here, but the priority is to minimize
+     * cache footprint...
+     */
+    u128 Hshr4[16];             /* Htable shifted right by 4 bits */
+    u8 Hshl4[16];               /* Htable shifted left by 4 bits */
+    static const unsigned short rem_8bit[256] = {
+        0x0000, 0x01C2, 0x0384, 0x0246, 0x0708, 0x06CA, 0x048C, 0x054E,
+        0x0E10, 0x0FD2, 0x0D94, 0x0C56, 0x0918, 0x08DA, 0x0A9C, 0x0B5E,
+        0x1C20, 0x1DE2, 0x1FA4, 0x1E66, 0x1B28, 0x1AEA, 0x18AC, 0x196E,
+        0x1230, 0x13F2, 0x11B4, 0x1076, 0x1538, 0x14FA, 0x16BC, 0x177E,
+        0x3840, 0x3982, 0x3BC4, 0x3A06, 0x3F48, 0x3E8A, 0x3CCC, 0x3D0E,
+        0x3650, 0x3792, 0x35D4, 0x3416, 0x3158, 0x309A, 0x32DC, 0x331E,
+        0x2460, 0x25A2, 0x27E4, 0x2626, 0x2368, 0x22AA, 0x20EC, 0x212E,
+        0x2A70, 0x2BB2, 0x29F4, 0x2836, 0x2D78, 0x2CBA, 0x2EFC, 0x2F3E,
+        0x7080, 0x7142, 0x7304, 0x72C6, 0x7788, 0x764A, 0x740C, 0x75CE,
+        0x7E90, 0x7F52, 0x7D14, 0x7CD6, 0x7998, 0x785A, 0x7A1C, 0x7BDE,
+        0x6CA0, 0x6D62, 0x6F24, 0x6EE6, 0x6BA8, 0x6A6A, 0x682C, 0x69EE,
+        0x62B0, 0x6372, 0x6134, 0x60F6, 0x65B8, 0x647A, 0x663C, 0x67FE,
+        0x48C0, 0x4902, 0x4B44, 0x4A86, 0x4FC8, 0x4E0A, 0x4C4C, 0x4D8E,
+        0x46D0, 0x4712, 0x4554, 0x4496, 0x41D8, 0x401A, 0x425C, 0x439E,
+        0x54E0, 0x5522, 0x5764, 0x56A6, 0x53E8, 0x522A, 0x506C, 0x51AE,
+        0x5AF0, 0x5B32, 0x5974, 0x58B6, 0x5DF8, 0x5C3A, 0x5E7C, 0x5FBE,
+        0xE100, 0xE0C2, 0xE284, 0xE346, 0xE608, 0xE7CA, 0xE58C, 0xE44E,
+        0xEF10, 0xEED2, 0xEC94, 0xED56, 0xE818, 0xE9DA, 0xEB9C, 0xEA5E,
+        0xFD20, 0xFCE2, 0xFEA4, 0xFF66, 0xFA28, 0xFBEA, 0xF9AC, 0xF86E,
+        0xF330, 0xF2F2, 0xF0B4, 0xF176, 0xF438, 0xF5FA, 0xF7BC, 0xF67E,
+        0xD940, 0xD882, 0xDAC4, 0xDB06, 0xDE48, 0xDF8A, 0xDDCC, 0xDC0E,
+        0xD750, 0xD692, 0xD4D4, 0xD516, 0xD058, 0xD19A, 0xD3DC, 0xD21E,
+        0xC560, 0xC4A2, 0xC6E4, 0xC726, 0xC268, 0xC3AA, 0xC1EC, 0xC02E,
+        0xCB70, 0xCAB2, 0xC8F4, 0xC936, 0xCC78, 0xCDBA, 0xCFFC, 0xCE3E,
+        0x9180, 0x9042, 0x9204, 0x93C6, 0x9688, 0x974A, 0x950C, 0x94CE,
+        0x9F90, 0x9E52, 0x9C14, 0x9DD6, 0x9898, 0x995A, 0x9B1C, 0x9ADE,
+        0x8DA0, 0x8C62, 0x8E24, 0x8FE6, 0x8AA8, 0x8B6A, 0x892C, 0x88EE,
+        0x83B0, 0x8272, 0x8034, 0x81F6, 0x84B8, 0x857A, 0x873C, 0x86FE,
+        0xA9C0, 0xA802, 0xAA44, 0xAB86, 0xAEC8, 0xAF0A, 0xAD4C, 0xAC8E,
+        0xA7D0, 0xA612, 0xA454, 0xA596, 0xA0D8, 0xA11A, 0xA35C, 0xA29E,
+        0xB5E0, 0xB422, 0xB664, 0xB7A6, 0xB2E8, 0xB32A, 0xB16C, 0xB0AE,
+        0xBBF0, 0xBA32, 0xB874, 0xB9B6, 0xBCF8, 0xBD3A, 0xBF7C, 0xBEBE
+    };
+    /*
+     * This pre-processing phase slows down procedure by approximately
+     * same time as it makes each loop spin faster. In other words
+     * single block performance is approximately same as straightforward
+     * "4-bit" implementation, and then it goes only faster...
+     */
+    for (cnt = 0; cnt < 16; ++cnt) {
+        Z.hi = Htable[cnt].hi;
+        Z.lo = Htable[cnt].lo;
+        Hshr4[cnt].lo = (Z.hi << 60) | (Z.lo >> 4);
+        Hshr4[cnt].hi = (Z.hi >> 4);
+        Hshl4[cnt] = (u8)(Z.lo << 4);
+    }
+
+    do {
+        for (Z.lo = 0, Z.hi = 0, cnt = 15; cnt; --cnt) {
+            nlo = ((const u8 *)Xi)[cnt];
+            nlo ^= inp[cnt];
+            nhi = nlo >> 4;
+            nlo &= 0xf;
+
+            Z.hi ^= Htable[nlo].hi;
+            Z.lo ^= Htable[nlo].lo;
+
+            rem = (size_t)Z.lo & 0xff;
+
+            Z.lo = (Z.hi << 56) | (Z.lo >> 8);
+            Z.hi = (Z.hi >> 8);
+
+            Z.hi ^= Hshr4[nhi].hi;
+            Z.lo ^= Hshr4[nhi].lo;
+            Z.hi ^= (u64)rem_8bit[rem ^ Hshl4[nhi]] << 48;
+        }
+
+        nlo = ((const u8 *)Xi)[0];
+        nlo ^= inp[0];
+        nhi = nlo >> 4;
+        nlo &= 0xf;
+
+        Z.hi ^= Htable[nlo].hi;
+        Z.lo ^= Htable[nlo].lo;
+
+        rem = (size_t)Z.lo & 0xf;
+
+        Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+        Z.hi = (Z.hi >> 4);
+
+        Z.hi ^= Htable[nhi].hi;
+        Z.lo ^= Htable[nhi].lo;
+        Z.hi ^= ((u64)rem_8bit[rem << 4]) << 48;
+#   endif
+
+        if (is_endian.little) {
+#   ifdef BSWAP8
+            Xi[0] = BSWAP8(Z.hi);
+            Xi[1] = BSWAP8(Z.lo);
+#   else
+            u8 *p = (u8 *)Xi;
+            u32 v;
+            v = (u32)(Z.hi >> 32);
+            PUTU32(p, v);
+            v = (u32)(Z.hi);
+            PUTU32(p + 4, v);
+            v = (u32)(Z.lo >> 32);
+            PUTU32(p + 8, v);
+            v = (u32)(Z.lo);
+            PUTU32(p + 12, v);
+#   endif
+        } else {
+            Xi[0] = Z.hi;
+            Xi[1] = Z.lo;
+        }
+    } while (inp += 16, len -= 16);
+}
+#  endif
+# else
+void gcm_gmult_4bit(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_4bit(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                    size_t len);
+# endif
+
+# define GCM_MUL(ctx,Xi)   gcm_gmult_4bit(ctx->Xi.u,ctx->Htable)
+# if defined(GHASH_ASM) || !defined(OPENSSL_SMALL_FOOTPRINT)
+#  define GHASH(ctx,in,len) gcm_ghash_4bit((ctx)->Xi.u,(ctx)->Htable,in,len)
+/*
+ * GHASH_CHUNK is "stride parameter" missioned to mitigate cache trashing
+ * effect. In other words idea is to hash data while it's still in L1 cache
+ * after encryption pass...
+ */
+#  define GHASH_CHUNK       (3*1024)
+# endif
+
+#else                           /* TABLE_BITS */
+
+static void gcm_gmult_1bit(u64 Xi[2], const u64 H[2])
+{
+    u128 V, Z = { 0, 0 };
+    long X;
+    int i, j;
+    const long *xi = (const long *)Xi;
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+
+    V.hi = H[0];                /* H is in host byte order, no byte swapping */
+    V.lo = H[1];
+
+    for (j = 0; j < 16 / sizeof(long); ++j) {
+        if (is_endian.little) {
+            if (sizeof(long) == 8) {
+# ifdef BSWAP8
+                X = (long)(BSWAP8(xi[j]));
+# else
+                const u8 *p = (const u8 *)(xi + j);
+                X = (long)((u64)GETU32(p) << 32 | GETU32(p + 4));
+# endif
+            } else {
+                const u8 *p = (const u8 *)(xi + j);
+                X = (long)GETU32(p);
+            }
+        } else
+            X = xi[j];
+
+        for (i = 0; i < 8 * sizeof(long); ++i, X <<= 1) {
+            u64 M = (u64)(X >> (8 * sizeof(long) - 1));
+            Z.hi ^= V.hi & M;
+            Z.lo ^= V.lo & M;
+
+            REDUCE1BIT(V);
+        }
+    }
+
+    if (is_endian.little) {
+# ifdef BSWAP8
+        Xi[0] = BSWAP8(Z.hi);
+        Xi[1] = BSWAP8(Z.lo);
+# else
+        u8 *p = (u8 *)Xi;
+        u32 v;
+        v = (u32)(Z.hi >> 32);
+        PUTU32(p, v);
+        v = (u32)(Z.hi);
+        PUTU32(p + 4, v);
+        v = (u32)(Z.lo >> 32);
+        PUTU32(p + 8, v);
+        v = (u32)(Z.lo);
+        PUTU32(p + 12, v);
+# endif
+    } else {
+        Xi[0] = Z.hi;
+        Xi[1] = Z.lo;
+    }
+}
+
+# define GCM_MUL(ctx,Xi)   gcm_gmult_1bit(ctx->Xi.u,ctx->H.u)
+
+#endif
+
+#if     TABLE_BITS==4 && (defined(GHASH_ASM) || defined(OPENSSL_CPUID_OBJ))
+# if    !defined(I386_ONLY) && \
+        (defined(__i386)        || defined(__i386__)    || \
+         defined(__x86_64)      || defined(__x86_64__)  || \
+         defined(_M_IX86)       || defined(_M_AMD64)    || defined(_M_X64))
+#  define GHASH_ASM_X86_OR_64
+#  define GCM_FUNCREF_4BIT
+extern unsigned int OPENSSL_ia32cap_P[];
+
+void gcm_init_clmul(u128 Htable[16], const u64 Xi[2]);
+void gcm_gmult_clmul(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_clmul(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                     size_t len);
+
+#  if defined(__i386) || defined(__i386__) || defined(_M_IX86)
+#   define gcm_init_avx   gcm_init_clmul
+#   define gcm_gmult_avx  gcm_gmult_clmul
+#   define gcm_ghash_avx  gcm_ghash_clmul
+#  else
+void gcm_init_avx(u128 Htable[16], const u64 Xi[2]);
+void gcm_gmult_avx(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_avx(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                   size_t len);
+#  endif
+
+#  if   defined(__i386) || defined(__i386__) || defined(_M_IX86)
+#   define GHASH_ASM_X86
+void gcm_gmult_4bit_mmx(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_4bit_mmx(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                        size_t len);
+
+void gcm_gmult_4bit_x86(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_4bit_x86(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                        size_t len);
+#  endif
+# elif defined(__arm__) || defined(__arm) || defined(__aarch64__)
+#  include "arm_arch.h"
+#  if __ARM_MAX_ARCH__>=7
+#   define GHASH_ASM_ARM
+#   define GCM_FUNCREF_4BIT
+#   define PMULL_CAPABLE        (OPENSSL_armcap_P & ARMV8_PMULL)
+#   if defined(__arm__) || defined(__arm)
+#    define NEON_CAPABLE        (OPENSSL_armcap_P & ARMV7_NEON)
+#   endif
+void gcm_init_neon(u128 Htable[16], const u64 Xi[2]);
+void gcm_gmult_neon(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_neon(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                    size_t len);
+void gcm_init_v8(u128 Htable[16], const u64 Xi[2]);
+void gcm_gmult_v8(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_v8(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                  size_t len);
+#  endif
+# elif defined(__sparc__) || defined(__sparc)
+#  include "sparc_arch.h"
+#  define GHASH_ASM_SPARC
+#  define GCM_FUNCREF_4BIT
+extern unsigned int OPENSSL_sparcv9cap_P[];
+void gcm_init_vis3(u128 Htable[16], const u64 Xi[2]);
+void gcm_gmult_vis3(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_vis3(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                    size_t len);
+# elif defined(OPENSSL_CPUID_OBJ) && (defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC))
+#  include "ppc_arch.h"
+#  define GHASH_ASM_PPC
+#  define GCM_FUNCREF_4BIT
+void gcm_init_p8(u128 Htable[16], const u64 Xi[2]);
+void gcm_gmult_p8(u64 Xi[2], const u128 Htable[16]);
+void gcm_ghash_p8(u64 Xi[2], const u128 Htable[16], const u8 *inp,
+                  size_t len);
+# endif
+#endif
+
+#ifdef GCM_FUNCREF_4BIT
+# undef  GCM_MUL
+# define GCM_MUL(ctx,Xi)        (*gcm_gmult_p)(ctx->Xi.u,ctx->Htable)
+# ifdef GHASH
+#  undef  GHASH
+#  define GHASH(ctx,in,len)     (*gcm_ghash_p)(ctx->Xi.u,ctx->Htable,in,len)
+# endif
+#endif
+
+void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block)
+{
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+
+    memset(ctx, 0, sizeof(*ctx));
+    ctx->block = block;
+    ctx->key = key;
+
+    (*block) (ctx->H.c, ctx->H.c, key);
+
+    if (is_endian.little) {
+        /* H is stored in host byte order */
+#ifdef BSWAP8
+        ctx->H.u[0] = BSWAP8(ctx->H.u[0]);
+        ctx->H.u[1] = BSWAP8(ctx->H.u[1]);
+#else
+        u8 *p = ctx->H.c;
+        u64 hi, lo;
+        hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
+        lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
+        ctx->H.u[0] = hi;
+        ctx->H.u[1] = lo;
+#endif
+    }
+#if     TABLE_BITS==8
+    gcm_init_8bit(ctx->Htable, ctx->H.u);
+#elif   TABLE_BITS==4
+# if    defined(GHASH)
+#  define CTX__GHASH(f) (ctx->ghash = (f))
+# else
+#  define CTX__GHASH(f) (ctx->ghash = NULL)
+# endif
+# if    defined(GHASH_ASM_X86_OR_64)
+#  if   !defined(GHASH_ASM_X86) || defined(OPENSSL_IA32_SSE2)
+    if (OPENSSL_ia32cap_P[0] & (1 << 24) && /* check FXSR bit */
+        OPENSSL_ia32cap_P[1] & (1 << 1)) { /* check PCLMULQDQ bit */
+        if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */
+            gcm_init_avx(ctx->Htable, ctx->H.u);
+            ctx->gmult = gcm_gmult_avx;
+            CTX__GHASH(gcm_ghash_avx);
+        } else {
+            gcm_init_clmul(ctx->Htable, ctx->H.u);
+            ctx->gmult = gcm_gmult_clmul;
+            CTX__GHASH(gcm_ghash_clmul);
+        }
+        return;
+    }
+#  endif
+    gcm_init_4bit(ctx->Htable, ctx->H.u);
+#  if   defined(GHASH_ASM_X86)  /* x86 only */
+#   if  defined(OPENSSL_IA32_SSE2)
+    if (OPENSSL_ia32cap_P[0] & (1 << 25)) { /* check SSE bit */
+#   else
+    if (OPENSSL_ia32cap_P[0] & (1 << 23)) { /* check MMX bit */
+#   endif
+        ctx->gmult = gcm_gmult_4bit_mmx;
+        CTX__GHASH(gcm_ghash_4bit_mmx);
+    } else {
+        ctx->gmult = gcm_gmult_4bit_x86;
+        CTX__GHASH(gcm_ghash_4bit_x86);
+    }
+#  else
+    ctx->gmult = gcm_gmult_4bit;
+    CTX__GHASH(gcm_ghash_4bit);
+#  endif
+# elif  defined(GHASH_ASM_ARM)
+#  ifdef PMULL_CAPABLE
+    if (PMULL_CAPABLE) {
+        gcm_init_v8(ctx->Htable, ctx->H.u);
+        ctx->gmult = gcm_gmult_v8;
+        CTX__GHASH(gcm_ghash_v8);
+    } else
+#  endif
+#  ifdef NEON_CAPABLE
+    if (NEON_CAPABLE) {
+        gcm_init_neon(ctx->Htable, ctx->H.u);
+        ctx->gmult = gcm_gmult_neon;
+        CTX__GHASH(gcm_ghash_neon);
+    } else
+#  endif
+    {
+        gcm_init_4bit(ctx->Htable, ctx->H.u);
+        ctx->gmult = gcm_gmult_4bit;
+        CTX__GHASH(gcm_ghash_4bit);
+    }
+# elif  defined(GHASH_ASM_SPARC)
+    if (OPENSSL_sparcv9cap_P[0] & SPARCV9_VIS3) {
+        gcm_init_vis3(ctx->Htable, ctx->H.u);
+        ctx->gmult = gcm_gmult_vis3;
+        CTX__GHASH(gcm_ghash_vis3);
+    } else {
+        gcm_init_4bit(ctx->Htable, ctx->H.u);
+        ctx->gmult = gcm_gmult_4bit;
+        CTX__GHASH(gcm_ghash_4bit);
+    }
+# elif  defined(GHASH_ASM_PPC)
+    if (OPENSSL_ppccap_P & PPC_CRYPTO207) {
+        gcm_init_p8(ctx->Htable, ctx->H.u);
+        ctx->gmult = gcm_gmult_p8;
+        CTX__GHASH(gcm_ghash_p8);
+    } else {
+        gcm_init_4bit(ctx->Htable, ctx->H.u);
+        ctx->gmult = gcm_gmult_4bit;
+        CTX__GHASH(gcm_ghash_4bit);
+    }
+# else
+    gcm_init_4bit(ctx->Htable, ctx->H.u);
+# endif
+# undef CTX__GHASH
+#endif
+}
+
+void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const unsigned char *iv,
+                         size_t len)
+{
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+    unsigned int ctr;
+#ifdef GCM_FUNCREF_4BIT
+    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
+#endif
+
+    ctx->Yi.u[0] = 0;
+    ctx->Yi.u[1] = 0;
+    ctx->Xi.u[0] = 0;
+    ctx->Xi.u[1] = 0;
+    ctx->len.u[0] = 0;          /* AAD length */
+    ctx->len.u[1] = 0;          /* message length */
+    ctx->ares = 0;
+    ctx->mres = 0;
+
+    if (len == 12) {
+        memcpy(ctx->Yi.c, iv, 12);
+        ctx->Yi.c[15] = 1;
+        ctr = 1;
+    } else {
+        size_t i;
+        u64 len0 = len;
+
+        while (len >= 16) {
+            for (i = 0; i < 16; ++i)
+                ctx->Yi.c[i] ^= iv[i];
+            GCM_MUL(ctx, Yi);
+            iv += 16;
+            len -= 16;
+        }
+        if (len) {
+            for (i = 0; i < len; ++i)
+                ctx->Yi.c[i] ^= iv[i];
+            GCM_MUL(ctx, Yi);
+        }
+        len0 <<= 3;
+        if (is_endian.little) {
+#ifdef BSWAP8
+            ctx->Yi.u[1] ^= BSWAP8(len0);
+#else
+            ctx->Yi.c[8] ^= (u8)(len0 >> 56);
+            ctx->Yi.c[9] ^= (u8)(len0 >> 48);
+            ctx->Yi.c[10] ^= (u8)(len0 >> 40);
+            ctx->Yi.c[11] ^= (u8)(len0 >> 32);
+            ctx->Yi.c[12] ^= (u8)(len0 >> 24);
+            ctx->Yi.c[13] ^= (u8)(len0 >> 16);
+            ctx->Yi.c[14] ^= (u8)(len0 >> 8);
+            ctx->Yi.c[15] ^= (u8)(len0);
+#endif
+        } else
+            ctx->Yi.u[1] ^= len0;
+
+        GCM_MUL(ctx, Yi);
+
+        if (is_endian.little)
+#ifdef BSWAP4
+            ctr = BSWAP4(ctx->Yi.d[3]);
+#else
+            ctr = GETU32(ctx->Yi.c + 12);
+#endif
+        else
+            ctr = ctx->Yi.d[3];
+    }
+
+    (*ctx->block) (ctx->Yi.c, ctx->EK0.c, ctx->key);
+    ++ctr;
+    if (is_endian.little)
+#ifdef BSWAP4
+        ctx->Yi.d[3] = BSWAP4(ctr);
+#else
+        PUTU32(ctx->Yi.c + 12, ctr);
+#endif
+    else
+        ctx->Yi.d[3] = ctr;
+}
+
+int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const unsigned char *aad,
+                      size_t len)
+{
+    size_t i;
+    unsigned int n;
+    u64 alen = ctx->len.u[0];
+#ifdef GCM_FUNCREF_4BIT
+    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
+# ifdef GHASH
+    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
+                         const u8 *inp, size_t len) = ctx->ghash;
+# endif
+#endif
+
+    if (ctx->len.u[1])
+        return -2;
+
+    alen += len;
+    if (alen > (U64(1) << 61) || (sizeof(len) == 8 && alen < len))
+        return -1;
+    ctx->len.u[0] = alen;
+
+    n = ctx->ares;
+    if (n) {
+        while (n && len) {
+            ctx->Xi.c[n] ^= *(aad++);
+            --len;
+            n = (n + 1) % 16;
+        }
+        if (n == 0)
+            GCM_MUL(ctx, Xi);
+        else {
+            ctx->ares = n;
+            return 0;
+        }
+    }
+#ifdef GHASH
+    if ((i = (len & (size_t)-16))) {
+        GHASH(ctx, aad, i);
+        aad += i;
+        len -= i;
+    }
+#else
+    while (len >= 16) {
+        for (i = 0; i < 16; ++i)
+            ctx->Xi.c[i] ^= aad[i];
+        GCM_MUL(ctx, Xi);
+        aad += 16;
+        len -= 16;
+    }
+#endif
+    if (len) {
+        n = (unsigned int)len;
+        for (i = 0; i < len; ++i)
+            ctx->Xi.c[i] ^= aad[i];
+    }
+
+    ctx->ares = n;
+    return 0;
+}
+
+int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx,
+                          const unsigned char *in, unsigned char *out,
+                          size_t len)
+{
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+    unsigned int n, ctr;
+    size_t i;
+    u64 mlen = ctx->len.u[1];
+    block128_f block = ctx->block;
+    void *key = ctx->key;
+#ifdef GCM_FUNCREF_4BIT
+    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
+# if defined(GHASH) && !defined(OPENSSL_SMALL_FOOTPRINT)
+    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
+                         const u8 *inp, size_t len) = ctx->ghash;
+# endif
+#endif
+
+    mlen += len;
+    if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
+        return -1;
+    ctx->len.u[1] = mlen;
+
+    if (ctx->ares) {
+        /* First call to encrypt finalizes GHASH(AAD) */
+        GCM_MUL(ctx, Xi);
+        ctx->ares = 0;
+    }
+
+    if (is_endian.little)
+#ifdef BSWAP4
+        ctr = BSWAP4(ctx->Yi.d[3]);
+#else
+        ctr = GETU32(ctx->Yi.c + 12);
+#endif
+    else
+        ctr = ctx->Yi.d[3];
+
+    n = ctx->mres;
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+    if (16 % sizeof(size_t) == 0) { /* always true actually */
+        do {
+            if (n) {
+                while (n && len) {
+                    ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n];
+                    --len;
+                    n = (n + 1) % 16;
+                }
+                if (n == 0)
+                    GCM_MUL(ctx, Xi);
+                else {
+                    ctx->mres = n;
+                    return 0;
+                }
+            }
+# if defined(STRICT_ALIGNMENT)
+            if (((size_t)in | (size_t)out) % sizeof(size_t) != 0)
+                break;
+# endif
+# if defined(GHASH)
+#  if defined(GHASH_CHUNK)
+            while (len >= GHASH_CHUNK) {
+                size_t j = GHASH_CHUNK;
+
+                while (j) {
+                    size_t *out_t = (size_t *)out;
+                    const size_t *in_t = (const size_t *)in;
+
+                    (*block) (ctx->Yi.c, ctx->EKi.c, key);
+                    ++ctr;
+                    if (is_endian.little)
+#   ifdef BSWAP4
+                        ctx->Yi.d[3] = BSWAP4(ctr);
+#   else
+                        PUTU32(ctx->Yi.c + 12, ctr);
+#   endif
+                    else
+                        ctx->Yi.d[3] = ctr;
+                    for (i = 0; i < 16 / sizeof(size_t); ++i)
+                        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+                    out += 16;
+                    in += 16;
+                    j -= 16;
+                }
+                GHASH(ctx, out - GHASH_CHUNK, GHASH_CHUNK);
+                len -= GHASH_CHUNK;
+            }
+#  endif
+            if ((i = (len & (size_t)-16))) {
+                size_t j = i;
+
+                while (len >= 16) {
+                    size_t *out_t = (size_t *)out;
+                    const size_t *in_t = (const size_t *)in;
+
+                    (*block) (ctx->Yi.c, ctx->EKi.c, key);
+                    ++ctr;
+                    if (is_endian.little)
+#  ifdef BSWAP4
+                        ctx->Yi.d[3] = BSWAP4(ctr);
+#  else
+                        PUTU32(ctx->Yi.c + 12, ctr);
+#  endif
+                    else
+                        ctx->Yi.d[3] = ctr;
+                    for (i = 0; i < 16 / sizeof(size_t); ++i)
+                        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+                    out += 16;
+                    in += 16;
+                    len -= 16;
+                }
+                GHASH(ctx, out - j, j);
+            }
+# else
+            while (len >= 16) {
+                size_t *out_t = (size_t *)out;
+                const size_t *in_t = (const size_t *)in;
+
+                (*block) (ctx->Yi.c, ctx->EKi.c, key);
+                ++ctr;
+                if (is_endian.little)
+#  ifdef BSWAP4
+                    ctx->Yi.d[3] = BSWAP4(ctr);
+#  else
+                    PUTU32(ctx->Yi.c + 12, ctr);
+#  endif
+                else
+                    ctx->Yi.d[3] = ctr;
+                for (i = 0; i < 16 / sizeof(size_t); ++i)
+                    ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+                GCM_MUL(ctx, Xi);
+                out += 16;
+                in += 16;
+                len -= 16;
+            }
+# endif
+            if (len) {
+                (*block) (ctx->Yi.c, ctx->EKi.c, key);
+                ++ctr;
+                if (is_endian.little)
+# ifdef BSWAP4
+                    ctx->Yi.d[3] = BSWAP4(ctr);
+# else
+                    PUTU32(ctx->Yi.c + 12, ctr);
+# endif
+                else
+                    ctx->Yi.d[3] = ctr;
+                while (len--) {
+                    ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n];
+                    ++n;
+                }
+            }
+
+            ctx->mres = n;
+            return 0;
+        } while (0);
+    }
+#endif
+    for (i = 0; i < len; ++i) {
+        if (n == 0) {
+            (*block) (ctx->Yi.c, ctx->EKi.c, key);
+            ++ctr;
+            if (is_endian.little)
+#ifdef BSWAP4
+                ctx->Yi.d[3] = BSWAP4(ctr);
+#else
+                PUTU32(ctx->Yi.c + 12, ctr);
+#endif
+            else
+                ctx->Yi.d[3] = ctr;
+        }
+        ctx->Xi.c[n] ^= out[i] = in[i] ^ ctx->EKi.c[n];
+        n = (n + 1) % 16;
+        if (n == 0)
+            GCM_MUL(ctx, Xi);
+    }
+
+    ctx->mres = n;
+    return 0;
+}
+
+int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx,
+                          const unsigned char *in, unsigned char *out,
+                          size_t len)
+{
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+    unsigned int n, ctr;
+    size_t i;
+    u64 mlen = ctx->len.u[1];
+    block128_f block = ctx->block;
+    void *key = ctx->key;
+#ifdef GCM_FUNCREF_4BIT
+    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
+# if defined(GHASH) && !defined(OPENSSL_SMALL_FOOTPRINT)
+    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
+                         const u8 *inp, size_t len) = ctx->ghash;
+# endif
+#endif
+
+    mlen += len;
+    if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
+        return -1;
+    ctx->len.u[1] = mlen;
+
+    if (ctx->ares) {
+        /* First call to decrypt finalizes GHASH(AAD) */
+        GCM_MUL(ctx, Xi);
+        ctx->ares = 0;
+    }
+
+    if (is_endian.little)
+#ifdef BSWAP4
+        ctr = BSWAP4(ctx->Yi.d[3]);
+#else
+        ctr = GETU32(ctx->Yi.c + 12);
+#endif
+    else
+        ctr = ctx->Yi.d[3];
+
+    n = ctx->mres;
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+    if (16 % sizeof(size_t) == 0) { /* always true actually */
+        do {
+            if (n) {
+                while (n && len) {
+                    u8 c = *(in++);
+                    *(out++) = c ^ ctx->EKi.c[n];
+                    ctx->Xi.c[n] ^= c;
+                    --len;
+                    n = (n + 1) % 16;
+                }
+                if (n == 0)
+                    GCM_MUL(ctx, Xi);
+                else {
+                    ctx->mres = n;
+                    return 0;
+                }
+            }
+# if defined(STRICT_ALIGNMENT)
+            if (((size_t)in | (size_t)out) % sizeof(size_t) != 0)
+                break;
+# endif
+# if defined(GHASH)
+#  if defined(GHASH_CHUNK)
+            while (len >= GHASH_CHUNK) {
+                size_t j = GHASH_CHUNK;
+
+                GHASH(ctx, in, GHASH_CHUNK);
+                while (j) {
+                    size_t *out_t = (size_t *)out;
+                    const size_t *in_t = (const size_t *)in;
+
+                    (*block) (ctx->Yi.c, ctx->EKi.c, key);
+                    ++ctr;
+                    if (is_endian.little)
+#   ifdef BSWAP4
+                        ctx->Yi.d[3] = BSWAP4(ctr);
+#   else
+                        PUTU32(ctx->Yi.c + 12, ctr);
+#   endif
+                    else
+                        ctx->Yi.d[3] = ctr;
+                    for (i = 0; i < 16 / sizeof(size_t); ++i)
+                        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+                    out += 16;
+                    in += 16;
+                    j -= 16;
+                }
+                len -= GHASH_CHUNK;
+            }
+#  endif
+            if ((i = (len & (size_t)-16))) {
+                GHASH(ctx, in, i);
+                while (len >= 16) {
+                    size_t *out_t = (size_t *)out;
+                    const size_t *in_t = (const size_t *)in;
+
+                    (*block) (ctx->Yi.c, ctx->EKi.c, key);
+                    ++ctr;
+                    if (is_endian.little)
+#  ifdef BSWAP4
+                        ctx->Yi.d[3] = BSWAP4(ctr);
+#  else
+                        PUTU32(ctx->Yi.c + 12, ctr);
+#  endif
+                    else
+                        ctx->Yi.d[3] = ctr;
+                    for (i = 0; i < 16 / sizeof(size_t); ++i)
+                        out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+                    out += 16;
+                    in += 16;
+                    len -= 16;
+                }
+            }
+# else
+            while (len >= 16) {
+                size_t *out_t = (size_t *)out;
+                const size_t *in_t = (const size_t *)in;
+
+                (*block) (ctx->Yi.c, ctx->EKi.c, key);
+                ++ctr;
+                if (is_endian.little)
+#  ifdef BSWAP4
+                    ctx->Yi.d[3] = BSWAP4(ctr);
+#  else
+                    PUTU32(ctx->Yi.c + 12, ctr);
+#  endif
+                else
+                    ctx->Yi.d[3] = ctr;
+                for (i = 0; i < 16 / sizeof(size_t); ++i) {
+                    size_t c = in[i];
+                    out[i] = c ^ ctx->EKi.t[i];
+                    ctx->Xi.t[i] ^= c;
+                }
+                GCM_MUL(ctx, Xi);
+                out += 16;
+                in += 16;
+                len -= 16;
+            }
+# endif
+            if (len) {
+                (*block) (ctx->Yi.c, ctx->EKi.c, key);
+                ++ctr;
+                if (is_endian.little)
+# ifdef BSWAP4
+                    ctx->Yi.d[3] = BSWAP4(ctr);
+# else
+                    PUTU32(ctx->Yi.c + 12, ctr);
+# endif
+                else
+                    ctx->Yi.d[3] = ctr;
+                while (len--) {
+                    u8 c = in[n];
+                    ctx->Xi.c[n] ^= c;
+                    out[n] = c ^ ctx->EKi.c[n];
+                    ++n;
+                }
+            }
+
+            ctx->mres = n;
+            return 0;
+        } while (0);
+    }
+#endif
+    for (i = 0; i < len; ++i) {
+        u8 c;
+        if (n == 0) {
+            (*block) (ctx->Yi.c, ctx->EKi.c, key);
+            ++ctr;
+            if (is_endian.little)
+#ifdef BSWAP4
+                ctx->Yi.d[3] = BSWAP4(ctr);
+#else
+                PUTU32(ctx->Yi.c + 12, ctr);
+#endif
+            else
+                ctx->Yi.d[3] = ctr;
+        }
+        c = in[i];
+        out[i] = c ^ ctx->EKi.c[n];
+        ctx->Xi.c[n] ^= c;
+        n = (n + 1) % 16;
+        if (n == 0)
+            GCM_MUL(ctx, Xi);
+    }
+
+    ctx->mres = n;
+    return 0;
+}
+
+int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx,
+                                const unsigned char *in, unsigned char *out,
+                                size_t len, ctr128_f stream)
+{
+#if defined(OPENSSL_SMALL_FOOTPRINT)
+    return CRYPTO_gcm128_encrypt(ctx, in, out, len);
+#else
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+    unsigned int n, ctr;
+    size_t i;
+    u64 mlen = ctx->len.u[1];
+    void *key = ctx->key;
+# ifdef GCM_FUNCREF_4BIT
+    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
+#  ifdef GHASH
+    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
+                         const u8 *inp, size_t len) = ctx->ghash;
+#  endif
+# endif
+
+    mlen += len;
+    if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
+        return -1;
+    ctx->len.u[1] = mlen;
+
+    if (ctx->ares) {
+        /* First call to encrypt finalizes GHASH(AAD) */
+        GCM_MUL(ctx, Xi);
+        ctx->ares = 0;
+    }
+
+    if (is_endian.little)
+# ifdef BSWAP4
+        ctr = BSWAP4(ctx->Yi.d[3]);
+# else
+        ctr = GETU32(ctx->Yi.c + 12);
+# endif
+    else
+        ctr = ctx->Yi.d[3];
+
+    n = ctx->mres;
+    if (n) {
+        while (n && len) {
+            ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n];
+            --len;
+            n = (n + 1) % 16;
+        }
+        if (n == 0)
+            GCM_MUL(ctx, Xi);
+        else {
+            ctx->mres = n;
+            return 0;
+        }
+    }
+# if defined(GHASH) && defined(GHASH_CHUNK)
+    while (len >= GHASH_CHUNK) {
+        (*stream) (in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
+        ctr += GHASH_CHUNK / 16;
+        if (is_endian.little)
+#  ifdef BSWAP4
+            ctx->Yi.d[3] = BSWAP4(ctr);
+#  else
+            PUTU32(ctx->Yi.c + 12, ctr);
+#  endif
+        else
+            ctx->Yi.d[3] = ctr;
+        GHASH(ctx, out, GHASH_CHUNK);
+        out += GHASH_CHUNK;
+        in += GHASH_CHUNK;
+        len -= GHASH_CHUNK;
+    }
+# endif
+    if ((i = (len & (size_t)-16))) {
+        size_t j = i / 16;
+
+        (*stream) (in, out, j, key, ctx->Yi.c);
+        ctr += (unsigned int)j;
+        if (is_endian.little)
+# ifdef BSWAP4
+            ctx->Yi.d[3] = BSWAP4(ctr);
+# else
+            PUTU32(ctx->Yi.c + 12, ctr);
+# endif
+        else
+            ctx->Yi.d[3] = ctr;
+        in += i;
+        len -= i;
+# if defined(GHASH)
+        GHASH(ctx, out, i);
+        out += i;
+# else
+        while (j--) {
+            for (i = 0; i < 16; ++i)
+                ctx->Xi.c[i] ^= out[i];
+            GCM_MUL(ctx, Xi);
+            out += 16;
+        }
+# endif
+    }
+    if (len) {
+        (*ctx->block) (ctx->Yi.c, ctx->EKi.c, key);
+        ++ctr;
+        if (is_endian.little)
+# ifdef BSWAP4
+            ctx->Yi.d[3] = BSWAP4(ctr);
+# else
+            PUTU32(ctx->Yi.c + 12, ctr);
+# endif
+        else
+            ctx->Yi.d[3] = ctr;
+        while (len--) {
+            ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n];
+            ++n;
+        }
+    }
+
+    ctx->mres = n;
+    return 0;
+#endif
+}
+
+int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx,
+                                const unsigned char *in, unsigned char *out,
+                                size_t len, ctr128_f stream)
+{
+#if defined(OPENSSL_SMALL_FOOTPRINT)
+    return CRYPTO_gcm128_decrypt(ctx, in, out, len);
+#else
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+    unsigned int n, ctr;
+    size_t i;
+    u64 mlen = ctx->len.u[1];
+    void *key = ctx->key;
+# ifdef GCM_FUNCREF_4BIT
+    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
+#  ifdef GHASH
+    void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
+                         const u8 *inp, size_t len) = ctx->ghash;
+#  endif
+# endif
+
+    mlen += len;
+    if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
+        return -1;
+    ctx->len.u[1] = mlen;
+
+    if (ctx->ares) {
+        /* First call to decrypt finalizes GHASH(AAD) */
+        GCM_MUL(ctx, Xi);
+        ctx->ares = 0;
+    }
+
+    if (is_endian.little)
+# ifdef BSWAP4
+        ctr = BSWAP4(ctx->Yi.d[3]);
+# else
+        ctr = GETU32(ctx->Yi.c + 12);
+# endif
+    else
+        ctr = ctx->Yi.d[3];
+
+    n = ctx->mres;
+    if (n) {
+        while (n && len) {
+            u8 c = *(in++);
+            *(out++) = c ^ ctx->EKi.c[n];
+            ctx->Xi.c[n] ^= c;
+            --len;
+            n = (n + 1) % 16;
+        }
+        if (n == 0)
+            GCM_MUL(ctx, Xi);
+        else {
+            ctx->mres = n;
+            return 0;
+        }
+    }
+# if defined(GHASH) && defined(GHASH_CHUNK)
+    while (len >= GHASH_CHUNK) {
+        GHASH(ctx, in, GHASH_CHUNK);
+        (*stream) (in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
+        ctr += GHASH_CHUNK / 16;
+        if (is_endian.little)
+#  ifdef BSWAP4
+            ctx->Yi.d[3] = BSWAP4(ctr);
+#  else
+            PUTU32(ctx->Yi.c + 12, ctr);
+#  endif
+        else
+            ctx->Yi.d[3] = ctr;
+        out += GHASH_CHUNK;
+        in += GHASH_CHUNK;
+        len -= GHASH_CHUNK;
+    }
+# endif
+    if ((i = (len & (size_t)-16))) {
+        size_t j = i / 16;
+
+# if defined(GHASH)
+        GHASH(ctx, in, i);
+# else
+        while (j--) {
+            size_t k;
+            for (k = 0; k < 16; ++k)
+                ctx->Xi.c[k] ^= in[k];
+            GCM_MUL(ctx, Xi);
+            in += 16;
+        }
+        j = i / 16;
+        in -= i;
+# endif
+        (*stream) (in, out, j, key, ctx->Yi.c);
+        ctr += (unsigned int)j;
+        if (is_endian.little)
+# ifdef BSWAP4
+            ctx->Yi.d[3] = BSWAP4(ctr);
+# else
+            PUTU32(ctx->Yi.c + 12, ctr);
+# endif
+        else
+            ctx->Yi.d[3] = ctr;
+        out += i;
+        in += i;
+        len -= i;
+    }
+    if (len) {
+        (*ctx->block) (ctx->Yi.c, ctx->EKi.c, key);
+        ++ctr;
+        if (is_endian.little)
+# ifdef BSWAP4
+            ctx->Yi.d[3] = BSWAP4(ctr);
+# else
+            PUTU32(ctx->Yi.c + 12, ctr);
+# endif
+        else
+            ctx->Yi.d[3] = ctr;
+        while (len--) {
+            u8 c = in[n];
+            ctx->Xi.c[n] ^= c;
+            out[n] = c ^ ctx->EKi.c[n];
+            ++n;
+        }
+    }
+
+    ctx->mres = n;
+    return 0;
+#endif
+}
+
+int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const unsigned char *tag,
+                         size_t len)
+{
+    const union {
+        long one;
+        char little;
+    } is_endian = { 1 };
+    u64 alen = ctx->len.u[0] << 3;
+    u64 clen = ctx->len.u[1] << 3;
+#ifdef GCM_FUNCREF_4BIT
+    void (*gcm_gmult_p) (u64 Xi[2], const u128 Htable[16]) = ctx->gmult;
+#endif
+
+    if (ctx->mres || ctx->ares)
+        GCM_MUL(ctx, Xi);
+
+    if (is_endian.little) {
+#ifdef BSWAP8
+        alen = BSWAP8(alen);
+        clen = BSWAP8(clen);
+#else
+        u8 *p = ctx->len.c;
+
+        ctx->len.u[0] = alen;
+        ctx->len.u[1] = clen;
+
+        alen = (u64)GETU32(p) << 32 | GETU32(p + 4);
+        clen = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
+#endif
+    }
+
+    ctx->Xi.u[0] ^= alen;
+    ctx->Xi.u[1] ^= clen;
+    GCM_MUL(ctx, Xi);
+
+    ctx->Xi.u[0] ^= ctx->EK0.u[0];
+    ctx->Xi.u[1] ^= ctx->EK0.u[1];
+
+    if (tag && len <= sizeof(ctx->Xi))
+        return CRYPTO_memcmp(ctx->Xi.c, tag, len);
+    else
+        return -1;
+}
+
+void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len)
+{
+    CRYPTO_gcm128_finish(ctx, NULL, 0);
+    memcpy(tag, ctx->Xi.c,
+           len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c));
+}
+
+GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block)
+{
+    GCM128_CONTEXT *ret;
+
+    if ((ret = OPENSSL_malloc(sizeof(*ret))) != NULL)
+        CRYPTO_gcm128_init(ret, key, block);
+
+    return ret;
+}
+
+void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx)
+{
+    OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+#if defined(SELFTEST)
+# include <stdio.h>
+# include <openssl/aes.h>
+
+/* Test Case 1 */
+static const u8 K1[16], *P1 = NULL, *A1 = NULL, IV1[12], *C1 = NULL;
+static const u8 T1[] = {
+    0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
+    0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a
+};
+
+/* Test Case 2 */
+# define K2 K1
+# define A2 A1
+# define IV2 IV1
+static const u8 P2[16];
+static const u8 C2[] = {
+    0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
+    0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78
+};
+
+static const u8 T2[] = {
+    0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
+    0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf
+};
+
+/* Test Case 3 */
+# define A3 A2
+static const u8 K3[] = {
+    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
+};
+
+static const u8 P3[] = {
+    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55
+};
+
+static const u8 IV3[] = {
+    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+    0xde, 0xca, 0xf8, 0x88
+};
+
+static const u8 C3[] = {
+    0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+    0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+    0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+    0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+    0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+    0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+    0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+    0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85
+};
+
+static const u8 T3[] = {
+    0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
+    0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4
+};
+
+/* Test Case 4 */
+# define K4 K3
+# define IV4 IV3
+static const u8 P4[] = {
+    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+    0xba, 0x63, 0x7b, 0x39
+};
+
+static const u8 A4[] = {
+    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+    0xab, 0xad, 0xda, 0xd2
+};
+
+static const u8 C4[] = {
+    0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+    0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+    0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+    0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+    0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+    0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+    0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+    0x3d, 0x58, 0xe0, 0x91
+};
+
+static const u8 T4[] = {
+    0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
+    0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47
+};
+
+/* Test Case 5 */
+# define K5 K4
+# define P5 P4
+# define A5 A4
+static const u8 IV5[] = {
+    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad
+};
+
+static const u8 C5[] = {
+    0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a,
+    0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55,
+    0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8,
+    0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23,
+    0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2,
+    0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42,
+    0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07,
+    0xc2, 0x3f, 0x45, 0x98
+};
+
+static const u8 T5[] = {
+    0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85,
+    0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb
+};
+
+/* Test Case 6 */
+# define K6 K5
+# define P6 P5
+# define A6 A5
+static const u8 IV6[] = {
+    0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
+    0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
+    0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
+    0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
+    0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
+    0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
+    0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
+    0xa6, 0x37, 0xb3, 0x9b
+};
+
+static const u8 C6[] = {
+    0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6,
+    0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94,
+    0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8,
+    0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7,
+    0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90,
+    0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f,
+    0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03,
+    0x4c, 0x34, 0xae, 0xe5
+};
+
+static const u8 T6[] = {
+    0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa,
+    0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50
+};
+
+/* Test Case 7 */
+static const u8 K7[24], *P7 = NULL, *A7 = NULL, IV7[12], *C7 = NULL;
+static const u8 T7[] = {
+    0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b,
+    0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35
+};
+
+/* Test Case 8 */
+# define K8 K7
+# define IV8 IV7
+# define A8 A7
+static const u8 P8[16];
+static const u8 C8[] = {
+    0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41,
+    0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00
+};
+
+static const u8 T8[] = {
+    0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab,
+    0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb
+};
+
+/* Test Case 9 */
+# define A9 A8
+static const u8 K9[] = {
+    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c
+};
+
+static const u8 P9[] = {
+    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55
+};
+
+static const u8 IV9[] = {
+    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+    0xde, 0xca, 0xf8, 0x88
+};
+
+static const u8 C9[] = {
+    0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+    0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+    0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+    0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+    0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+    0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+    0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+    0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56
+};
+
+static const u8 T9[] = {
+    0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf,
+    0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14
+};
+
+/* Test Case 10 */
+# define K10 K9
+# define IV10 IV9
+static const u8 P10[] = {
+    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+    0xba, 0x63, 0x7b, 0x39
+};
+
+static const u8 A10[] = {
+    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+    0xab, 0xad, 0xda, 0xd2
+};
+
+static const u8 C10[] = {
+    0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41,
+    0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57,
+    0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
+    0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c,
+    0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25,
+    0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
+    0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9,
+    0xcc, 0xda, 0x27, 0x10
+};
+
+static const u8 T10[] = {
+    0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f,
+    0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c
+};
+
+/* Test Case 11 */
+# define K11 K10
+# define P11 P10
+# define A11 A10
+static const u8 IV11[] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
+
+static const u8 C11[] = {
+    0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54,
+    0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8,
+    0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f,
+    0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57,
+    0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75,
+    0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9,
+    0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f,
+    0xa0, 0xf0, 0x62, 0xf7
+};
+
+static const u8 T11[] = {
+    0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24,
+    0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8
+};
+
+/* Test Case 12 */
+# define K12 K11
+# define P12 P11
+# define A12 A11
+static const u8 IV12[] = {
+    0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
+    0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
+    0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
+    0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
+    0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
+    0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
+    0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
+    0xa6, 0x37, 0xb3, 0x9b
+};
+
+static const u8 C12[] = {
+    0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c,
+    0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff,
+    0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef,
+    0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45,
+    0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9,
+    0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3,
+    0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7,
+    0xe9, 0xb7, 0x37, 0x3b
+};
+
+static const u8 T12[] = {
+    0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb,
+    0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9
+};
+
+/* Test Case 13 */
+static const u8 K13[32], *P13 = NULL, *A13 = NULL, IV13[12], *C13 = NULL;
+static const u8 T13[] = {
+    0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9,
+    0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b
+};
+
+/* Test Case 14 */
+# define K14 K13
+# define A14 A13
+static const u8 P14[16], IV14[12];
+static const u8 C14[] = {
+    0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
+    0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18
+};
+
+static const u8 T14[] = {
+    0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0,
+    0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19
+};
+
+/* Test Case 15 */
+# define A15 A14
+static const u8 K15[] = {
+    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
+};
+
+static const u8 P15[] = {
+    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55
+};
+
+static const u8 IV15[] = {
+    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+    0xde, 0xca, 0xf8, 0x88
+};
+
+static const u8 C15[] = {
+    0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+    0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+    0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+    0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+    0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+    0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad
+};
+
+static const u8 T15[] = {
+    0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
+    0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c
+};
+
+/* Test Case 16 */
+# define K16 K15
+# define IV16 IV15
+static const u8 P16[] = {
+    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+    0xba, 0x63, 0x7b, 0x39
+};
+
+static const u8 A16[] = {
+    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+    0xab, 0xad, 0xda, 0xd2
+};
+
+static const u8 C16[] = {
+    0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+    0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+    0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+    0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+    0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+    0xbc, 0xc9, 0xf6, 0x62
+};
+
+static const u8 T16[] = {
+    0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
+    0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b
+};
+
+/* Test Case 17 */
+# define K17 K16
+# define P17 P16
+# define A17 A16
+static const u8 IV17[] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
+
+static const u8 C17[] = {
+    0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32,
+    0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb,
+    0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa,
+    0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0,
+    0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0,
+    0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78,
+    0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99,
+    0xf4, 0x7c, 0x9b, 0x1f
+};
+
+static const u8 T17[] = {
+    0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4,
+    0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2
+};
+
+/* Test Case 18 */
+# define K18 K17
+# define P18 P17
+# define A18 A17
+static const u8 IV18[] = {
+    0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
+    0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
+    0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
+    0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
+    0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
+    0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
+    0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
+    0xa6, 0x37, 0xb3, 0x9b
+};
+
+static const u8 C18[] = {
+    0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1,
+    0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20,
+    0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19,
+    0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4,
+    0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45,
+    0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde,
+    0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e,
+    0x44, 0xae, 0x7e, 0x3f
+};
+
+static const u8 T18[] = {
+    0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0,
+    0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a
+};
+
+/* Test Case 19 */
+# define K19 K1
+# define P19 P1
+# define IV19 IV1
+# define C19 C1
+static const u8 A19[] = {
+    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+    0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55,
+    0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+    0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+    0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+    0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+    0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+    0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad
+};
+
+static const u8 T19[] = {
+    0x5f, 0xea, 0x79, 0x3a, 0x2d, 0x6f, 0x97, 0x4d,
+    0x37, 0xe6, 0x8e, 0x0c, 0xb8, 0xff, 0x94, 0x92
+};
+
+/* Test Case 20 */
+# define K20 K1
+# define A20 A1
+/* this results in 0xff in counter LSB */
+static const u8 IV20[64] = { 0xff, 0xff, 0xff, 0xff };
+
+static const u8 P20[288];
+static const u8 C20[] = {
+    0x56, 0xb3, 0x37, 0x3c, 0xa9, 0xef, 0x6e, 0x4a,
+    0x2b, 0x64, 0xfe, 0x1e, 0x9a, 0x17, 0xb6, 0x14,
+    0x25, 0xf1, 0x0d, 0x47, 0xa7, 0x5a, 0x5f, 0xce,
+    0x13, 0xef, 0xc6, 0xbc, 0x78, 0x4a, 0xf2, 0x4f,
+    0x41, 0x41, 0xbd, 0xd4, 0x8c, 0xf7, 0xc7, 0x70,
+    0x88, 0x7a, 0xfd, 0x57, 0x3c, 0xca, 0x54, 0x18,
+    0xa9, 0xae, 0xff, 0xcd, 0x7c, 0x5c, 0xed, 0xdf,
+    0xc6, 0xa7, 0x83, 0x97, 0xb9, 0xa8, 0x5b, 0x49,
+    0x9d, 0xa5, 0x58, 0x25, 0x72, 0x67, 0xca, 0xab,
+    0x2a, 0xd0, 0xb2, 0x3c, 0xa4, 0x76, 0xa5, 0x3c,
+    0xb1, 0x7f, 0xb4, 0x1c, 0x4b, 0x8b, 0x47, 0x5c,
+    0xb4, 0xf3, 0xf7, 0x16, 0x50, 0x94, 0xc2, 0x29,
+    0xc9, 0xe8, 0xc4, 0xdc, 0x0a, 0x2a, 0x5f, 0xf1,
+    0x90, 0x3e, 0x50, 0x15, 0x11, 0x22, 0x13, 0x76,
+    0xa1, 0xcd, 0xb8, 0x36, 0x4c, 0x50, 0x61, 0xa2,
+    0x0c, 0xae, 0x74, 0xbc, 0x4a, 0xcd, 0x76, 0xce,
+    0xb0, 0xab, 0xc9, 0xfd, 0x32, 0x17, 0xef, 0x9f,
+    0x8c, 0x90, 0xbe, 0x40, 0x2d, 0xdf, 0x6d, 0x86,
+    0x97, 0xf4, 0xf8, 0x80, 0xdf, 0xf1, 0x5b, 0xfb,
+    0x7a, 0x6b, 0x28, 0x24, 0x1e, 0xc8, 0xfe, 0x18,
+    0x3c, 0x2d, 0x59, 0xe3, 0xf9, 0xdf, 0xff, 0x65,
+    0x3c, 0x71, 0x26, 0xf0, 0xac, 0xb9, 0xe6, 0x42,
+    0x11, 0xf4, 0x2b, 0xae, 0x12, 0xaf, 0x46, 0x2b,
+    0x10, 0x70, 0xbe, 0xf1, 0xab, 0x5e, 0x36, 0x06,
+    0x87, 0x2c, 0xa1, 0x0d, 0xee, 0x15, 0xb3, 0x24,
+    0x9b, 0x1a, 0x1b, 0x95, 0x8f, 0x23, 0x13, 0x4c,
+    0x4b, 0xcc, 0xb7, 0xd0, 0x32, 0x00, 0xbc, 0xe4,
+    0x20, 0xa2, 0xf8, 0xeb, 0x66, 0xdc, 0xf3, 0x64,
+    0x4d, 0x14, 0x23, 0xc1, 0xb5, 0x69, 0x90, 0x03,
+    0xc1, 0x3e, 0xce, 0xf4, 0xbf, 0x38, 0xa3, 0xb6,
+    0x0e, 0xed, 0xc3, 0x40, 0x33, 0xba, 0xc1, 0x90,
+    0x27, 0x83, 0xdc, 0x6d, 0x89, 0xe2, 0xe7, 0x74,
+    0x18, 0x8a, 0x43, 0x9c, 0x7e, 0xbc, 0xc0, 0x67,
+    0x2d, 0xbd, 0xa4, 0xdd, 0xcf, 0xb2, 0x79, 0x46,
+    0x13, 0xb0, 0xbe, 0x41, 0x31, 0x5e, 0xf7, 0x78,
+    0x70, 0x8a, 0x70, 0xee, 0x7d, 0x75, 0x16, 0x5c
+};
+
+static const u8 T20[] = {
+    0x8b, 0x30, 0x7f, 0x6b, 0x33, 0x28, 0x6d, 0x0a,
+    0xb0, 0x26, 0xa9, 0xed, 0x3f, 0xe1, 0xe8, 0x5f
+};
+
+# define TEST_CASE(n)    do {                                    \
+        u8 out[sizeof(P##n)];                                   \
+        AES_set_encrypt_key(K##n,sizeof(K##n)*8,&key);          \
+        CRYPTO_gcm128_init(&ctx,&key,(block128_f)AES_encrypt);  \
+        CRYPTO_gcm128_setiv(&ctx,IV##n,sizeof(IV##n));          \
+        memset(out,0,sizeof(out));                              \
+        if (A##n) CRYPTO_gcm128_aad(&ctx,A##n,sizeof(A##n));    \
+        if (P##n) CRYPTO_gcm128_encrypt(&ctx,P##n,out,sizeof(out));     \
+        if (CRYPTO_gcm128_finish(&ctx,T##n,16) ||               \
+            (C##n && memcmp(out,C##n,sizeof(out))))             \
+                ret++, printf ("encrypt test#%d failed.\n",n);  \
+        CRYPTO_gcm128_setiv(&ctx,IV##n,sizeof(IV##n));          \
+        memset(out,0,sizeof(out));                              \
+        if (A##n) CRYPTO_gcm128_aad(&ctx,A##n,sizeof(A##n));    \
+        if (C##n) CRYPTO_gcm128_decrypt(&ctx,C##n,out,sizeof(out));     \
+        if (CRYPTO_gcm128_finish(&ctx,T##n,16) ||               \
+            (P##n && memcmp(out,P##n,sizeof(out))))             \
+                ret++, printf ("decrypt test#%d failed.\n",n);  \
+        } while(0)
+
+int main()
+{
+    GCM128_CONTEXT ctx;
+    AES_KEY key;
+    int ret = 0;
+
+    TEST_CASE(1);
+    TEST_CASE(2);
+    TEST_CASE(3);
+    TEST_CASE(4);
+    TEST_CASE(5);
+    TEST_CASE(6);
+    TEST_CASE(7);
+    TEST_CASE(8);
+    TEST_CASE(9);
+    TEST_CASE(10);
+    TEST_CASE(11);
+    TEST_CASE(12);
+    TEST_CASE(13);
+    TEST_CASE(14);
+    TEST_CASE(15);
+    TEST_CASE(16);
+    TEST_CASE(17);
+    TEST_CASE(18);
+    TEST_CASE(19);
+    TEST_CASE(20);
+
+# ifdef OPENSSL_CPUID_OBJ
+    {
+        size_t start, stop, gcm_t, ctr_t, OPENSSL_rdtsc();
+        union {
+            u64 u;
+            u8 c[1024];
+        } buf;
+        int i;
+
+        AES_set_encrypt_key(K1, sizeof(K1) * 8, &key);
+        CRYPTO_gcm128_init(&ctx, &key, (block128_f) AES_encrypt);
+        CRYPTO_gcm128_setiv(&ctx, IV1, sizeof(IV1));
+
+        CRYPTO_gcm128_encrypt(&ctx, buf.c, buf.c, sizeof(buf));
+        start = OPENSSL_rdtsc();
+        CRYPTO_gcm128_encrypt(&ctx, buf.c, buf.c, sizeof(buf));
+        gcm_t = OPENSSL_rdtsc() - start;
+
+        CRYPTO_ctr128_encrypt(buf.c, buf.c, sizeof(buf),
+                              &key, ctx.Yi.c, ctx.EKi.c, &ctx.mres,
+                              (block128_f) AES_encrypt);
+        start = OPENSSL_rdtsc();
+        CRYPTO_ctr128_encrypt(buf.c, buf.c, sizeof(buf),
+                              &key, ctx.Yi.c, ctx.EKi.c, &ctx.mres,
+                              (block128_f) AES_encrypt);
+        ctr_t = OPENSSL_rdtsc() - start;
+
+        printf("%.2f-%.2f=%.2f\n",
+               gcm_t / (double)sizeof(buf),
+               ctr_t / (double)sizeof(buf),
+               (gcm_t - ctr_t) / (double)sizeof(buf));
+#  ifdef GHASH
+        {
+            void (*gcm_ghash_p) (u64 Xi[2], const u128 Htable[16],
+                                 const u8 *inp, size_t len) = ctx.ghash;
+
+            GHASH((&ctx), buf.c, sizeof(buf));
+            start = OPENSSL_rdtsc();
+            for (i = 0; i < 100; ++i)
+                GHASH((&ctx), buf.c, sizeof(buf));
+            gcm_t = OPENSSL_rdtsc() - start;
+            printf("%.2f\n", gcm_t / (double)sizeof(buf) / (double)i);
+        }
+#  endif
+    }
+# endif
+
+    return ret;
+}
+#endif

+ 204 - 0
components/SM/src/modes/gcmf.c

@@ -0,0 +1,204 @@
+#include <openssl/modes.h>
+
+int gcmf_init(gcmf_context *ctx, void *key, block128_f block)
+{
+	memset(ctx->tag, 0, sizeof(GCM_FILE_TAG_LEN));
+	ctx->gcm = (GCM128_CONTEXT *)malloc(sizeof(GCM128_CONTEXT));
+	CRYPTO_gcm128_init(ctx->gcm, key, block);
+	return 0;
+}
+
+int gcmf_free(gcmf_context *ctx)
+{
+	int ret = CRYPTO_gcm128_finish(ctx->gcm, ctx->tag, GCM_FILE_TAG_LEN);
+	if (ret != 0)
+	{
+		return ret;
+	}
+	CRYPTO_gcm128_release(ctx->gcm);
+	//    free(ctx->gcm);
+	memset(ctx, 0, sizeof(gcmf_context));
+	return 0;
+}
+
+int gcmf_set_iv(gcmf_context *ctx, const unsigned char *iv, size_t len)
+{
+	CRYPTO_gcm128_setiv(ctx->gcm, iv, len);
+	return 0;
+}
+
+int gcmf_encrypt_file(gcmf_context *ctx, char *infpath, char *outfpath)
+{
+	int len_outfpath, file_size, block_size;
+	FILE *infp, *tmpfp, *outfp;
+	char *tmp_file_path = NULL;
+	unsigned char buf[GCM_FILE_MAX_BLOCK_LEN];
+	unsigned char out[GCM_FILE_MAX_BLOCK_LEN];
+	unsigned char size_buf[sizeof(size_t)];
+
+	int ver = GCM_FILE_VERSION;
+	// #0 Open file
+	len_outfpath = strlen(outfpath);
+	tmp_file_path = (char *)malloc((len_outfpath + 5) * sizeof(char));
+	memcpy(tmp_file_path, outfpath, len_outfpath);
+	memcpy(tmp_file_path + len_outfpath, ".tmp", 5);
+
+	if ((infp = fopen(infpath, "rb")) == NULL)
+		return -1;
+	if ((tmpfp = fopen(tmp_file_path, "wb+")) == NULL)
+		return -2;
+	if ((outfp = fopen(outfpath, "wb+")) == NULL)
+		return -3;
+
+	// #1 Encrypt file (slice blocks)
+
+	memset(buf, 0, GCM_FILE_MAX_BLOCK_LEN);
+	memset(out, 0, GCM_FILE_MAX_BLOCK_LEN);
+
+	// Get size of file
+	fseek(infp, 0, SEEK_END);
+	file_size = ftell(infp);
+	memset(size_buf, 0, sizeof(size_t));
+	memcpy(size_buf, &file_size, sizeof(size_t));
+	fseek(infp, 0, SEEK_SET);
+
+	// GCM Block encrypt
+	while (
+		(block_size = fread(buf, sizeof(unsigned char), GCM_FILE_MAX_BLOCK_LEN, infp)) &&
+		block_size != 0)
+	{
+		CRYPTO_gcm128_encrypt(ctx->gcm, buf, out, block_size);
+		fwrite(out, sizeof(unsigned char), block_size, tmpfp);
+
+		memset(buf, 0, GCM_FILE_MAX_BLOCK_LEN);
+		memset(out, 0, GCM_FILE_MAX_BLOCK_LEN);
+	}
+
+	// Get Tag of GCM encrypt
+	CRYPTO_gcm128_tag(ctx->gcm, ctx->tag, GCM_FILE_TAG_LEN);
+
+	// Finish encrypt
+	fflush(tmpfp);
+	fseek(tmpfp, 0, SEEK_SET);
+	fclose(infp);
+
+	// #2 Write cipher file
+
+	// add file flag
+	fputs(GCM_FILE_MAGIC_TAG, outfp);
+	// add version (default: 1)
+
+	fwrite(&ver, sizeof(int), 1, outfp);
+	// add tag
+	fwrite(&ctx->tag, sizeof(unsigned char), GCM_FILE_TAG_LEN, outfp);
+	// add file len
+	fwrite(size_buf, sizeof(unsigned char), sizeof(size_t), outfp);
+	// copy cipher
+	memset(buf, 0, GCM_FILE_MAX_BLOCK_LEN);
+	while (
+		(block_size = fread(buf, sizeof(unsigned char), GCM_FILE_MAX_BLOCK_LEN, tmpfp)) &&
+		block_size != 0)
+	{
+		fwrite(buf, sizeof(unsigned char), block_size, outfp);
+		memset(buf, 0, GCM_FILE_MAX_BLOCK_LEN);
+	}
+
+	fclose(tmpfp);
+	fclose(outfp);
+	remove(tmp_file_path);
+	free(tmp_file_path);
+
+	return 0;
+}
+
+int gcmf_decrypt_file(gcmf_context *ctx, char *infpath, char *outfpath)
+{
+	int ret = 0;
+	int file_size = 0, read_size = 0, block_size;
+	unsigned char size_buf[sizeof(size_t)];
+	char flag[GCM_FILE_TAG_LEN + 1];
+	FILE *infp, *outfp;
+	int version;
+	unsigned char buf[GCM_FILE_MAX_BLOCK_LEN];
+	unsigned char out[GCM_FILE_MAX_BLOCK_LEN];
+	memset(buf, 0, GCM_FILE_MAX_BLOCK_LEN);
+	memset(out, 0, GCM_FILE_MAX_BLOCK_LEN);
+
+	if ((infp = fopen(infpath, "rb")) == NULL)
+	{
+		return -1;
+	}
+
+	memset(flag, 0, sizeof(flag));
+	//read file flag
+	fgets(flag, GCM_FILE_MAGIC_TAG_LEN + 1, infp);
+	if (strcmp(flag, GCM_FILE_MAGIC_TAG))
+	{
+		ret = -2;
+		goto end;
+	}
+
+	//read version
+
+	if (fread(&version, sizeof(version), 1, infp) == 0)
+	{
+		ret = -3;
+		goto end;
+	}
+	if (version != GCM_FILE_VERSION)
+	{
+		ret = -3;
+		goto end;
+	}
+
+	//read tag
+	if (fread(ctx->tag, sizeof(unsigned char), GCM_FILE_TAG_LEN, infp) == 0)
+	{
+		ret = -4;
+		goto end;
+	}
+
+	memset(size_buf, 0, sizeof(size_t));
+	// read real length
+	if (fread(size_buf, sizeof(unsigned char), sizeof(size_t), infp) == 0)
+	{
+		ret = -5;
+		goto end;
+	}
+	file_size = (int)((((size_buf[3] & 0xff) << 24) | ((size_buf[2] & 0xff) << 16) | ((size_buf[1] & 0xff) << 8) | ((size_buf[0] & 0xff) << 0)));
+
+	// Write Plaintext
+	if ((outfp = fopen(outfpath, "wb+")) == NULL)
+	{
+		ret = -6;
+		goto end;
+	}
+
+	CRYPTO_gcm128_tag(ctx->gcm, ctx->tag, GCM_FILE_TAG_LEN);
+
+	while (
+		(block_size = fread(buf, sizeof(unsigned char), GCM_FILE_MAX_BLOCK_LEN, infp)) &&
+		block_size != 0)
+	{
+		CRYPTO_gcm128_decrypt(ctx->gcm, buf, out, block_size);
+		read_size += block_size;
+		fwrite(out, sizeof(unsigned char), block_size, outfp);
+
+		memset(buf, 0, GCM_FILE_MAX_BLOCK_LEN);
+		memset(out, 0, GCM_FILE_MAX_BLOCK_LEN);
+	}
+
+	fflush(outfp);
+	// Invalid file
+	if (read_size != file_size)
+	{
+		ret = -7;
+		goto end;
+	}
+
+end:
+	fclose(infp);
+	fclose(outfp);
+
+	return ret;
+}

+ 567 - 0
components/SM/src/modes/ocb128.c

@@ -0,0 +1,567 @@
+/*
+ * Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include "modes_lcl.h"
+
+#ifndef OPENSSL_NO_OCB
+
+/*
+ * Calculate the number of binary trailing zero's in any given number
+ */
+static u32 ocb_ntz(u64 n)
+{
+    u32 cnt = 0;
+
+    /*
+     * We do a right-to-left simple sequential search. This is surprisingly
+     * efficient as the distribution of trailing zeros is not uniform,
+     * e.g. the number of possible inputs with no trailing zeros is equal to
+     * the number with 1 or more; the number with exactly 1 is equal to the
+     * number with 2 or more, etc. Checking the last two bits covers 75% of
+     * all numbers. Checking the last three covers 87.5%
+     */
+    while (!(n & 1)) {
+        n >>= 1;
+        cnt++;
+    }
+    return cnt;
+}
+
+/*
+ * Shift a block of 16 bytes left by shift bits
+ */
+static void ocb_block_lshift(const unsigned char *in, size_t shift,
+                             unsigned char *out)
+{
+    unsigned char shift_mask;
+    int i;
+    unsigned char mask[15];
+
+    shift_mask = 0xff;
+    shift_mask <<= (8 - shift);
+    for (i = 15; i >= 0; i--) {
+        if (i > 0) {
+            mask[i - 1] = in[i] & shift_mask;
+            mask[i - 1] >>= 8 - shift;
+        }
+        out[i] = in[i] << shift;
+
+        if (i != 15) {
+            out[i] ^= mask[i];
+        }
+    }
+}
+
+/*
+ * Perform a "double" operation as per OCB spec
+ */
+static void ocb_double(OCB_BLOCK *in, OCB_BLOCK *out)
+{
+    unsigned char mask;
+
+    /*
+     * Calculate the mask based on the most significant bit. There are more
+     * efficient ways to do this - but this way is constant time
+     */
+    mask = in->c[0] & 0x80;
+    mask >>= 7;
+    mask *= 135;
+
+    ocb_block_lshift(in->c, 1, out->c);
+
+    out->c[15] ^= mask;
+}
+
+/*
+ * Perform an xor on in1 and in2 - each of len bytes. Store result in out
+ */
+static void ocb_block_xor(const unsigned char *in1,
+                          const unsigned char *in2, size_t len,
+                          unsigned char *out)
+{
+    size_t i;
+    for (i = 0; i < len; i++) {
+        out[i] = in1[i] ^ in2[i];
+    }
+}
+
+/*
+ * Lookup L_index in our lookup table. If we haven't already got it we need to
+ * calculate it
+ */
+static OCB_BLOCK *ocb_lookup_l(OCB128_CONTEXT *ctx, size_t idx)
+{
+    size_t l_index = ctx->l_index;
+
+    if (idx <= l_index) {
+        return ctx->l + idx;
+    }
+
+    /* We don't have it - so calculate it */
+    if (idx >= ctx->max_l_index) {
+        void *tmp_ptr;
+        /*
+         * Each additional entry allows to process almost double as
+         * much data, so that in linear world the table will need to
+         * be expanded with smaller and smaller increments. Originally
+         * it was doubling in size, which was a waste. Growing it
+         * linearly is not formally optimal, but is simpler to implement.
+         * We grow table by minimally required 4*n that would accommodate
+         * the index.
+         */
+        ctx->max_l_index += (idx - ctx->max_l_index + 4) & ~3;
+        tmp_ptr =
+            OPENSSL_realloc(ctx->l, ctx->max_l_index * sizeof(OCB_BLOCK));
+        if (tmp_ptr == NULL) /* prevent ctx->l from being clobbered */
+            return NULL;
+        ctx->l = tmp_ptr;
+    }
+    while (l_index < idx) {
+        ocb_double(ctx->l + l_index, ctx->l + l_index + 1);
+        l_index++;
+    }
+    ctx->l_index = l_index;
+
+    return ctx->l + idx;
+}
+
+/*
+ * Create a new OCB128_CONTEXT
+ */
+OCB128_CONTEXT *CRYPTO_ocb128_new(void *keyenc, void *keydec,
+                                  block128_f encrypt, block128_f decrypt,
+                                  ocb128_f stream)
+{
+    OCB128_CONTEXT *octx;
+    int ret;
+
+    if ((octx = OPENSSL_malloc(sizeof(*octx))) != NULL) {
+        ret = CRYPTO_ocb128_init(octx, keyenc, keydec, encrypt, decrypt,
+                                 stream);
+        if (ret)
+            return octx;
+        OPENSSL_free(octx);
+    }
+
+    return NULL;
+}
+
+/*
+ * Initialise an existing OCB128_CONTEXT
+ */
+int CRYPTO_ocb128_init(OCB128_CONTEXT *ctx, void *keyenc, void *keydec,
+                       block128_f encrypt, block128_f decrypt,
+                       ocb128_f stream)
+{
+    memset(ctx, 0, sizeof(*ctx));
+    ctx->l_index = 0;
+    ctx->max_l_index = 5;
+    ctx->l = OPENSSL_malloc(ctx->max_l_index * 16);
+    if (ctx->l == NULL)
+        return 0;
+
+    /*
+     * We set both the encryption and decryption key schedules - decryption
+     * needs both. Don't really need decryption schedule if only doing
+     * encryption - but it simplifies things to take it anyway
+     */
+    ctx->encrypt = encrypt;
+    ctx->decrypt = decrypt;
+    ctx->stream = stream;
+    ctx->keyenc = keyenc;
+    ctx->keydec = keydec;
+
+    /* L_* = ENCIPHER(K, zeros(128)) */
+    ctx->encrypt(ctx->l_star.c, ctx->l_star.c, ctx->keyenc);
+
+    /* L_$ = double(L_*) */
+    ocb_double(&ctx->l_star, &ctx->l_dollar);
+
+    /* L_0 = double(L_$) */
+    ocb_double(&ctx->l_dollar, ctx->l);
+
+    /* L_{i} = double(L_{i-1}) */
+    ocb_double(ctx->l, ctx->l+1);
+    ocb_double(ctx->l+1, ctx->l+2);
+    ocb_double(ctx->l+2, ctx->l+3);
+    ocb_double(ctx->l+3, ctx->l+4);
+    ctx->l_index = 4;   /* enough to process up to 496 bytes */
+
+    return 1;
+}
+
+/*
+ * Copy an OCB128_CONTEXT object
+ */
+int CRYPTO_ocb128_copy_ctx(OCB128_CONTEXT *dest, OCB128_CONTEXT *src,
+                           void *keyenc, void *keydec)
+{
+    memcpy(dest, src, sizeof(OCB128_CONTEXT));
+    if (keyenc)
+        dest->keyenc = keyenc;
+    if (keydec)
+        dest->keydec = keydec;
+    if (src->l) {
+        dest->l = OPENSSL_malloc(src->max_l_index * 16);
+        if (dest->l == NULL)
+            return 0;
+        memcpy(dest->l, src->l, (src->l_index + 1) * 16);
+    }
+    return 1;
+}
+
+/*
+ * Set the IV to be used for this operation. Must be 1 - 15 bytes.
+ */
+int CRYPTO_ocb128_setiv(OCB128_CONTEXT *ctx, const unsigned char *iv,
+                        size_t len, size_t taglen)
+{
+    unsigned char ktop[16], tmp[16], mask;
+    unsigned char stretch[24], nonce[16];
+    size_t bottom, shift;
+
+    /*
+     * Spec says IV is 120 bits or fewer - it allows non byte aligned lengths.
+     * We don't support this at this stage
+     */
+    if ((len > 15) || (len < 1) || (taglen > 16) || (taglen < 1)) {
+        return -1;
+    }
+
+    /* Nonce = num2str(TAGLEN mod 128,7) || zeros(120-bitlen(N)) || 1 || N */
+    nonce[0] = ((taglen * 8) % 128) << 1;
+    memset(nonce + 1, 0, 15);
+    memcpy(nonce + 16 - len, iv, len);
+    nonce[15 - len] |= 1;
+
+    /* Ktop = ENCIPHER(K, Nonce[1..122] || zeros(6)) */
+    memcpy(tmp, nonce, 16);
+    tmp[15] &= 0xc0;
+    ctx->encrypt(tmp, ktop, ctx->keyenc);
+
+    /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */
+    memcpy(stretch, ktop, 16);
+    ocb_block_xor(ktop, ktop + 1, 8, stretch + 16);
+
+    /* bottom = str2num(Nonce[123..128]) */
+    bottom = nonce[15] & 0x3f;
+
+    /* Offset_0 = Stretch[1+bottom..128+bottom] */
+    shift = bottom % 8;
+    ocb_block_lshift(stretch + (bottom / 8), shift, ctx->offset.c);
+    mask = 0xff;
+    mask <<= 8 - shift;
+    ctx->offset.c[15] |=
+        (*(stretch + (bottom / 8) + 16) & mask) >> (8 - shift);
+
+    return 1;
+}
+
+/*
+ * Provide any AAD. This can be called multiple times. Only the final time can
+ * have a partial block
+ */
+int CRYPTO_ocb128_aad(OCB128_CONTEXT *ctx, const unsigned char *aad,
+                      size_t len)
+{
+    u64 i, all_num_blocks;
+    size_t num_blocks, last_len;
+    OCB_BLOCK tmp1;
+    OCB_BLOCK tmp2;
+
+    /* Calculate the number of blocks of AAD provided now, and so far */
+    num_blocks = len / 16;
+    all_num_blocks = num_blocks + ctx->blocks_hashed;
+
+    /* Loop through all full blocks of AAD */
+    for (i = ctx->blocks_hashed + 1; i <= all_num_blocks; i++) {
+        OCB_BLOCK *lookup;
+        OCB_BLOCK *aad_block;
+
+        /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+        lookup = ocb_lookup_l(ctx, ocb_ntz(i));
+        if (lookup == NULL)
+            return 0;
+        ocb_block16_xor(&ctx->offset_aad, lookup, &ctx->offset_aad);
+
+        /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */
+        aad_block = (OCB_BLOCK *)(aad + ((i - ctx->blocks_hashed - 1) * 16));
+        ocb_block16_xor(&ctx->offset_aad, aad_block, &tmp1);
+        ctx->encrypt(tmp1.c, tmp2.c, ctx->keyenc);
+        ocb_block16_xor(&ctx->sum, &tmp2, &ctx->sum);
+    }
+
+    /*
+     * Check if we have any partial blocks left over. This is only valid in the
+     * last call to this function
+     */
+    last_len = len % 16;
+
+    if (last_len > 0) {
+        /* Offset_* = Offset_m xor L_* */
+        ocb_block16_xor(&ctx->offset_aad, &ctx->l_star, &ctx->offset_aad);
+
+        /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* */
+        memset(&tmp1, 0, 16);
+        memcpy(&tmp1, aad + (num_blocks * 16), last_len);
+        ((unsigned char *)&tmp1)[last_len] = 0x80;
+        ocb_block16_xor(&ctx->offset_aad, &tmp1, &tmp2);
+
+        /* Sum = Sum_m xor ENCIPHER(K, CipherInput) */
+        ctx->encrypt(tmp2.c, tmp1.c, ctx->keyenc);
+        ocb_block16_xor(&ctx->sum, &tmp1, &ctx->sum);
+    }
+
+    ctx->blocks_hashed = all_num_blocks;
+
+    return 1;
+}
+
+/*
+ * Provide any data to be encrypted. This can be called multiple times. Only
+ * the final time can have a partial block
+ */
+int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
+                          const unsigned char *in, unsigned char *out,
+                          size_t len)
+{
+    u64 i, all_num_blocks;
+    size_t num_blocks, last_len;
+    OCB_BLOCK tmp1;
+    OCB_BLOCK tmp2;
+    OCB_BLOCK pad;
+
+    /*
+     * Calculate the number of blocks of data to be encrypted provided now, and
+     * so far
+     */
+    num_blocks = len / 16;
+    all_num_blocks = num_blocks + ctx->blocks_processed;
+
+    if (num_blocks && all_num_blocks == (size_t)all_num_blocks
+        && ctx->stream != NULL) {
+        size_t max_idx = 0, top = (size_t)all_num_blocks;
+
+        /*
+         * See how many L_{i} entries we need to process data at hand
+         * and pre-compute missing entries in the table [if any]...
+         */
+        while (top >>= 1)
+            max_idx++;
+        if (ocb_lookup_l(ctx, max_idx) == NULL)
+            return 0;
+
+        ctx->stream(in, out, num_blocks, ctx->keyenc,
+                    (size_t)ctx->blocks_processed + 1, ctx->offset.c,
+                    (const unsigned char (*)[16])ctx->l, ctx->checksum.c);
+    } else {
+        /* Loop through all full blocks to be encrypted */
+        for (i = ctx->blocks_processed + 1; i <= all_num_blocks; i++) {
+            OCB_BLOCK *lookup;
+            OCB_BLOCK *inblock;
+            OCB_BLOCK *outblock;
+
+            /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+            lookup = ocb_lookup_l(ctx, ocb_ntz(i));
+            if (lookup == NULL)
+                return 0;
+            ocb_block16_xor(&ctx->offset, lookup, &ctx->offset);
+
+            /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */
+            inblock =
+                (OCB_BLOCK *)(in + ((i - ctx->blocks_processed - 1) * 16));
+            ocb_block16_xor_misaligned(&ctx->offset, inblock, &tmp1);
+            /* Checksum_i = Checksum_{i-1} xor P_i */
+            ocb_block16_xor_misaligned(&ctx->checksum, inblock, &ctx->checksum);
+            ctx->encrypt(tmp1.c, tmp2.c, ctx->keyenc);
+            outblock =
+                (OCB_BLOCK *)(out + ((i - ctx->blocks_processed - 1) * 16));
+            ocb_block16_xor_misaligned(&ctx->offset, &tmp2, outblock);
+        }
+    }
+
+    /*
+     * Check if we have any partial blocks left over. This is only valid in the
+     * last call to this function
+     */
+    last_len = len % 16;
+
+    if (last_len > 0) {
+        /* Offset_* = Offset_m xor L_* */
+        ocb_block16_xor(&ctx->offset, &ctx->l_star, &ctx->offset);
+
+        /* Pad = ENCIPHER(K, Offset_*) */
+        ctx->encrypt(ctx->offset.c, pad.c, ctx->keyenc);
+
+        /* C_* = P_* xor Pad[1..bitlen(P_*)] */
+        ocb_block_xor(in + (len / 16) * 16, (unsigned char *)&pad, last_len,
+                      out + (num_blocks * 16));
+
+        /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
+        memset(&tmp1, 0, 16);
+        memcpy(&tmp1, in + (len / 16) * 16, last_len);
+        ((unsigned char *)(&tmp1))[last_len] = 0x80;
+        ocb_block16_xor(&ctx->checksum, &tmp1, &ctx->checksum);
+    }
+
+    ctx->blocks_processed = all_num_blocks;
+
+    return 1;
+}
+
+/*
+ * Provide any data to be decrypted. This can be called multiple times. Only
+ * the final time can have a partial block
+ */
+int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
+                          const unsigned char *in, unsigned char *out,
+                          size_t len)
+{
+    u64 i, all_num_blocks;
+    size_t num_blocks, last_len;
+    OCB_BLOCK tmp1;
+    OCB_BLOCK tmp2;
+    OCB_BLOCK pad;
+
+    /*
+     * Calculate the number of blocks of data to be decrypted provided now, and
+     * so far
+     */
+    num_blocks = len / 16;
+    all_num_blocks = num_blocks + ctx->blocks_processed;
+
+    if (num_blocks && all_num_blocks == (size_t)all_num_blocks
+        && ctx->stream != NULL) {
+        size_t max_idx = 0, top = (size_t)all_num_blocks;
+
+        /*
+         * See how many L_{i} entries we need to process data at hand
+         * and pre-compute missing entries in the table [if any]...
+         */
+        while (top >>= 1)
+            max_idx++;
+        if (ocb_lookup_l(ctx, max_idx) == NULL)
+            return 0;
+
+        ctx->stream(in, out, num_blocks, ctx->keydec,
+                    (size_t)ctx->blocks_processed + 1, ctx->offset.c,
+                    (const unsigned char (*)[16])ctx->l, ctx->checksum.c);
+    } else {
+        /* Loop through all full blocks to be decrypted */
+        for (i = ctx->blocks_processed + 1; i <= all_num_blocks; i++) {
+            OCB_BLOCK *inblock;
+            OCB_BLOCK *outblock;
+
+            /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+            OCB_BLOCK *lookup = ocb_lookup_l(ctx, ocb_ntz(i));
+            if (lookup == NULL)
+                return 0;
+            ocb_block16_xor(&ctx->offset, lookup, &ctx->offset);
+
+            /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) */
+            inblock =
+                (OCB_BLOCK *)(in + ((i - ctx->blocks_processed - 1) * 16));
+            ocb_block16_xor_misaligned(&ctx->offset, inblock, &tmp1);
+            ctx->decrypt(tmp1.c, tmp2.c, ctx->keydec);
+            outblock =
+                (OCB_BLOCK *)(out + ((i - ctx->blocks_processed - 1) * 16));
+            ocb_block16_xor_misaligned(&ctx->offset, &tmp2, outblock);
+
+            /* Checksum_i = Checksum_{i-1} xor P_i */
+            ocb_block16_xor_misaligned(&ctx->checksum, outblock, &ctx->checksum);
+        }
+    }
+
+    /*
+     * Check if we have any partial blocks left over. This is only valid in the
+     * last call to this function
+     */
+    last_len = len % 16;
+
+    if (last_len > 0) {
+        /* Offset_* = Offset_m xor L_* */
+        ocb_block16_xor(&ctx->offset, &ctx->l_star, &ctx->offset);
+
+        /* Pad = ENCIPHER(K, Offset_*) */
+        ctx->encrypt(ctx->offset.c, pad.c, ctx->keyenc);
+
+        /* P_* = C_* xor Pad[1..bitlen(C_*)] */
+        ocb_block_xor(in + (len / 16) * 16, (unsigned char *)&pad, last_len,
+                      out + (num_blocks * 16));
+
+        /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
+        memset(&tmp1, 0, 16);
+        memcpy(&tmp1, out + (len / 16) * 16, last_len);
+        ((unsigned char *)(&tmp1))[last_len] = 0x80;
+        ocb_block16_xor(&ctx->checksum, &tmp1, &ctx->checksum);
+    }
+
+    ctx->blocks_processed = all_num_blocks;
+
+    return 1;
+}
+
+/*
+ * Calculate the tag and verify it against the supplied tag
+ */
+int CRYPTO_ocb128_finish(OCB128_CONTEXT *ctx, const unsigned char *tag,
+                         size_t len)
+{
+    OCB_BLOCK tmp1, tmp2;
+
+    /*
+     * Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A)
+     */
+    ocb_block16_xor(&ctx->checksum, &ctx->offset, &tmp1);
+    ocb_block16_xor(&tmp1, &ctx->l_dollar, &tmp2);
+    ctx->encrypt(tmp2.c, tmp1.c, ctx->keyenc);
+    ocb_block16_xor(&tmp1, &ctx->sum, &ctx->tag);
+
+    if (len > 16 || len < 1) {
+        return -1;
+    }
+
+    /* Compare the tag if we've been given one */
+    if (tag)
+        return CRYPTO_memcmp(&ctx->tag, tag, len);
+    else
+        return -1;
+}
+
+/*
+ * Retrieve the calculated tag
+ */
+int CRYPTO_ocb128_tag(OCB128_CONTEXT *ctx, unsigned char *tag, size_t len)
+{
+    if (len > 16 || len < 1) {
+        return -1;
+    }
+
+    /* Calculate the tag */
+    CRYPTO_ocb128_finish(ctx, NULL, 0);
+
+    /* Copy the tag into the supplied buffer */
+    memcpy(tag, &ctx->tag, len);
+
+    return 1;
+}
+
+/*
+ * Release all resources
+ */
+void CRYPTO_ocb128_cleanup(OCB128_CONTEXT *ctx)
+{
+    if (ctx) {
+        OPENSSL_clear_free(ctx->l, ctx->max_l_index * 16);
+        OPENSSL_cleanse(ctx, sizeof(*ctx));
+    }
+}
+
+#endif                          /* OPENSSL_NO_OCB */

+ 73 - 0
components/SM/src/modes/ofb128.c

@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "modes_lcl.h"
+#include <string.h>
+
+/*
+ * The input and output encrypted as though 128bit ofb mode is being used.
+ * The extra state information to record how much of the 128bit block we have
+ * used is contained in *num;
+ */
+void CRYPTO_ofb128_encrypt(const unsigned char *in, unsigned char *out,
+                           size_t len, const void *key,
+                           unsigned char ivec[16], int *num, block128_f block)
+{
+    unsigned int n;
+    size_t l = 0;
+
+    n = *num;
+
+#if !defined(OPENSSL_SMALL_FOOTPRINT)
+    if (16 % sizeof(size_t) == 0) { /* always true actually */
+        do {
+            while (n && len) {
+                *(out++) = *(in++) ^ ivec[n];
+                --len;
+                n = (n + 1) % 16;
+            }
+# if defined(STRICT_ALIGNMENT)
+            if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) !=
+                0)
+                break;
+# endif
+            while (len >= 16) {
+                (*block) (ivec, ivec, key);
+                for (; n < 16; n += sizeof(size_t))
+                    *(size_t *)(out + n) =
+                        *(size_t *)(in + n) ^ *(size_t *)(ivec + n);
+                len -= 16;
+                out += 16;
+                in += 16;
+                n = 0;
+            }
+            if (len) {
+                (*block) (ivec, ivec, key);
+                while (len--) {
+                    out[n] = in[n] ^ ivec[n];
+                    ++n;
+                }
+            }
+            *num = n;
+            return;
+        } while (0);
+    }
+    /* the rest would be commonly eliminated by x86* compiler */
+#endif
+    while (l < len) {
+        if (n == 0) {
+            (*block) (ivec, ivec, key);
+        }
+        out[l] = in[l] ^ ivec[n];
+        ++l;
+        n = (n + 1) % 16;
+    }
+
+    *num = n;
+}

+ 330 - 0
components/SM/src/modes/wrap128.c

@@ -0,0 +1,330 @@
+/*
+ * Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/**  Beware!
+ *
+ *  Following wrapping modes were designed for AES but this implementation
+ *  allows you to use them for any 128 bit block cipher.
+ */
+
+// #include "internal/cryptlib.h"
+#include <internal/openssl_aid.h>
+#include <openssl/modes.h>
+
+/** RFC 3394 section 2.2.3.1 Default Initial Value */
+static const unsigned char default_iv[] = {
+    0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+};
+
+/** RFC 5649 section 3 Alternative Initial Value 32-bit constant */
+static const unsigned char default_aiv[] = {
+    0xA6, 0x59, 0x59, 0xA6
+};
+
+/** Input size limit: lower than maximum of standards but far larger than
+ *  anything that will be used in practice.
+ */
+#define CRYPTO128_WRAP_MAX (1UL << 31)
+
+/** Wrapping according to RFC 3394 section 2.2.1.
+ *
+ *  @param[in]  key    Key value.
+ *  @param[in]  iv     IV value. Length = 8 bytes. NULL = use default_iv.
+ *  @param[in]  in     Plaintext as n 64-bit blocks, n >= 2.
+ *  @param[in]  inlen  Length of in.
+ *  @param[out] out    Ciphertext. Minimal buffer length = (inlen + 8) bytes.
+ *                     Input and output buffers can overlap if block function
+ *                     supports that.
+ *  @param[in]  block  Block processing function.
+ *  @return            0 if inlen does not consist of n 64-bit blocks, n >= 2.
+ *                     or if inlen > CRYPTO128_WRAP_MAX.
+ *                     Output length if wrapping succeeded.
+ */
+size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
+                       unsigned char *out,
+                       const unsigned char *in, size_t inlen,
+                       block128_f block)
+{
+    unsigned char *A, B[16], *R;
+    size_t i, j, t;
+    if ((inlen & 0x7) || (inlen < 16) || (inlen > CRYPTO128_WRAP_MAX))
+        return 0;
+    A = B;
+    t = 1;
+    memmove(out + 8, in, inlen);
+    if (!iv)
+        iv = default_iv;
+
+    memcpy(A, iv, 8);
+
+    for (j = 0; j < 6; j++) {
+        R = out + 8;
+        for (i = 0; i < inlen; i += 8, t++, R += 8) {
+            memcpy(B + 8, R, 8);
+            block(B, B, key);
+            A[7] ^= (unsigned char)(t & 0xff);
+            if (t > 0xff) {
+                A[6] ^= (unsigned char)((t >> 8) & 0xff);
+                A[5] ^= (unsigned char)((t >> 16) & 0xff);
+                A[4] ^= (unsigned char)((t >> 24) & 0xff);
+            }
+            memcpy(R, B + 8, 8);
+        }
+    }
+    memcpy(out, A, 8);
+    return inlen + 8;
+}
+
+/** Unwrapping according to RFC 3394 section 2.2.2 steps 1-2.
+ *  The IV check (step 3) is responsibility of the caller.
+ *
+ *  @param[in]  key    Key value.
+ *  @param[out] iv     Unchecked IV value. Minimal buffer length = 8 bytes.
+ *  @param[out] out    Plaintext without IV.
+ *                     Minimal buffer length = (inlen - 8) bytes.
+ *                     Input and output buffers can overlap if block function
+ *                     supports that.
+ *  @param[in]  in     Ciphertext as n 64-bit blocks.
+ *  @param[in]  inlen  Length of in.
+ *  @param[in]  block  Block processing function.
+ *  @return            0 if inlen is out of range [24, CRYPTO128_WRAP_MAX]
+ *                     or if inlen is not a multiple of 8.
+ *                     Output length otherwise.
+ */
+static size_t crypto_128_unwrap_raw(void *key, unsigned char *iv,
+                                    unsigned char *out,
+                                    const unsigned char *in, size_t inlen,
+                                    block128_f block)
+{
+    unsigned char *A, B[16], *R;
+    size_t i, j, t;
+    inlen -= 8;
+    if ((inlen & 0x7) || (inlen < 16) || (inlen > CRYPTO128_WRAP_MAX))
+        return 0;
+    A = B;
+    t = 6 * (inlen >> 3);
+    memcpy(A, in, 8);
+    memmove(out, in + 8, inlen);
+    for (j = 0; j < 6; j++) {
+        R = out + inlen - 8;
+        for (i = 0; i < inlen; i += 8, t--, R -= 8) {
+            A[7] ^= (unsigned char)(t & 0xff);
+            if (t > 0xff) {
+                A[6] ^= (unsigned char)((t >> 8) & 0xff);
+                A[5] ^= (unsigned char)((t >> 16) & 0xff);
+                A[4] ^= (unsigned char)((t >> 24) & 0xff);
+            }
+            memcpy(B + 8, R, 8);
+            block(B, B, key);
+            memcpy(R, B + 8, 8);
+        }
+    }
+    memcpy(iv, A, 8);
+    return inlen;
+}
+
+/** Unwrapping according to RFC 3394 section 2.2.2, including the IV check.
+ *  The first block of plaintext has to match the supplied IV, otherwise an
+ *  error is returned.
+ *
+ *  @param[in]  key    Key value.
+ *  @param[out] iv     IV value to match against. Length = 8 bytes.
+ *                     NULL = use default_iv.
+ *  @param[out] out    Plaintext without IV.
+ *                     Minimal buffer length = (inlen - 8) bytes.
+ *                     Input and output buffers can overlap if block function
+ *                     supports that.
+ *  @param[in]  in     Ciphertext as n 64-bit blocks.
+ *  @param[in]  inlen  Length of in.
+ *  @param[in]  block  Block processing function.
+ *  @return            0 if inlen is out of range [24, CRYPTO128_WRAP_MAX]
+ *                     or if inlen is not a multiple of 8
+ *                     or if IV doesn't match expected value.
+ *                     Output length otherwise.
+ */
+size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
+                         unsigned char *out, const unsigned char *in,
+                         size_t inlen, block128_f block)
+{
+    size_t ret;
+    unsigned char got_iv[8];
+
+    ret = crypto_128_unwrap_raw(key, got_iv, out, in, inlen, block);
+    if (ret == 0)
+        return 0;
+
+    if (!iv)
+        iv = default_iv;
+    if (CRYPTO_memcmp(got_iv, iv, 8)) {
+        OPENSSL_cleanse(out, ret);
+        return 0;
+    }
+    return ret;
+}
+
+/** Wrapping according to RFC 5649 section 4.1.
+ *
+ *  @param[in]  key    Key value.
+ *  @param[in]  icv    (Non-standard) IV, 4 bytes. NULL = use default_aiv.
+ *  @param[out] out    Ciphertext. Minimal buffer length = (inlen + 15) bytes.
+ *                     Input and output buffers can overlap if block function
+ *                     supports that.
+ *  @param[in]  in     Plaintext as n 64-bit blocks, n >= 2.
+ *  @param[in]  inlen  Length of in.
+ *  @param[in]  block  Block processing function.
+ *  @return            0 if inlen is out of range [1, CRYPTO128_WRAP_MAX].
+ *                     Output length if wrapping succeeded.
+ */
+size_t CRYPTO_128_wrap_pad(void *key, const unsigned char *icv,
+                           unsigned char *out,
+                           const unsigned char *in, size_t inlen,
+                           block128_f block)
+{
+    /* n: number of 64-bit blocks in the padded key data
+     *
+     * If length of plain text is not a multiple of 8, pad the plain text octet
+     * string on the right with octets of zeros, where final length is the
+     * smallest multiple of 8 that is greater than length of plain text.
+     * If length of plain text is a multiple of 8, then there is no padding. */
+    const size_t blocks_padded = (inlen + 7) / 8; /* CEILING(m/8) */
+    const size_t padded_len = blocks_padded * 8;
+    const size_t padding_len = padded_len - inlen;
+    /* RFC 5649 section 3: Alternative Initial Value */
+    unsigned char aiv[8];
+    int ret;
+
+    /* Section 1: use 32-bit fixed field for plaintext octet length */
+    if (inlen == 0 || inlen >= CRYPTO128_WRAP_MAX)
+        return 0;
+
+    /* Section 3: Alternative Initial Value */
+    if (!icv)
+        memcpy(aiv, default_aiv, 4);
+    else
+        memcpy(aiv, icv, 4);    /* Standard doesn't mention this. */
+
+    aiv[4] = (inlen >> 24) & 0xFF;
+    aiv[5] = (inlen >> 16) & 0xFF;
+    aiv[6] = (inlen >> 8) & 0xFF;
+    aiv[7] = inlen & 0xFF;
+
+    if (padded_len == 8) {
+        /*
+         * Section 4.1 - special case in step 2: If the padded plaintext
+         * contains exactly eight octets, then prepend the AIV and encrypt
+         * the resulting 128-bit block using AES in ECB mode.
+         */
+        memmove(out + 8, in, inlen);
+        memcpy(out, aiv, 8);
+        memset(out + 8 + inlen, 0, padding_len);
+        block(out, out, key);
+        ret = 16;               /* AIV + padded input */
+    } else {
+        memmove(out, in, inlen);
+        memset(out + inlen, 0, padding_len); /* Section 4.1 step 1 */
+        ret = CRYPTO_128_wrap(key, aiv, out, out, padded_len, block);
+    }
+
+    return ret;
+}
+
+/** Unwrapping according to RFC 5649 section 4.2.
+ *
+ *  @param[in]  key    Key value.
+ *  @param[in]  icv    (Non-standard) IV, 4 bytes. NULL = use default_aiv.
+ *  @param[out] out    Plaintext. Minimal buffer length = inlen bytes.
+ *                     Input and output buffers can overlap if block function
+ *                     supports that.
+ *  @param[in]  in     Ciphertext as n 64-bit blocks.
+ *  @param[in]  inlen  Length of in.
+ *  @param[in]  block  Block processing function.
+ *  @return            0 if inlen is out of range [16, CRYPTO128_WRAP_MAX],
+ *                     or if inlen is not a multiple of 8
+ *                     or if IV and message length indicator doesn't match.
+ *                     Output length if unwrapping succeeded and IV matches.
+ */
+size_t CRYPTO_128_unwrap_pad(void *key, const unsigned char *icv,
+                             unsigned char *out,
+                             const unsigned char *in, size_t inlen,
+                             block128_f block)
+{
+    /* n: number of 64-bit blocks in the padded key data */
+    size_t n = inlen / 8 - 1;
+    size_t padded_len;
+    size_t padding_len;
+    size_t ptext_len;
+    /* RFC 5649 section 3: Alternative Initial Value */
+    unsigned char aiv[8];
+    static unsigned char zeros[8] = { 0x0 };
+    size_t ret;
+
+    /* Section 4.2: Ciphertext length has to be (n+1) 64-bit blocks. */
+    if ((inlen & 0x7) != 0 || inlen < 16 || inlen >= CRYPTO128_WRAP_MAX)
+        return 0;
+
+    memmove(out, in, inlen);
+    if (inlen == 16) {
+        /*
+         * Section 4.2 - special case in step 1: When n=1, the ciphertext
+         * contains exactly two 64-bit blocks and they are decrypted as a
+         * single AES block using AES in ECB mode: AIV | P[1] = DEC(K, C[0] |
+         * C[1])
+         */
+        block(out, out, key);
+        memcpy(aiv, out, 8);
+        /* Remove AIV */
+        memmove(out, out + 8, 8);
+        padded_len = 8;
+    } else {
+        padded_len = inlen - 8;
+        ret = crypto_128_unwrap_raw(key, aiv, out, out, inlen, block);
+        if (padded_len != ret) {
+            OPENSSL_cleanse(out, inlen);
+            return 0;
+        }
+    }
+
+    /*
+     * Section 3: AIV checks: Check that MSB(32,A) = A65959A6. Optionally a
+     * user-supplied value can be used (even if standard doesn't mention
+     * this).
+     */
+    if ((!icv && CRYPTO_memcmp(aiv, default_aiv, 4))
+        || (icv && CRYPTO_memcmp(aiv, icv, 4))) {
+        OPENSSL_cleanse(out, inlen);
+        return 0;
+    }
+
+    /*
+     * Check that 8*(n-1) < LSB(32,AIV) <= 8*n. If so, let ptext_len =
+     * LSB(32,AIV).
+     */
+
+    ptext_len =   ((unsigned int)aiv[4] << 24)
+                | ((unsigned int)aiv[5] << 16)
+                | ((unsigned int)aiv[6] <<  8)
+                |  (unsigned int)aiv[7];
+    if (8 * (n - 1) >= ptext_len || ptext_len > 8 * n) {
+        OPENSSL_cleanse(out, inlen);
+        return 0;
+    }
+
+    /*
+     * Check that the rightmost padding_len octets of the output data are
+     * zero.
+     */
+    padding_len = padded_len - ptext_len;
+    if (CRYPTO_memcmp(out + ptext_len, zeros, padding_len) != 0) {
+        OPENSSL_cleanse(out, inlen);
+        return 0;
+    }
+
+    /* Section 4.2 step 3: Remove padding */
+    return ptext_len;
+}

+ 156 - 0
components/SM/src/modes/xts128.c

@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "modes_lcl.h"
+#include <string.h>
+
+int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx,
+                          const unsigned char iv[16],
+                          const unsigned char *inp, unsigned char *out,
+                          size_t len, int enc)
+{
+    const union {
+        long one;
+        char little;
+    } is_endian = {
+        1
+    };
+    union {
+        u64 u[2];
+        u32 d[4];
+        u8 c[16];
+    } tweak, scratch;
+    unsigned int i;
+
+    if (len < 16)
+        return -1;
+
+    memcpy(tweak.c, iv, 16);
+
+    (*ctx->block2) (tweak.c, tweak.c, ctx->key2);
+
+    if (!enc && (len % 16))
+        len -= 16;
+
+    while (len >= 16) {
+#if defined(STRICT_ALIGNMENT)
+        memcpy(scratch.c, inp, 16);
+        scratch.u[0] ^= tweak.u[0];
+        scratch.u[1] ^= tweak.u[1];
+#else
+        scratch.u[0] = ((u64 *)inp)[0] ^ tweak.u[0];
+        scratch.u[1] = ((u64 *)inp)[1] ^ tweak.u[1];
+#endif
+        (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
+#if defined(STRICT_ALIGNMENT)
+        scratch.u[0] ^= tweak.u[0];
+        scratch.u[1] ^= tweak.u[1];
+        memcpy(out, scratch.c, 16);
+#else
+        ((u64 *)out)[0] = scratch.u[0] ^= tweak.u[0];
+        ((u64 *)out)[1] = scratch.u[1] ^= tweak.u[1];
+#endif
+        inp += 16;
+        out += 16;
+        len -= 16;
+
+        if (len == 0)
+            return 0;
+
+        if (is_endian.little) {
+            unsigned int carry, res;
+
+            res = 0x87 & (((int)tweak.d[3]) >> 31);
+            carry = (unsigned int)(tweak.u[0] >> 63);
+            tweak.u[0] = (tweak.u[0] << 1) ^ res;
+            tweak.u[1] = (tweak.u[1] << 1) | carry;
+        } else {
+            size_t c;
+
+            for (c = 0, i = 0; i < 16; ++i) {
+                /*
+                 * + substitutes for |, because c is 1 bit
+                 */
+                c += ((size_t)tweak.c[i]) << 1;
+                tweak.c[i] = (u8)c;
+                c = c >> 8;
+            }
+            tweak.c[0] ^= (u8)(0x87 & (0 - c));
+        }
+    }
+    if (enc) {
+        for (i = 0; i < len; ++i) {
+            u8 c = inp[i];
+            out[i] = scratch.c[i];
+            scratch.c[i] = c;
+        }
+        scratch.u[0] ^= tweak.u[0];
+        scratch.u[1] ^= tweak.u[1];
+        (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
+        scratch.u[0] ^= tweak.u[0];
+        scratch.u[1] ^= tweak.u[1];
+        memcpy(out - 16, scratch.c, 16);
+    } else {
+        union {
+            u64 u[2];
+            u8 c[16];
+        } tweak1;
+
+        if (is_endian.little) {
+            unsigned int carry, res;
+
+            res = 0x87 & (((int)tweak.d[3]) >> 31);
+            carry = (unsigned int)(tweak.u[0] >> 63);
+            tweak1.u[0] = (tweak.u[0] << 1) ^ res;
+            tweak1.u[1] = (tweak.u[1] << 1) | carry;
+        } else {
+            size_t c;
+
+            for (c = 0, i = 0; i < 16; ++i) {
+                /*
+                 * + substitutes for |, because c is 1 bit
+                 */
+                c += ((size_t)tweak.c[i]) << 1;
+                tweak1.c[i] = (u8)c;
+                c = c >> 8;
+            }
+            tweak1.c[0] ^= (u8)(0x87 & (0 - c));
+        }
+#if defined(STRICT_ALIGNMENT)
+        memcpy(scratch.c, inp, 16);
+        scratch.u[0] ^= tweak1.u[0];
+        scratch.u[1] ^= tweak1.u[1];
+#else
+        scratch.u[0] = ((u64 *)inp)[0] ^ tweak1.u[0];
+        scratch.u[1] = ((u64 *)inp)[1] ^ tweak1.u[1];
+#endif
+        (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
+        scratch.u[0] ^= tweak1.u[0];
+        scratch.u[1] ^= tweak1.u[1];
+
+        for (i = 0; i < len; ++i) {
+            u8 c = inp[16 + i];
+            out[16 + i] = scratch.c[i];
+            scratch.c[i] = c;
+        }
+        scratch.u[0] ^= tweak.u[0];
+        scratch.u[1] ^= tweak.u[1];
+        (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
+#if defined(STRICT_ALIGNMENT)
+        scratch.u[0] ^= tweak.u[0];
+        scratch.u[1] ^= tweak.u[1];
+        memcpy(out, scratch.c, 16);
+#else
+        ((u64 *)out)[0] = scratch.u[0] ^ tweak.u[0];
+        ((u64 *)out)[1] = scratch.u[1] ^ tweak.u[1];
+#endif
+    }
+
+    return 0;
+}

+ 489 - 0
components/SM/src/rsa/rsa_cloud.c

@@ -0,0 +1,489 @@
+//
+// Created by lzj on 2017/9/11.
+//
+
+#include <rsa/rsa_cloud.h>
+#include <mbedtls/hmac_drbg.h>
+#include <mbedtls/sha256.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <internal/ssl_random.h>
+
+void rsa_cloud_init(rsa_cloud_context *ctx)
+{
+	memset(ctx, 0, sizeof(rsa_cloud_context));
+}
+
+void rsa_cloud_free(rsa_cloud_context *ctx)
+{
+	mbedtls_mpi_free(&ctx->Q);
+	mbedtls_mpi_free(&ctx->P);
+	mbedtls_mpi_free(&ctx->PK.E);
+	mbedtls_mpi_free(&ctx->SK.D);
+	mbedtls_mpi_free(&ctx->PK.N);
+	mbedtls_mpi_free(&ctx->SK.N);
+}
+
+void rsa_cloud_hsk_init(rsa_cloud_hsk_context *ctx)
+{
+	memset(ctx, 0, sizeof(rsa_cloud_hsk_context));
+}
+
+void rsa_cloud_hsk_free(rsa_cloud_hsk_context *ctx)
+{
+	mbedtls_mpi_free(&ctx->hd_A);
+	mbedtls_mpi_free(&ctx->hd_SA);
+	mbedtls_mpi_free(&ctx->n_A);
+}
+
+void rsa_cloud_mds_init(rsa_cloud_mds_context *ctx)
+{
+	memset(ctx, 0, sizeof(rsa_cloud_hsk_context));
+}
+
+void rsa_cloud_mds_free(rsa_cloud_mds_context *ctx)
+{
+	mbedtls_mpi_free(&ctx->hd_SA);
+	mbedtls_mpi_free(&ctx->q_);
+}
+
+static int rsa_cloud_gen_keypair(rsa_cloud_context *ctx,
+								 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+								 unsigned int nbits, int exponent, const mbedtls_mpi *judge)
+{
+	int ret;
+	mbedtls_mpi P1, Q1, H, G;
+
+	if (f_rng == NULL || nbits < 128 || exponent < 3)
+		return (MBEDTLS_ERR_RSA_CLOUD_BAD_INPUT_DATA);
+
+	if (nbits % 2)
+		return (MBEDTLS_ERR_RSA_CLOUD_BAD_INPUT_DATA);
+
+	mbedtls_mpi_init(&P1);
+	mbedtls_mpi_init(&Q1);
+	mbedtls_mpi_init(&H);
+	mbedtls_mpi_init(&G);
+
+	/*
+	 * find primes P and Q with Q < P so that:
+	 * GCD( E, (P-1)*(Q-1) ) == 1
+	 */
+	MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->PK.E, exponent));
+
+	do
+	{
+		MBEDTLS_MPI_CHK(
+			mbedtls_mpi_gen_prime(&ctx->P, nbits >> 1, 0, f_rng, p_rng));
+
+		MBEDTLS_MPI_CHK(
+			mbedtls_mpi_gen_prime(&ctx->Q, nbits >> 1, 0, f_rng, p_rng));
+
+		if (mbedtls_mpi_cmp_mpi(&ctx->P, &ctx->Q) == 0)
+			continue;
+
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->PK.N, &ctx->P, &ctx->Q));
+
+		if (judge != NULL && mbedtls_mpi_cmp_mpi(&ctx->PK.N, judge) >= 0)
+		{
+			continue;
+		}
+
+		if (mbedtls_mpi_bitlen(&ctx->PK.N) != nbits)
+			continue;
+
+		if (mbedtls_mpi_cmp_mpi(&ctx->P, &ctx->Q) < 0)
+			mbedtls_mpi_swap(&ctx->P, &ctx->Q);
+
+		MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&P1, &ctx->P, 1));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&Q1, &ctx->Q, 1));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&H, &P1, &Q1));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, &ctx->PK.E, &H));
+	} while (mbedtls_mpi_cmp_int(&G, 1) != 0);
+
+	/*
+	 * D  = E^-1 mod ((P-1)*(Q-1))
+	 */
+	MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&ctx->SK.D, &ctx->PK.E, &H));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&ctx->SK.N, &ctx->PK.N));
+
+	ctx->len = (mbedtls_mpi_bitlen(&ctx->PK.N) + 7) >> 3;
+
+cleanup:
+
+	mbedtls_mpi_free(&P1);
+	mbedtls_mpi_free(&Q1);
+	mbedtls_mpi_free(&H);
+	mbedtls_mpi_free(&G);
+
+	if (ret != 0)
+	{
+		rsa_cloud_free(ctx);
+		return (MBEDTLS_ERR_CLOUD_RSA_KEY_GEN_FAILED + ret);
+	}
+
+	return (0);
+}
+
+int rsa_cloud_gen_server_keypair(rsa_cloud_context *ctx, f_rand f_rng,
+								 void *p_rng, unsigned int nbits, int exponent)
+{
+	return rsa_cloud_gen_keypair(ctx, f_rng, p_rng, nbits, exponent, NULL);
+}
+
+int rsa_cloud_gen_client_keypair(rsa_cloud_context *ctx,
+								 const rsa_cloud_pk *pk_server, f_rand f_rng, void *p_rng,
+								 unsigned int nbits, int exponent)
+{
+	if (pk_server == NULL)
+	{
+		return MBEDTLS_ERR_RSA_CLOUD_SERVER_N_S_NULL;
+	}
+
+	return rsa_cloud_gen_keypair(ctx, f_rng, p_rng, nbits, exponent,
+								 &pk_server->N);
+}
+
+/**
+ *  generate big number k from 1 to range-1
+ */
+
+int rsa_cloud_rand(mbedtls_mpi *k, const mbedtls_mpi *range)
+{
+	int ret;
+	size_t size;
+	ssl_random_context ctx;
+	mbedtls_mpi tmp;
+	unsigned char *out;
+	mbedtls_mpi_init(&tmp);
+
+	ssl_random_init(&ctx);
+	ssl_random_seed(&ctx, NULL, 0);
+
+	size = mbedtls_mpi_size(range);
+	MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&tmp, range, 1));
+
+	out = calloc(size, sizeof(unsigned char));
+	do
+	{
+		ssl_random_rand(&ctx, out, size);
+		MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(k, out, size));
+
+	} while (mbedtls_mpi_cmp_mpi(k, &tmp) > -1 || mbedtls_mpi_cmp_int(k, 1) < 1);
+
+cleanup:
+	ssl_random_free(&ctx);
+	mbedtls_mpi_free(&tmp);
+	free(out);
+	return (ret);
+}
+
+int rsa_cloud_key_hide(const rsa_cloud_sk *client,
+					   const rsa_cloud_pk *pk_server, rsa_cloud_hsk_context *hsk)
+{
+
+	int ret;
+	mbedtls_mpi d_SA;
+
+	mbedtls_mpi_init(&d_SA);
+
+	// hda = da - dsa
+	do
+	{
+		MBEDTLS_MPI_CHK(rsa_cloud_rand(&d_SA, &client->N));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&hsk->hd_A, &client->D, &d_SA));
+
+	} while (mbedtls_mpi_cmp_int(&hsk->hd_A, 0) < 1);
+
+	// encrypt hda
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_exp_mod(&hsk->hd_SA, &d_SA, &pk_server->E, &pk_server->N, NULL));
+
+	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&hsk->n_A, &client->N));
+
+cleanup:
+	mbedtls_mpi_free(&d_SA);
+	return ret;
+}
+
+int rsa_cloud_md_sign(const rsa_cloud_hsk_context *hsk, const char *message,
+					  size_t msglen, rsa_cloud_mds_context *mds)
+{
+	int ret;
+
+	unsigned char h[32];
+	mbedtls_mpi t;
+
+	memset(h, 0, sizeof(h));
+	mbedtls_mpi_init(&t);
+
+	//h = H(m)
+	mbedtls_sha256((unsigned char *)message, msglen, h, 1);
+
+	mbedtls_mpi_read_binary(&t, h, sizeof(h));
+
+	if (mbedtls_mpi_cmp_mpi(&t, &hsk->n_A) >= 0)
+	{
+		ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+		goto cleanup;
+	}
+
+	// encrypt hda
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_exp_mod(&mds->q_, &t, &hsk->hd_A, &hsk->n_A, NULL));
+
+	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&mds->hd_SA, &hsk->hd_SA));
+
+cleanup:
+	mbedtls_mpi_free(&t);
+	return ret;
+}
+
+int rsa_cloud_transformation(const rsa_cloud_pk *client,
+							 const rsa_cloud_sk *server, const rsa_cloud_mds_context *mds,
+							 const char *message, size_t msglen, unsigned char *out, size_t outlen,
+							 size_t *olen)
+{
+	int ret;
+	unsigned char hash[32];
+	mbedtls_mpi d_SA, q, h, tmp;
+
+	memset(hash, 0, sizeof(hash));
+	mbedtls_mpi_init(&d_SA);
+	mbedtls_mpi_init(&q);
+	mbedtls_mpi_init(&h);
+	mbedtls_mpi_init(&tmp);
+
+	//h = H(m)
+	mbedtls_sha256((unsigned char *)message, msglen, hash, 1);
+	mbedtls_mpi_read_binary(&h, hash, sizeof(hash));
+
+	if (mbedtls_mpi_cmp_mpi(&h, &client->N) >= 0)
+	{
+		ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+		goto cleanup;
+	}
+
+	if (mbedtls_mpi_cmp_mpi(&mds->hd_SA, &server->N) >= 0)
+	{
+		ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+		goto cleanup;
+	}
+
+	// decrypt hda
+	// d_sa = (hd_sa)^d_s mod n_s
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_exp_mod(&d_SA, &mds->hd_SA, &server->D, &server->N, NULL));
+
+	//q = q_ * h^d_sa mod n_a
+	// q = (q_ mod n_a ) * (h^d_sa mod n_a) mod n_a
+	//q = (q_ mod n_a )
+	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&q, &mds->q_, &client->N));
+	//tmp = (h^d_sa mod n_a)
+	MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&tmp, &h, &d_SA, &client->N, NULL));
+	//q = q* tmp
+	MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&q, &q, &tmp));
+	//q =q mod n_a
+	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&q, &q, &client->N));
+
+	//tmp = q ^e_A mod n_a
+	mbedtls_mpi_free(&tmp);
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_exp_mod(&tmp, &q, &client->E, &client->N, NULL));
+
+	if (mbedtls_mpi_cmp_mpi(&h, &tmp) != 0)
+	{
+		ret = MBEDTLS_ERR_CLOUD_RSA_KEY_SERVER_TRANSFORMATION_FAILED;
+	}
+
+	*olen = mbedtls_mpi_size(&q);
+	if (outlen < *olen)
+	{
+		ret = MBEDTLS_ERR_CLOUD_RSA_KEY_SERVER_TRANSFORMATION_BAD_OUT;
+	}
+	else
+	{
+		mbedtls_mpi_write_binary(&q, out, *olen);
+	}
+
+cleanup:
+	mbedtls_mpi_free(&d_SA);
+	mbedtls_mpi_free(&q);
+	mbedtls_mpi_free(&h);
+	mbedtls_mpi_free(&tmp);
+	return ret;
+}
+
+#ifdef RSA_CLOUD_TEST
+int rsa_cloud_sefl_test_all()
+{
+	int ret;
+	size_t olen;
+	int i;
+	unsigned char out[64];
+	const char *str = "hello world";
+	rsa_cloud_context server, client;
+	rsa_cloud_hsk_context hsk;
+	rsa_cloud_mds_context mds;
+	mbedtls_hmac_drbg_context drbg;
+
+	mbedtls_hmac_drbg_init(&drbg);
+	rsa_cloud_init(&server);
+	rsa_cloud_init(&client);
+	rsa_cloud_hsk_init(&hsk);
+	rsa_cloud_mds_init(&mds);
+
+	ret = rsa_cloud_gen_server_keypair(&server, mbedtls_hmac_drbg_random, &drbg,
+									   256, 3);
+
+	printf("server pk e: ");
+	mbedtls_mpi_write_binary(&server.PK.E, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("server pk n: ");
+	mbedtls_mpi_write_binary(&server.PK.N, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("server sk d: ");
+	mbedtls_mpi_write_binary(&server.SK.D, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("server sk n: ");
+	mbedtls_mpi_write_binary(&server.SK.N, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("server p: ");
+	mbedtls_mpi_write_binary(&server.P, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("server q: ");
+	mbedtls_mpi_write_binary(&server.Q, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+
+	ret = rsa_cloud_gen_client_keypair(&client, &server.PK,
+									   mbedtls_hmac_drbg_random, &drbg, 256, 3);
+
+	printf("client pk e: ");
+	mbedtls_mpi_write_binary(&client.PK.E, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("client pk n: ");
+	mbedtls_mpi_write_binary(&client.PK.N, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("client sk d: ");
+	mbedtls_mpi_write_binary(&client.SK.D, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("client sk n: ");
+	mbedtls_mpi_write_binary(&client.SK.N, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("client p: ");
+	mbedtls_mpi_write_binary(&client.P, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("client q: ");
+	mbedtls_mpi_write_binary(&client.Q, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+
+	ret = rsa_cloud_key_hide(&client.SK, &server.PK, &hsk);
+
+	printf("hsk hd_a: ");
+	mbedtls_mpi_write_binary(&hsk.hd_A, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("hsk hd_sa: ");
+	mbedtls_mpi_write_binary(&hsk.hd_SA, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("hsk n_a: ");
+	mbedtls_mpi_write_binary(&hsk.n_A, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+
+	ret = rsa_cloud_md_sign(&hsk, str, strlen(str), &mds);
+
+	printf("mds q_: ");
+	mbedtls_mpi_write_binary(&mds.q_, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+	printf("mds hd_sa: ");
+	mbedtls_mpi_write_binary(&mds.hd_SA, out, 32);
+	for (i = 0; i < 32; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+
+	ret = rsa_cloud_transformation(&client.PK, &server.SK, &mds, str,
+								   strlen(str), out, 64, &olen);
+
+	printf("signature : \n");
+
+	for (i = 0; i < (int)olen; ++i)
+	{
+		printf("%02x", out[i]);
+	}
+	printf("\n");
+
+	rsa_cloud_free(&server);
+	rsa_cloud_free(&client);
+	rsa_cloud_hsk_free(&hsk);
+	rsa_cloud_mds_free(&mds);
+	mbedtls_hmac_drbg_free(&drbg);
+	return ret;
+}
+#endif

+ 1051 - 0
components/SM/src/sm2/sm2.c

@@ -0,0 +1,1051 @@
+//
+// Created by  lzj on 2017/8/15.
+//
+
+#include <sm2/sm2.h>
+#include <mbedtls/hmac_drbg.h>
+#include <mbedtls/ecp.h>
+#include <sm3/sm3.h>
+#include <mbedtls/bignum.h>
+
+#include <string.h>
+#include <time.h>
+#include <stdint.h>
+
+#define HEX_CODE 16
+#define SM3_LEN 32
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include <mbedtls/platform.h>
+#else
+#include <stdlib.h>
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+#if defined(MBEDTLS_SELF_TEST)
+
+#ifdef ANDROID_LOG
+
+#include <android/log.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define mbedtls_printf(...) __android_log_print(ANDROID_LOG_DEBUG, "SECURITY_LIBRARY", __VA_ARGS__)
+
+#else
+#define mbedtls_printf printf
+#endif // android log
+
+#endif // test end
+
+/**
+ * init context and
+ * set default group
+ * @param ctx
+ */
+int sm2_init(sm2_context *ctx)
+{
+	memset(ctx, 0, sizeof(sm2_context));
+	mbedtls_ecp_point_init(&ctx->Pb);
+	mbedtls_mpi_init(&ctx->d);
+	return mbedtls_ecp_group_load(&(ctx->grp), ECP_DP_SM2_256V1);
+}
+
+/**
+ *  free  context
+ * @param ctx
+ */
+void sm2_free(sm2_context *ctx)
+{
+	if (ctx == NULL)
+	{
+		return;
+	}
+
+	mbedtls_ecp_group_free(&ctx->grp);
+	mbedtls_ecp_point_free(&ctx->Pb);
+	mbedtls_mpi_free(&ctx->d);
+}
+
+/**
+ * set private key by hex buf
+ * @param ctx
+ * @param buf
+ * @return
+ */
+int sm2_read_string_private(sm2_context *ctx, const char *buf)
+{
+	return mbedtls_mpi_read_string(&(ctx->d), HEX_CODE, buf);
+}
+
+/**
+ *   set public key
+ * @param ctx
+ * @param x
+ * @param y
+ * @return
+ */
+int sm2_read_string_public(sm2_context *ctx, const char *x, const char *y)
+{
+	return mbedtls_ecp_point_read_string(&(ctx->Pb), HEX_CODE, x, y);
+}
+
+/**
+ *   generate key
+ * @param ctx
+ * @param f_rng
+ * @param p_rng
+ * @return
+ */
+int sm2_gen_keypair(sm2_context *ctx,
+					int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+{
+	return mbedtls_ecp_gen_keypair(&(ctx->grp), &(ctx->d), &(ctx->Pb), f_rng,
+								   p_rng);
+}
+
+/**
+ *  check private key int the group
+ * @param ctx
+ * @return
+ */
+int sm2_check_private(sm2_context *ctx)
+{
+	return mbedtls_ecp_check_privkey(&(ctx->grp), &(ctx->d));
+}
+
+/**
+ * check public key int group
+ * @param ctx
+ * @return
+ */
+int sm2_check_public(sm2_context *ctx)
+{
+	return mbedtls_ecp_check_pubkey(&(ctx->grp), &(ctx->Pb));
+}
+
+/**
+ *set sm2 group by hex string param
+ */
+int sm2_read_group_string(sm2_context *ctx, const char *p, const char *a,
+						  const char *b, const char *gx, const char *gy, const char *n)
+{
+	int ret;
+	static mbedtls_mpi_uint one[] = {1};
+	mbedtls_ecp_group_free(&ctx->grp);
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.P), HEX_CODE, p));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.A), HEX_CODE, a));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.B), HEX_CODE, b));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.G.X), HEX_CODE, gx));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.G.Y), HEX_CODE, gy));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.N), HEX_CODE, n));
+
+	ctx->grp.G.Z.s = 1;
+	ctx->grp.G.Z.n = 1;
+	ctx->grp.G.Z.p = one;
+	ctx->grp.pbits = mbedtls_mpi_bitlen(&(ctx->grp.P));
+	ctx->grp.nbits = mbedtls_mpi_bitlen(&(ctx->grp.N));
+	ctx->grp.h = 1;
+cleanup:
+	return ret;
+}
+
+/**
+ *  sm2 contest copy
+ */
+int sm2_copy(sm2_context *dst, const sm2_context *src)
+{
+
+	int ret;
+	MBEDTLS_MPI_CHK(mbedtls_ecp_group_copy(&dst->grp, &src->grp));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->d, &src->d));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Pb.X, &src->Pb.X));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Pb.Y, &src->Pb.Y));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Pb.Z, &src->Pb.Z));
+cleanup:
+
+	return (ret);
+}
+
+#define int_to_byte_4(b, i, u)      \
+	b[i] = (unsigned char)(u >> 8); \
+	b[i + 1] = (unsigned char)(u)
+
+#define int_to_byte_8(b, i, u)           \
+	b[i] = (unsigned char)(u >> 24);     \
+	b[i + 1] = (unsigned char)(u >> 16); \
+	b[i + 2] = (unsigned char)(u >> 8);  \
+	b[i + 3] = (unsigned char)(u)
+
+static int kdf(unsigned char *out, const unsigned char *buf, size_t buf_len,
+			   size_t klen)
+{
+	const int CT_LEN = sizeof(size_t);
+	const size_t counts = klen / SM3_LEN;
+	const size_t mod = klen % SM3_LEN;
+
+	size_t tmp_len = buf_len + CT_LEN;
+	size_t ct;
+	//buf len  + ct len ()
+	unsigned char *buf_z_ct = mbedtls_calloc(tmp_len, sizeof(unsigned char));
+	unsigned char *temp_out = mbedtls_calloc(SM3_LEN, sizeof(unsigned char));
+
+	if (buf_z_ct == NULL || temp_out == NULL)
+	{
+		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
+	}
+	for (ct = 1; ct <= counts + 1; ct++)
+	{
+		memset(buf_z_ct, 0, tmp_len);
+		memcpy(buf_z_ct, buf, buf_len);
+		int_to_byte_8(buf_z_ct, buf_len, ct);
+		if (ct <= counts)
+		{
+			sm3(buf_z_ct, tmp_len, out + (ct - 1) * SM3_LEN);
+		}
+		else
+		{
+			memset(temp_out, 0, SM3_LEN);
+			sm3(buf_z_ct, tmp_len, temp_out);
+			memcpy(out + (ct - 1) * SM3_LEN, temp_out, mod);
+		}
+	}
+	mbedtls_free(buf_z_ct);
+	mbedtls_free(temp_out);
+	return 0;
+}
+
+/*byte =  x2 || y2*/
+static int x_y2byte(mbedtls_mpi *x, mbedtls_mpi *y, mbedtls_ecp_group *group,
+					unsigned char *byte, size_t *blen)
+{
+	int ret;
+	size_t tmp_len;
+	/*byte =  x2 || y2*/
+	memset(byte, 0, *blen);
+	tmp_len = mbedtls_mpi_size(&group->P);
+	// temp += x2
+	MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(x, byte, tmp_len));
+	// temp += y2
+	MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(y, byte + tmp_len, tmp_len));
+
+cleanup:
+	*blen = tmp_len * 2;
+
+	return (ret);
+}
+
+/*byte =  x2 || y2*/
+static int point2byte(mbedtls_ecp_point *point, mbedtls_ecp_group *group,
+					  unsigned char *byte, size_t *blen)
+{
+	return x_y2byte(&point->X, &point->Y, group, byte, blen);
+}
+
+/*byte = x2 || m || y2*/
+static int byte_cat(mbedtls_ecp_point *point, const unsigned char *m,
+					size_t mlen, mbedtls_ecp_group *group, unsigned char *byte,
+					size_t *blen)
+{
+	int ret;
+	size_t p_len;
+	/*byte = x2 || m || y2*/
+	memset(byte, 0, *blen);
+	p_len = mbedtls_mpi_size(&(group->P));
+	// byte += x2
+	MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&point->X, byte, p_len));
+	//byte += m
+	memcpy(byte + p_len, m, mlen);
+	// byte += y2
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_write_binary(&point->Y, byte + p_len + mlen, p_len));
+
+cleanup:
+	*blen = p_len * 2 + mlen;
+
+	return (ret);
+}
+
+/**
+ * sm2 encrypt
+ *
+ */
+int sm2_do_encrypt(sm2_context *ctx, const unsigned char *buffer,
+				   size_t plen, unsigned char *out, size_t max_out_len, size_t *olen,
+				   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+{
+	int ret;
+	size_t max_len, c1_len, c2_len, c3_len, temp_len;
+	unsigned char *c1_buf, *c2_buf, *c3_buf, *temp;
+	int i;
+	mbedtls_mpi k;
+	mbedtls_ecp_point KG;
+	mbedtls_ecp_point KPb;
+
+	if (ctx == NULL || buffer == NULL)
+	{
+		return MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
+	}
+
+	max_len = plen + 64 * 2 + 1;
+
+	c1_len = 100;
+	c1_buf = mbedtls_calloc(c1_len, sizeof(unsigned char));
+
+	c2_len = plen + 1;
+	c2_buf = mbedtls_calloc(c2_len, sizeof(unsigned char));
+
+	c3_len = SM3_LEN;
+	c3_buf = mbedtls_calloc(c3_len, sizeof(unsigned char));
+
+	temp_len = max_len;
+	temp = mbedtls_calloc(temp_len, sizeof(unsigned char));
+
+	if (c1_buf == NULL || c2_buf == NULL || c3_buf == NULL || temp == NULL)
+	{
+		return MBEDTLS_ERR_MPI_ALLOC_FAILED;
+	}
+
+	mbedtls_mpi_init(&k);
+	mbedtls_ecp_point_init(&KG);
+	mbedtls_ecp_point_init(&KPb);
+
+	do
+	{
+		size_t n_size, tmp_len;
+		int iter;
+		/* generate rand k  from range n */
+		/* rand k in [1, n-1] */
+		n_size = (ctx->grp.nbits + 7) / 8;
+		MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&k, n_size, f_rng, p_rng));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&k, &k, &ctx->grp.N));
+		// MBEDTLS_MPI_CHK(rand(&k, &(ctx->grp.N)));
+
+		/* compute ephem_point [k]G = (x1, y1)   to KG */
+		MBEDTLS_MPI_CHK(
+			mbedtls_ecp_mul(&(ctx->grp), &KG, &k, &(ctx->grp.G), NULL, NULL));
+		tmp_len = 0;
+		memset(c1_buf, 0, c1_len);
+		MBEDTLS_MPI_CHK(
+			mbedtls_ecp_point_write_binary(&(ctx->grp), &KG, MBEDTLS_ECP_PF_UNCOMPRESSED, &tmp_len, c1_buf, c1_len));
+		c1_len = tmp_len;
+		tmp_len = 0;
+
+		/* compute [k]PukeyB = [k](XB,YB) = (x2,y2)*/
+		MBEDTLS_MPI_CHK(
+			mbedtls_ecp_mul(&(ctx->grp), &KPb, &k, &(ctx->Pb), NULL, NULL));
+
+		/*temp =  x2 || y2*/
+		MBEDTLS_MPI_CHK(point2byte(&KPb, &(ctx->grp), temp, &temp_len));
+
+		/* compute t = KDF(x2 || y2, klen) */
+		MBEDTLS_MPI_CHK(kdf(c2_buf, temp, temp_len, plen));
+		temp_len = max_len;
+
+		// check :if(t == 0) -> return to 1st step
+
+		for (iter = 0; iter < (int)plen; iter++)
+		{
+			if (c2_buf[iter] != 0)
+				break;
+		}
+		if ((int)plen != iter)
+			break;
+
+	} while (1);
+
+	/* cipher_text = t xor M */
+
+	for (i = 0; i < (int)plen; i++)
+	{
+		c2_buf[i] ^= buffer[i];
+	}
+	c2_len = plen;
+
+	/*compute C3 = HASH(x2|| M || y2)*/
+	/*temp buf = x2 || m || y2*/
+	MBEDTLS_MPI_CHK(byte_cat(&KPb, buffer, plen, &(ctx->grp), temp, &temp_len));
+
+	//sm3 temp
+	sm3(temp, temp_len, c3_buf);
+
+	if (max_out_len < c1_len + c2_len + c3_len || NULL == out)
+	{
+		ret = MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE;
+		goto cleanup;
+	}
+
+	memset(out, 0, max_out_len);
+	memcpy(out, c1_buf, c1_len);
+	memcpy(out + c1_len, c2_buf, c2_len);
+	memcpy(out + c1_len + c2_len, c3_buf, c3_len);
+
+cleanup:
+	*olen = c1_len + c2_len + c3_len;
+
+	mbedtls_mpi_free(&k);
+	mbedtls_ecp_point_free(&KG);
+	mbedtls_ecp_point_free(&KPb);
+	mbedtls_free(temp);
+	mbedtls_free(c1_buf);
+	mbedtls_free(c2_buf);
+	mbedtls_free(c3_buf);
+
+	return (ret);
+}
+
+/**
+ * sm2 decrypt
+ *
+ */
+int sm2_do_decrypt(sm2_context *ctx, const unsigned char *cipher, size_t clen,
+				   unsigned char *out, size_t max_out_len, size_t *olen)
+{
+	int ret;
+	size_t i;
+	size_t temp_len, c1_len, c3_len, c2_len;
+	unsigned char *temp, *c1_buf, *c3_buf, *c2_buf;
+	mbedtls_ecp_point P_1;
+	mbedtls_ecp_point P_2;
+
+	//presume the input data : [C1(65 Byte)][C2(unknown length)][C3(32 Byte)]
+	if (NULL == cipher || 98 > clen)
+	{
+		return -MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
+	}
+
+	temp_len = clen;
+	temp = mbedtls_calloc(temp_len, sizeof(unsigned char));
+	c1_len = 65;
+	c1_buf = mbedtls_calloc(c1_len, sizeof(unsigned char));
+	c3_len = SM3_LEN;
+	c3_buf = mbedtls_calloc(c3_len, sizeof(unsigned char));
+	c2_len = clen - c1_len - c3_len;
+	c2_buf = mbedtls_calloc(c2_len, sizeof(unsigned char));
+
+	if (temp == NULL || c1_buf == NULL || c3_buf == NULL || c2_buf == NULL)
+	{
+		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
+	}
+
+	mbedtls_ecp_point_init(&P_2);
+	mbedtls_ecp_point_init(&P_1);
+
+	memcpy(c1_buf, cipher, c1_len);
+
+	/*get c1 point x1,y1  to P_1*/
+	MBEDTLS_MPI_CHK(
+		mbedtls_ecp_point_read_binary(&(ctx->grp), &P_1, c1_buf, c1_len));
+
+	/* check c1 */
+	MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(&(ctx->grp), &P_1));
+
+	/* P_2 = dA*C1 = (x2,y2) */
+	MBEDTLS_MPI_CHK(
+		mbedtls_ecp_mul(&(ctx->grp), &P_2, &(ctx->d), &P_1, NULL, NULL));
+
+	/* t= KDF(x2||y2, klen)*/
+	/*temp =  x2 || y2 */
+	MBEDTLS_MPI_CHK(point2byte(&P_2, &(ctx->grp), temp, &temp_len));
+
+	/* compute t = KDF(x2 || y2, klen) */
+	MBEDTLS_MPI_CHK(kdf(c2_buf, temp, temp_len, c2_len));
+
+	/*check  t !=0;*/
+
+	for (i = 0; i < c2_len; i++)
+	{
+		if (c2_buf[i] != 0)
+			break;
+	}
+	if (c2_len == i)
+	{
+		ret = MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
+		goto cleanup;
+	}
+
+	/* m` = t xor c2 */
+	for (i = 0; i < c2_len; i++)
+	{
+		c2_buf[i] ^= cipher[c1_len + i];
+	}
+
+	/*compute u = HASH(x2|| M` || y2)*/
+	/*temp buf = x2 || m` || y2*/
+	MBEDTLS_MPI_CHK(
+		byte_cat(&P_2, c2_buf, c2_len, &(ctx->grp), temp, &temp_len));
+
+	sm3(temp, temp_len, c3_buf);
+
+	for (i = 0; i < c3_len; i++)
+	{
+		if (c3_buf[i] != (cipher + c1_len + c2_len)[i])
+		{
+			ret = MBEDTLS_ERR_SM2_PRIVATE_FAILED;
+			goto cleanup;
+		}
+	}
+
+	if (max_out_len < c2_len || NULL == out)
+	{
+		ret = MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE;
+		goto cleanup;
+	}
+
+	memset(out, 0, max_out_len);
+	memcpy(out, c2_buf, c2_len);
+
+cleanup:
+	*olen = c2_len;
+
+	mbedtls_ecp_point_free(&P_1);
+	mbedtls_ecp_point_free(&P_2);
+	mbedtls_free(c1_buf);
+	mbedtls_free(c2_buf);
+	mbedtls_free(c3_buf);
+
+	return (ret);
+}
+
+/**
+ *
+ * sm2 sign byte e
+ */
+int sm2_do_sign(sm2_context *ctx, const unsigned char *dgst, size_t dgstlen,
+				unsigned char *out, size_t max_out_len, size_t *olen,
+				int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+{
+	int ret;
+	mbedtls_mpi e;
+	mbedtls_mpi k;
+	mbedtls_mpi r;
+	mbedtls_mpi s;
+	mbedtls_mpi tmp;
+	mbedtls_mpi tmp_2;
+
+	mbedtls_ecp_point KG;
+
+	mbedtls_mpi_init(&e);
+	mbedtls_mpi_init(&k);
+	mbedtls_mpi_init(&r);
+	mbedtls_mpi_init(&s);
+	mbedtls_mpi_init(&tmp);
+	mbedtls_mpi_init(&tmp_2);
+
+	mbedtls_ecp_point_init(&KG);
+
+	/* convert dgst to e  : e = h(m)  */
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&e, dgst, dgstlen));
+
+	do
+	{
+		/* generate rand k  from range n*/
+		size_t n_size = (ctx->grp.nbits + 7) / 8;
+		MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&k, n_size, f_rng, p_rng));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&k, &k, &ctx->grp.N));
+
+		/*KG = [K]G = (x1,y1)*/
+		MBEDTLS_MPI_CHK(
+			mbedtls_ecp_mul(&(ctx->grp), &KG, &k, &(ctx->grp.G), NULL, NULL));
+
+		/*r = (e + x1) mod n*/
+		/* tmp = e + x1 */
+		MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&tmp, &e, &KG.X));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&r, &tmp, &(ctx->grp.N)));
+
+		/* r !=0 and r + k != n*/
+		if (mbedtls_mpi_cmp_int(&r, 0) == 0)
+		{
+			continue;
+		}
+		else
+		{
+			mbedtls_mpi_free(&tmp);
+			MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&tmp, &r, &k));
+			if (mbedtls_mpi_cmp_mpi(&tmp, &(ctx->grp.N)) == 0)
+			{
+				continue;
+			}
+		}
+
+		/* s = ((1 + d)^-1 * (k - rd)) mod n
+		 * s = (((1 + d)^-1 mod n) *  ((k - rd) mod n) ) mod n
+		 */
+
+		/*((1 + d)^-1 mod n)*/
+		mbedtls_mpi_free(&tmp);
+		MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&tmp, &ctx->d, 1));
+		MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&s, &tmp, &(ctx->grp.N)));
+
+		/* ((k - rd) mod n) */
+		/* tmp = rd */
+		mbedtls_mpi_init(&tmp);
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&tmp, &r, (&ctx->d)));
+		/* tmp_2 = k - rd */
+		MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&tmp_2, &k, &tmp));
+		/* tmp_2 mod n*/
+		mbedtls_mpi_free(&tmp);
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&tmp, &tmp_2, &(ctx->grp.N)));
+
+		/* tmp_2 = ((1 + d)^-1 mod n) *  ((k - rd) mod n) */
+		mbedtls_mpi_free(&tmp_2);
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&tmp_2, &s, &tmp));
+		/* s = tmp_2 mod n*/
+		mbedtls_mpi_free(&s);
+		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&s, &tmp_2, &(ctx->grp.N)));
+
+		if (mbedtls_mpi_cmp_int(&s, 0) == 0)
+		{
+			continue;
+		}
+		else
+		{
+			break;
+		}
+
+	} while (1);
+
+	if (max_out_len < SM3_LEN * 2)
+	{
+		ret = MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE;
+		goto cleanup;
+	}
+	*olen = max_out_len;
+	MBEDTLS_MPI_CHK(x_y2byte(&r, &s, &(ctx->grp), out, olen));
+
+cleanup:
+	mbedtls_mpi_free(&e);
+	mbedtls_mpi_free(&k);
+	mbedtls_mpi_free(&r);
+	mbedtls_mpi_free(&s);
+	mbedtls_mpi_free(&tmp);
+	mbedtls_mpi_free(&tmp_2);
+	mbedtls_ecp_point_free(&KG);
+	return (ret);
+}
+
+/**
+ * sm2 sign verify byte e
+ *
+ */
+int sm2_do_verify(sm2_context *ctx, const unsigned char *message, size_t msglen,
+				  const unsigned char *dgst, size_t dgstlen)
+{
+	int ret;
+	mbedtls_mpi r;
+	mbedtls_mpi s;
+	mbedtls_mpi t;
+	mbedtls_mpi tmp;
+
+	mbedtls_ecp_point pointG;
+	if (dgstlen < SM3_LEN * 2)
+	{
+		return MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
+	}
+
+	mbedtls_mpi_init(&r);
+	mbedtls_mpi_init(&s);
+	mbedtls_mpi_init(&t);
+	mbedtls_mpi_init(&tmp);
+
+	mbedtls_ecp_point_init(&pointG);
+
+	/*init r and s from byte*/
+	mbedtls_mpi_read_binary(&r, dgst, SM3_LEN);
+	mbedtls_mpi_read_binary(&s, dgst + SM3_LEN, SM3_LEN);
+
+	/* check r, s in [1, n-1]*/
+	if (mbedtls_mpi_cmp_int(&r, 1) == -1 || mbedtls_mpi_cmp_int(&s, 1) == -1 || mbedtls_mpi_cmp_mpi(&r, &(ctx->grp.N)) == 1 || mbedtls_mpi_cmp_mpi(&s, &(ctx->grp.N)) == 1)
+	{
+		ret = MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
+		goto cleanup;
+	}
+
+	/*  t = (r + s) mod n  */
+	/* tmp = r + s*/
+	MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&tmp, &r, &s));
+	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&t, &tmp, &(ctx->grp.N)));
+
+	/* check t  != 0 */
+	if (mbedtls_mpi_cmp_int(&t, 0) == 0)
+	{
+		ret = MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
+		goto cleanup;
+	}
+
+	/* compute pointG= (x, y) = sG + tP, P is pub_key */
+	MBEDTLS_MPI_CHK(
+		mbedtls_ecp_muladd(&(ctx->grp), &pointG, &s, &(ctx->grp.G), &t,
+						   &(ctx->Pb)));
+
+	/* tmp <- R = (e + x1) mod n  ;x1 in pointG */
+	/* t <- e */
+	mbedtls_mpi_free(&t);
+	MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&t, message, msglen));
+	/* s <- e + x1 */
+	mbedtls_mpi_free(&s);
+	MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&s, &t, &(pointG.X)));
+	/*tmp <- R = s mod n*/
+	mbedtls_mpi_free(&tmp);
+	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&tmp, &s, &(ctx->grp.N)));
+
+	/*tmp (R) = r ?*/
+	if (mbedtls_mpi_cmp_mpi(&tmp, &r) != 0)
+	{
+		ret = MBEDTLS_ERR_SM2_VERIFY_FAILED;
+	}
+
+cleanup:
+
+	mbedtls_mpi_free(&r);
+	mbedtls_mpi_free(&s);
+	mbedtls_mpi_free(&t);
+	mbedtls_mpi_free(&tmp);
+
+	mbedtls_ecp_point_free(&pointG);
+	return (ret);
+}
+
+/**
+ *  generate the e   e = H(m)
+ */
+int sm2_z_generate(sm2_context *ctx, const char *id, size_t idlen,
+				   const char *message, size_t msglen, unsigned char *out)
+{
+
+	int ret;
+	size_t hasg_len = SM3_LEN + msglen;
+	unsigned char *hash = mbedtls_calloc(hasg_len, sizeof(unsigned char));
+
+	size_t len_idlen = 2;
+	size_t p_len = mbedtls_mpi_size(&(ctx->grp.P));
+	size_t z_len = len_idlen + idlen + p_len * 6;
+	unsigned char *z_buf = mbedtls_calloc(z_len, sizeof(unsigned char));
+
+	if (hash == NULL || z_buf == NULL)
+	{
+		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
+	}
+
+	/* z += ENTLa */
+	int_to_byte_4(z_buf, 0, idlen * 8);
+	/* z += id*/
+	memcpy(z_buf + len_idlen, id, idlen);
+	/* z += a*/
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_write_binary(&(ctx->grp.A), z_buf + len_idlen + idlen,
+								 p_len));
+	/* z += b*/
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_write_binary(&(ctx->grp.B),
+								 z_buf + len_idlen + idlen + p_len, p_len));
+	/* z += gx*/
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_write_binary(&(ctx->grp.G.X),
+								 z_buf + len_idlen + idlen + p_len * 2, p_len));
+	/* z +=gy*/
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_write_binary(&(ctx->grp.G.Y),
+								 z_buf + len_idlen + idlen + p_len * 3, p_len));
+	/* z += pk.x*/
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_write_binary(&(ctx->Pb.X),
+								 z_buf + len_idlen + idlen + p_len * 4, p_len));
+	/* z += pk.y*/
+	MBEDTLS_MPI_CHK(
+		mbedtls_mpi_write_binary(&(ctx->Pb.Y),
+								 z_buf + len_idlen + idlen + p_len * 5, p_len));
+	/*sm3 z*/
+	sm3(z_buf, z_len, hash);
+
+	memcpy(hash + SM3_LEN, message, msglen);
+
+	/*h(m)*/
+	sm3(hash, hasg_len, out);
+
+cleanup:
+	mbedtls_free(hash);
+	mbedtls_free(z_buf);
+
+	return (ret);
+}
+
+/**
+ *  sm2 sign
+ */
+int sm2_do_id_sign(sm2_context *ctx, const char *id, size_t idlen,
+				   const char *message, size_t msglen, unsigned char *out,
+				   size_t max_out_len, size_t *olen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+{
+
+	int ret;
+	unsigned char *hash = mbedtls_calloc(SM3_LEN, sizeof(unsigned char));
+	if (hash == NULL)
+	{
+		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
+	}
+	MBEDTLS_MPI_CHK(sm2_z_generate(ctx, id, idlen, message, msglen, hash));
+	MBEDTLS_MPI_CHK(
+		sm2_do_sign(ctx, hash, SM3_LEN, out, max_out_len, olen, f_rng, p_rng));
+
+cleanup:
+	mbedtls_free(hash);
+	return (ret);
+}
+
+/**
+ *   sm2 sign verify
+ */
+int sm2_do_id_verify(sm2_context *ctx, const char *id, size_t idlen,
+					 const char *message, size_t msglen, const unsigned char *dgst,
+					 size_t dgstlen)
+{
+	int ret;
+	unsigned char *hash = mbedtls_calloc(SM3_LEN, sizeof(unsigned char));
+	if (hash == NULL)
+	{
+		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
+	}
+	MBEDTLS_MPI_CHK(sm2_z_generate(ctx, id, idlen, message, msglen, hash));
+	MBEDTLS_MPI_CHK(sm2_do_verify(ctx, hash, SM3_LEN, dgst, dgstlen));
+
+cleanup:
+	mbedtls_free(hash);
+	return (ret);
+}
+
+/**
+ * test
+ */
+
+#if defined(MBEDTLS_SM2_SELF_TEST)
+
+#define STR_LEN 300
+#define PARAM_LEN 64
+
+#define PP "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3"
+#define PA "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498"
+#define PB "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A"
+#define PGX "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D"
+#define PGY "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"
+#define PN "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7"
+
+static int myrand(void *ctx, unsigned char *msg, size_t size)
+{
+	mbedtls_mpi k;
+	mbedtls_mpi_init(&k);
+	mbedtls_mpi_read_string(&k, HEX_CODE,
+							"4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F");
+	mbedtls_mpi_write_binary(&k, msg, size);
+	mbedtls_mpi_free(&k);
+	return 0;
+}
+
+static int signrand(void *ctx, unsigned char *msg, size_t size)
+{
+	mbedtls_mpi k;
+	if (ctx != NULL)
+	{
+		mbedtls_mpi_init(&k);
+		mbedtls_mpi_read_string(&k, HEX_CODE,
+								"6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F");
+		mbedtls_mpi_write_binary(&k, msg, size);
+		mbedtls_mpi_free(&k);
+	}
+
+	return 0;
+}
+
+const char d1[] =
+	"1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0";
+const char d2[] =
+	"128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263";
+
+const char pk1x[] =
+	"435B39CCA8F3B508C1488AFC67BE491A0F7BA07E581A0E4849A5CF70628A7E0A";
+const char pk1y[] =
+	"75DDBA78F15FEECB4C7895E2C1CDF5FE01DEBB2CDBADF45399CCF77BBA076A42";
+const char pk2x[] =
+	"0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A";
+const char pk2y[] =
+	"7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857";
+
+int mbedtls_sm2_self_test(int verbose)
+{
+
+	unsigned char *out = mbedtls_calloc(STR_LEN, sizeof(unsigned char));
+	unsigned char *out2 = mbedtls_calloc(STR_LEN, sizeof(unsigned char));
+
+	int ret = 0;
+	size_t olen = 0, olen2 = 0;
+	sm2_context sm2;
+	sm2_init(&sm2);
+
+	/**
+	 *   not advice to set the group
+	 *   but in here we just to test ,so set the test group param.
+	 *   commonly we do not set the group;
+	 *   because use the default group
+	 *   \see sm2_init(sm2_context * context)
+	 */
+	ret = sm2_read_group_string(&sm2, PP, PA, PB, PGX, PGY, PN);
+	if (ret != 0)
+	{
+		if (verbose > 0)
+		{
+			mbedtls_printf("sm2 init group failed:");
+		}
+		goto cleanup;
+	}
+
+	/**
+	 *  encrypt and decrypt
+	 */
+	if (verbose == 1)
+	{
+		const char *str = "encryption standard";
+		mbedtls_printf("sm2 encrypt start:");
+
+		//set key
+		sm2_read_string_private(&sm2, d1);
+		sm2_read_string_public(&sm2, pk1x, pk1y);
+
+		/**
+		 * here use the test rand k so use myrand
+		 */
+		ret = sm2_do_encrypt(&sm2, (const unsigned char *)str, strlen(str), out, STR_LEN, &olen,
+							 myrand, NULL);
+
+		if (ret == 0)
+		{
+			mbedtls_printf("sm2 encrypt passed.");
+		}
+		else
+		{
+			mbedtls_printf("sm2 encrypt failed.");
+			goto cleanup;
+		}
+
+		mbedtls_printf("sm2 decrypt start:");
+
+		ret = sm2_do_decrypt(&sm2, out, olen, out2, STR_LEN, &olen2);
+
+		if (ret == 0 && strcmp(str, (const char *)out2) == 0)
+		{
+
+			mbedtls_printf("sm2 decrypt passed.");
+		}
+		else
+		{
+
+			mbedtls_printf("sm2 decrypt failed.");
+			goto cleanup;
+		}
+	}
+	else if (verbose == 2)
+	{
+		//sign or verify
+		const char *str = "message digest";
+		const char *id = "ALICE123@YAHOO.COM";
+
+		mbedtls_printf("sm2 sign start:");
+		//set key
+		sm2_read_string_private(&sm2, d2);
+		sm2_read_string_public(&sm2, pk2x, pk2y);
+
+		/**
+		 * here use the test rand k so use signrand
+		 */
+		ret = sm2_do_id_sign(&sm2, id, strlen(id), str, strlen(str), out,
+							 STR_LEN, &olen, signrand, NULL);
+
+		if (ret == 0)
+		{
+			mbedtls_printf("sm2 sign passed.");
+		}
+		else
+		{
+			mbedtls_printf("sm2 sign failed.");
+			goto cleanup;
+		}
+
+		mbedtls_printf("sm2 sign verify start:");
+
+		ret = sm2_do_id_verify(&sm2, id, strlen(id), str, strlen(str), out,
+							   olen);
+		if (ret == 0)
+		{
+			mbedtls_printf("sm2 verify passed.");
+		}
+		else
+		{
+			mbedtls_printf("sm2 verify failed.");
+			goto cleanup;
+		}
+	}
+	else if (verbose == 3)
+	{
+
+		//        other test
+		mbedtls_printf("sm2  key generate start:\n");
+
+		sm2_free(&sm2);
+		sm2_init(&sm2);
+
+		// generate key test
+		ssl_random_context random_ctx;
+
+		ssl_random_init(&random_ctx);
+		ssl_random_seed(&random_ctx, NULL, 0);
+		ret = sm2_gen_keypair(&sm2, ssl_random_rand, &random_ctx);
+		ssl_random_free(&random_ctx);
+
+		if (ret == 0 && mbedtls_mpi_size(&sm2.d) > 0)
+		{
+			mbedtls_printf("sm2 key generate passed.\n");
+			memset(out, 0, STR_LEN);
+			mbedtls_mpi_write_binary(&sm2.d, out, 32);
+
+			mbedtls_printf("private key is : \n");
+			int i = 0;
+			for (i = 0; i < 32; i++)
+				mbedtls_printf("%02x", out[i]);
+			mbedtls_printf("\n");
+
+			mbedtls_printf("public key is \n");
+
+			memset(out, 0, STR_LEN);
+			mbedtls_mpi_write_binary(&sm2.Pb.X, out, 32);
+			for (i = 0; i < 32; i++)
+				mbedtls_printf("%02x", out[i]);
+			mbedtls_printf("\n");
+			memset(out, 0, STR_LEN);
+			mbedtls_mpi_write_binary(&sm2.Pb.Y, out, 32);
+			for (i = 0; i < 32; i++)
+				mbedtls_printf("%02x", out[i]);
+			mbedtls_printf("\n");
+			memset(out, 0, STR_LEN);
+			mbedtls_mpi_write_binary(&sm2.Pb.Z, out, 32);
+			for (i = 0; i < 32; i++)
+				mbedtls_printf("%02x", out[i]);
+			mbedtls_printf("\n");
+		}
+		else
+		{
+			mbedtls_printf("sm2 generate failed. %d", ret);
+			goto cleanup;
+		}
+	}
+
+cleanup:
+	sm2_free(&sm2);
+	mbedtls_free(out);
+	mbedtls_free(out2);
+
+	return ret;
+}
+
+#endif // test

+ 303 - 0
components/SM/src/sm3/sm3.c

@@ -0,0 +1,303 @@
+/**
+ *
+ *
+ * \file        sm3.c
+ *
+ * \brief       this file is header file for sm3(chinese business Digital Digest).
+ *              and  compatible md framework.
+ *
+ * \anchor      lzj
+ *
+ * \date        2017/8/14
+ *
+ *
+ */
+
+
+#include <mbedtls/config.h>
+#include <sm3/sm3.h>
+#include <string.h>
+
+#if defined(MBEDTLS_SELF_TEST)
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef ANDROID_LOG
+#include <android/log.h>
+#define mbedtls_printf(...)  __android_log_print(ANDROID_LOG_DEBUG, "SECURITY_LIBRARY", __VA_ARGS__)
+#else
+#define mbedtls_printf     printf
+#endif
+
+#define mbedtls_calloc    calloc
+#define mbedtls_free       free
+#endif /* MBEDTLS_SELF_TEST */
+
+
+#define SM3_DIGEST_LENGTH    32
+#define SM3_BLOCK_SIZE        64
+
+
+#define cpu_to_be32(v) (((v)>>24) | (((v)>>8)&0xff00) | (((v)<<8)&0xff0000) | ((v)<<24))
+
+#define ROTATELEFT(X, n)  (((X)<<(n&31)) | ((X)>>(32-(n&31))))
+
+#define P0(x) ((x) ^  ROTATELEFT((x),9)  ^ ROTATELEFT((x),17))
+#define P1(x) ((x) ^  ROTATELEFT((x),15) ^ ROTATELEFT((x),23))
+
+#define FF0(x, y, z) ( (x) ^ (y) ^ (z))
+#define FF1(x, y, z) (((x) & (y)) | ( (x) & (z)) | ( (y) & (z)))
+
+#define GG0(x, y, z) ( (x) ^ (y) ^ (z))
+#define GG1(x, y, z) (((x) & (y)) | ( (~(x)) & (z)) )
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize(void *v, size_t n) {
+    volatile unsigned char *p = v;
+    while (n--) *p++ = 0;
+}
+
+void sm3_init(sm3_context *ctx) {
+    memset(ctx, 0, sizeof(sm3_context));
+}
+
+void sm3_free(sm3_context *ctx) {
+    if (ctx == NULL)
+        return;
+    mbedtls_zeroize(ctx, sizeof(sm3_context));
+}
+
+void sm3_clone(sm3_context *dst, const sm3_context *src) {
+    *dst = *src;
+}
+
+
+void sm3_starts(sm3_context *ctx) {
+
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x7380166F;
+    ctx->state[1] = 0x4914B2B9;
+    ctx->state[2] = 0x172442D7;
+    ctx->state[3] = 0xDA8A0600;
+    ctx->state[4] = 0xA96F30BC;
+    ctx->state[5] = 0x163138AA;
+    ctx->state[6] = 0xE38DEE4D;
+    ctx->state[7] = 0xB0FB0E4E;
+}
+
+
+void sm3_process(sm3_context *ctx, const unsigned char block[64]) {
+
+
+    int j;
+    uint32_t W[68], W1[64];
+    const uint32_t *pblock = (const uint32_t *) block;
+
+    uint32_t A = ctx->state[0];
+    uint32_t B = ctx->state[1];
+    uint32_t C = ctx->state[2];
+    uint32_t D = ctx->state[3];
+    uint32_t E = ctx->state[4];
+    uint32_t F = ctx->state[5];
+    uint32_t G = ctx->state[6];
+    uint32_t H = ctx->state[7];
+    uint32_t SS1, SS2, TT1, TT2, T[64];
+
+    for (j = 0; j < 16; j++) {
+        W[j] = cpu_to_be32(pblock[j]);
+    }
+    for (j = 16; j < 68; j++) {
+        W[j] = P1(W[j - 16] ^ W[j - 9] ^ ROTATELEFT(W[j - 3], 15)) ^ ROTATELEFT(W[j - 13], 7) ^
+               W[j - 6];;
+    }
+
+
+    for (j = 0; j < 64; j++) {
+        W1[j] = W[j] ^ W[j + 4];
+    }
+
+    for (j = 0; j < 16; j++) {
+
+        T[j] = 0x79CC4519;
+        SS1 = ROTATELEFT((ROTATELEFT(A, 12) + E + ROTATELEFT(T[j], j)), 7);
+        SS2 = SS1 ^ ROTATELEFT(A, 12);
+        TT1 = FF0(A, B, C) + D + SS2 + W1[j];
+        TT2 = GG0(E, F, G) + H + SS1 + W[j];
+        D = C;
+        C = ROTATELEFT(B, 9);
+        B = A;
+        A = TT1;
+        H = G;
+        G = ROTATELEFT(F, 19);
+        F = E;
+        E = P0(TT2);
+    }
+
+    for (j = 16; j < 64; j++) {
+
+        T[j] = 0x7A879D8A;
+        SS1 = ROTATELEFT((ROTATELEFT(A, 12) + E + ROTATELEFT(T[j], j)), 7);
+        SS2 = SS1 ^ ROTATELEFT(A, 12);
+        TT1 = FF1(A, B, C) + D + SS2 + W1[j];
+        TT2 = GG1(E, F, G) + H + SS1 + W[j];
+        D = C;
+        C = ROTATELEFT(B, 9);
+        B = A;
+        A = TT1;
+        H = G;
+        G = ROTATELEFT(F, 19);
+        F = E;
+        E = P0(TT2);
+    }
+
+    ctx->state[0] ^= A;
+    ctx->state[1] ^= B;
+    ctx->state[2] ^= C;
+    ctx->state[3] ^= D;
+    ctx->state[4] ^= E;
+    ctx->state[5] ^= F;
+    ctx->state[6] ^= G;
+    ctx->state[7] ^= H;
+}
+
+
+void sm3_update(sm3_context *ctx, const unsigned char *input, size_t ilen) {
+    if (ctx->total[0]) {
+        unsigned int left = SM3_BLOCK_SIZE - ctx->total[0];
+        if (ilen < left) {
+            memcpy(ctx->buffer + ctx->total[0], input, ilen);
+            ctx->total[0] += ilen;
+            return;
+        } else {
+            memcpy(ctx->buffer + ctx->total[0], input, left);
+            sm3_process(ctx, ctx->buffer);
+            ctx->total[1]++;
+            input += left;
+            ilen -= left;
+        }
+    }
+    while (ilen >= SM3_BLOCK_SIZE) {
+        sm3_process(ctx, input);
+        ctx->total[1]++;
+        input += SM3_BLOCK_SIZE;
+        ilen -= SM3_BLOCK_SIZE;
+    }
+    ctx->total[0] = ilen;
+    if (ilen) {
+        memcpy(ctx->buffer, input, ilen);
+    }
+}
+
+
+void sm3_finish(sm3_context *ctx, unsigned char output[32]) {
+    size_t i;
+    uint32_t *pdigest = (uint32_t *) output;
+    uint32_t *count = (uint32_t *) (ctx->buffer + SM3_BLOCK_SIZE - 8);
+
+    ctx->buffer[ctx->total[0]] = 0x80;
+
+    if (ctx->total[0] + 9 <= SM3_BLOCK_SIZE) {
+        memset(ctx->buffer + ctx->total[0] + 1, 0, SM3_BLOCK_SIZE - ctx->total[0] - 9);
+    } else {
+        memset(ctx->buffer + ctx->total[0] + 1, 0, SM3_BLOCK_SIZE - ctx->total[0] - 1);
+        sm3_process(ctx, ctx->buffer);
+        memset(ctx->buffer, 0, SM3_BLOCK_SIZE - 8);
+    }
+
+    count[0] = cpu_to_be32((ctx->total[1]) >> 23);
+    count[1] = cpu_to_be32((ctx->total[1] << 9) + (ctx->total[0] << 3));
+
+    sm3_process(ctx, ctx->buffer);
+    for (i = 0; i < sizeof(ctx->state) / sizeof(ctx->state[0]); i++) {
+        pdigest[i] = cpu_to_be32(ctx->state[i]);
+    }
+}
+
+
+void sm3(const unsigned char *msg, size_t msglen,
+         unsigned char dgst[SM3_DIGEST_LENGTH]) {
+    sm3_context ctx;
+
+    sm3_init(&ctx);
+    sm3_starts(&ctx);
+    sm3_update(&ctx, msg, msglen);
+    sm3_finish(&ctx, dgst);
+    sm3_free(&ctx);
+}
+
+
+#ifdef  MBEDTLS_SELF_TEST
+static const uint8_t test_buf[2][64] = {
+        {"abc"},
+        {"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"},
+};
+
+static const int test_buflen[2] = {
+        3, 64
+};
+
+static const uint8_t test_sum[2][32] = {
+        /*
+         * sm3 test vectors
+         */
+        {0x66, 0xc7, 0xf0, 0xf4, 0x62, 0xee, 0xed, 0xd9,
+                0xd1, 0xf2, 0xd4, 0x6b, 0xdc, 0x10, 0xe4, 0xe2,
+                0x41, 0x67, 0xc4, 0x87, 0x5c, 0xf2, 0xf7, 0xa2,
+                0x29, 0x7d, 0xa0, 0x2b, 0x8f, 0x4b, 0xa8, 0xe0},
+
+        {0xDE, 0xBE, 0x9F, 0xF9, 0x22, 0x75, 0xB8, 0xA1,
+                0x38, 0x60, 0x48, 0x89, 0xC1, 0x8E, 0x5A, 0x4D,
+                0x6F, 0xDB, 0x70, 0xE5, 0x38, 0x7E, 0x57, 0x65,
+                0x29, 0x3D, 0xCB, 0xA3, 0x9c, 0x0c, 0x57, 0x32}
+
+};
+
+
+int sm3_self_test(int verbose) {
+    int i, ret = 0;
+    unsigned char sm3sum[32];
+    sm3_context ctx;
+
+
+    sm3_init(&ctx);
+
+    for (i = 0; i < 2; i++) {
+
+
+        if (verbose != 0)
+            mbedtls_printf("  sm3 test #%s: \n ", test_buf[i]);
+
+        sm3_starts(&ctx);
+
+
+        sm3_update(&ctx, test_buf[i], (size_t) test_buflen[i]);
+
+
+        sm3_finish(&ctx, sm3sum);
+
+        if (memcmp(sm3sum, test_sum[i], 32) != 0) {
+            if (verbose != 0)
+                mbedtls_printf("failed\n");
+
+            ret = 1;
+            goto exit;
+        }
+
+        if (verbose != 0)
+            mbedtls_printf("passed\n");
+    }
+
+    if (verbose != 0)
+        mbedtls_printf("\n");
+
+    exit:
+    sm3_free(&ctx);
+    return (ret);
+
+}
+
+#endif
+

+ 63 - 0
components/SM/src/sm4/sm4_cbc.c

@@ -0,0 +1,63 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <sm4/sm4.h>
+#include <openssl/modes.h>
+
+void sm4_cbc_encrypt(const unsigned char *in, unsigned char *out,
+	size_t len, const sm4_key_t *key, unsigned char *iv, int enc)
+{
+	unsigned char piv[16] = {0};
+	memcpy(piv,iv,16);
+	
+	if (enc)
+		CRYPTO_cbc128_encrypt(in, out, len, key, piv, (block128_f)sm4_encrypt);
+	else	
+		CRYPTO_cbc128_decrypt(in, out, len, key, piv, (block128_f)sm4_encrypt);
+}

+ 57 - 0
components/SM/src/sm4/sm4_cfb.c

@@ -0,0 +1,57 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <sm4/sm4.h>
+#include <openssl/modes.h>
+
+void sm4_cfb128_encrypt(const unsigned char *in, unsigned char *out,
+	size_t len, const sm4_key_t *key, unsigned char *iv, int *num, int enc)
+{
+	CRYPTO_cfb128_encrypt(in, out, len, key, iv, num, enc, (block128_f)sm4_encrypt);
+}

+ 104 - 0
components/SM/src/sm4/sm4_common.c

@@ -0,0 +1,104 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <stdint.h>
+#include "sm4_lcl.h"
+
+uint8_t SBOX[256] = {
+	0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
+	0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
+	0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
+	0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
+	0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
+	0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
+	0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
+	0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
+	0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
+	0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
+	0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
+	0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
+	0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
+	0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
+	0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
+	0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
+	0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
+	0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
+	0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
+	0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
+	0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
+	0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
+	0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
+	0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
+	0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
+	0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
+	0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
+	0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
+	0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
+	0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
+	0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
+	0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
+};
+#if 0
+uint32_t SBOX32L[256 * 256];
+uint32_t SBOX32H[256 * 256];
+
+void sm4_init_sbox32(void)
+{
+	int i, j;
+	uint32_t a;
+
+	for (i = 0; i < 256; i++) {
+		for (j = 0; j < 256; j++) {
+			a = SBOX[i] << 8 | SBOX[j];
+			SBOX32L[(i << 8) + j] = a;
+			SBOX32H[(i << 8) + j] = a << 16;
+		}
+	}
+}
+#endif

+ 80 - 0
components/SM/src/sm4/sm4_ctr.c

@@ -0,0 +1,80 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <sm4/sm4.h>
+#include <openssl/modes.h>
+
+void sm4_ctr128_encrypt(const unsigned char *in, unsigned char *out,
+	size_t len, const sm4_key_t *key, unsigned char *iv,
+	unsigned char ecount_buf[SM4_BLOCK_SIZE], unsigned int *num)
+{
+	CRYPTO_ctr128_encrypt(in, out, len, key, iv, ecount_buf, num,
+		(block128_f)sm4_encrypt);
+}
+
+void sm4_ctr128_ctr_init(unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16]) {
+    ctr128_init(nonce, iv, ctr_buf);
+}
+
+void sm4_ctr128_ctr_inc(unsigned char *counter) {
+    ctr128_inc(counter);
+}
+
+void sm4_ctr128_ctr_dec(unsigned char *counter) {
+    ctr128_dec(counter);
+}
+
+void sm4_ctr128_subctr(unsigned char *counter, const unsigned char *in, unsigned char *out,
+                        size_t length, const SM4_KEY *key) {
+
+    unsigned char ecount_buf[SM4_BLOCK_SIZE];
+    unsigned int num = 0;
+    memset(ecount_buf, 0, sizeof(ecount_buf));
+    sm4_ctr128_encrypt(in, out, length, key, counter, ecount_buf, &num);
+}

+ 59 - 0
components/SM/src/sm4/sm4_ecb.c

@@ -0,0 +1,59 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <sm4/sm4.h>
+#include <openssl/modes.h>
+
+void sm4_ecb_encrypt(const unsigned char *in, unsigned char *out,
+	const sm4_key_t *key, int enc)
+{
+	if (enc)
+		sm4_encrypt(in, out, key);
+	else	sm4_decrypt(in, out, key);
+}

+ 182 - 0
components/SM/src/sm4/sm4_enc.c

@@ -0,0 +1,182 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <sm4/sm4.h>
+#include "sm4_lcl.h"
+
+#ifdef DUMMY_ROUND
+	#include <string.h>
+	#include <stdbool.h>
+	#include <AisinoSSL/internal/aisinossl_random.h>
+#endif
+
+#ifdef SIMPLE_EXTERNAL_ENCODINGS
+
+#define APPLY_G_ROW( x, y, i) \
+    y = (G[i][(x >> 24) & 0xff] << 24) ^ \
+        (G[i][(x >> 16) & 0xff] << 16) ^ \
+        (G[i][(x >>  8) & 0xff] <<  8) ^ \
+        (G[i][(x      ) & 0xff]      );   \
+    x = y;
+
+ #define APPLY_F_ROW( x, y, i) \
+    y = (F[i][(x >> 24) & 0xff] << 24) ^ \
+        (F[i][(x >> 16) & 0xff] << 16) ^ \
+        (F[i][(x >>  8) & 0xff] <<  8) ^ \
+        (F[i][(x      ) & 0xff]      );   \
+    x = y;
+
+ #define SIMPLE_EXTERNAL_ENCODINGS_G(x, y, i) \
+    APPLY_G_ROW(x, y, i)
+
+ #define SIMPLE_EXTERNAL_ENCODINGS_F(x, y, i) \
+    APPLY_F_ROW(x, y, i)
+    
+#endif //SIMPLE_EXTERNAL_ENCODINGS
+
+#define L32(x)						\
+	((x) ^						\
+	ROT32((x),  2) ^				\
+	ROT32((x), 10) ^				\
+	ROT32((x), 18) ^				\
+	ROT32((x), 24))
+
+#define ROUND(x0, x1, x2, x3, x4, i)			\
+	x4 = x1 ^ x2 ^ x3 ^ *(rk + i);			\
+	x4 = S32(x4);					\
+	x4 = x0 ^ L32(x4)
+
+void sm4_encrypt(const unsigned char *in, unsigned char *out, const sm4_key_t *key)
+{
+	const uint32_t *rk = key->rk;
+	uint32_t x0, x1, x2, x3, x4;
+
+	x0 = GET32(in     );
+	x1 = GET32(in +  4);
+	x2 = GET32(in +  8);
+	x3 = GET32(in + 12);
+
+#ifdef DUMMY_ROUND
+	int r = 1;
+    uint32_t s[2][5];
+
+ 	// 0xf31a34ed, 0xb7b4cc7c, 0xfba9f4bf, 0x5e89d810, 0xf31a34ed, 0xb7b4cc7c, 0xfba9f4bf, 0x5e89d810,
+	// xor                                 0x1294e0d3, 0x563a1842, 0x1a272081, 0xbf070c2e
+	// k0                                  0x63e591a2, 0x274b6933, 0x6b5651f0, 0xce767d5f
+	// final 0x71717171
+    // sbox[0x71] = 0
+    const uint32_t beta[4] = {0xf31a34ed, 0xb7b4cc7c, 0xfba9f4bf, 0x5e89d810};
+    const uint32_t k0[4] = {0x63e591a2, 0x274b6933, 0x6b5651f0, 0xce767d5f};
+
+    memcpy(s[1], beta, 4*sizeof(uint32_t));
+
+    uint32_t dummyKey[SM4_NUM_ROUNDS+4];
+    memcpy(dummyKey+4, key->rk, SM4_NUM_ROUNDS*sizeof(uint32_t));
+    memcpy(dummyKey, k0, 4*sizeof(uint32_t));
+
+    s[0][0] = x0;
+    s[0][1] = x1;
+    s[0][2] = x2;
+    s[0][3] = x3;
+
+    rk = dummyKey;
+    int sm4_rounds = SM4_NUM_ROUNDS/4;
+
+    enum _CONST_INT{
+        E_RANDOM_NUMS = 100
+    };
+    
+    int random_list[E_RANDOM_NUMS];
+    
+    int rcnt = E_RANDOM_NUMS;
+
+    while(r <= sm4_rounds ) {
+
+        if (rcnt >= E_RANDOM_NUMS)  {
+            aisinossl_random_list(NULL, random_list, E_RANDOM_NUMS);
+            rcnt = 0;
+        }   
+        bool lambda  = ((random_list[rcnt++] %2)==1);  
+
+
+        int kai = lambda*r;
+        int tlambda = !lambda;  //turn lambda
+        ROUND(s[tlambda][0], s[tlambda][1], s[tlambda][2], s[tlambda][3], s[tlambda][4], 4*kai + 0);
+        ROUND(s[tlambda][1], s[tlambda][2], s[tlambda][3], s[tlambda][4], s[tlambda][0], 4*kai + 1);
+        ROUND(s[tlambda][2], s[tlambda][3], s[tlambda][4], s[tlambda][0], s[tlambda][1], 4*kai + 2);
+        ROUND(s[tlambda][3], s[tlambda][4], s[tlambda][0], s[tlambda][1], s[tlambda][2], 4*kai + 3);
+
+        s[tlambda][3] = s[tlambda][2];
+        s[tlambda][2] = s[tlambda][1];
+        s[tlambda][1] = s[tlambda][0];
+        s[tlambda][0] = s[tlambda][4];
+
+        s[0][0] = s[0][0] ^ s[1][0] ^ beta[0];
+        s[0][1] = s[0][1] ^ s[1][1] ^ beta[1];
+        s[0][2] = s[0][2] ^ s[1][2] ^ beta[2];
+        s[0][3] = s[0][3] ^ s[1][3] ^ beta[3];
+
+        r = r + lambda;
+    }
+    x0 = s[0][3];
+    x4 = s[0][2];
+    x3 = s[0][1];
+    x2 = s[0][0];
+
+#else
+    ROUNDS(x0, x1, x2, x3, x4);
+#endif
+
+	PUT32(x0, out     );
+	PUT32(x4, out +  4);
+	PUT32(x3, out +  8);
+	PUT32(x2, out + 12);
+
+	x0 = x1 = x2 = x3 = x4 = 0;
+}

+ 71 - 0
components/SM/src/sm4/sm4_enc_nblks.c

@@ -0,0 +1,71 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+
+#include <sm4/sm4.h>
+
+
+
+void sm4_encrypt_8blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key)
+{
+	sm4_encrypt(in, out, key);
+	sm4_encrypt(in + 16, out + 16, key);
+	sm4_encrypt(in + 16 * 2, out + 16 * 2, key);
+	sm4_encrypt(in + 16 * 3, out + 16 * 3, key);
+	sm4_encrypt(in + 16 * 4, out + 16 * 4, key);
+	sm4_encrypt(in + 16 * 5, out + 16 * 5, key);
+	sm4_encrypt(in + 16 * 6, out + 16 * 6, key);
+	sm4_encrypt(in + 16 * 7, out + 16 * 7, key);
+}
+
+void sm4_encrypt_16blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key)
+{
+	sm4_encrypt_8blocks(in, out, key);
+	sm4_encrypt_8blocks(in + 16 * 8, out + 16 * 8, key);
+}

+ 47 - 0
components/SM/src/sm4/sm4_gcm.c

@@ -0,0 +1,47 @@
+/*
+ * @Author: Weijie Li 
+ * @Date: 2017-11-06 19:54:05 
+ * @Last Modified by: Weijie Li
+ * @Last Modified time: 2017-12-22 17:19:30
+ */
+
+#include <sm4/sm4.h>
+#include <openssl/modes.h>
+
+void sm4_gcm128_init(SM4_GCM128_CONTEXT *ctx, SM4_KEY *key) {
+    CRYPTO_gcm128_init(ctx, key, (block128_f)sm4_encrypt);
+}
+
+void sm4_gcm128_setiv(SM4_GCM128_CONTEXT *ctx, const unsigned char *ivec,
+                      size_t len) {
+    CRYPTO_gcm128_setiv(ctx, ivec, len);
+}
+
+int sm4_gcm128_aad(SM4_GCM128_CONTEXT *ctx, const unsigned char *aad,
+                    size_t len) {
+    return CRYPTO_gcm128_aad(ctx, aad, len);
+}
+
+int sm4_gcm128_encrypt(const unsigned char *in, unsigned char *out,
+                        size_t length, SM4_GCM128_CONTEXT *ctx, const int enc) {
+    int ret;
+    if (enc)
+        ret = CRYPTO_gcm128_encrypt(ctx, in, out, length);
+    else
+        ret = CRYPTO_gcm128_decrypt(ctx, in, out, length);
+    return ret;
+}
+
+void sm4_gcm128_tag(SM4_GCM128_CONTEXT *ctx, unsigned char *tag,
+                    size_t len) {
+    CRYPTO_gcm128_tag(ctx, tag, len);
+}
+
+int sm4_gcm128_finish(SM4_GCM128_CONTEXT *ctx, const unsigned char *tag,
+                      size_t len) {
+    return CRYPTO_gcm128_finish(ctx, tag, len);
+}
+
+void sm4_gcm128_release(SM4_GCM128_CONTEXT *ctx) {
+    CRYPTO_gcm128_release(ctx);
+}

+ 30 - 0
components/SM/src/sm4/sm4_gcmf.c

@@ -0,0 +1,30 @@
+/*
+* sm4gcmf.c
+*
+*  Created on: 2017-10-18
+*      Author: lzj
+*      Updated: Payne
+*
+*/
+
+#include <sm4/sm4.h>
+
+int sm4_gcmf_init(sm4_gcmf_context *ctx, const SM4_KEY *sm4_key) {
+	return gcmf_init(ctx, (void *)sm4_key, (block128_f)sm4_encrypt);
+}
+
+int sm4_gcmf_free(sm4_gcmf_context *ctx) {
+	return gcmf_free(ctx);
+}
+
+int sm4_gcmf_set_iv(sm4_gcmf_context *ctx, const unsigned char * iv, size_t len) {
+	return gcmf_set_iv(ctx, iv, len);
+}
+
+int sm4_gcmf_encrypt_file(sm4_gcmf_context * ctx, char *infpath, char *outfpath) {
+	return gcmf_encrypt_file(ctx, infpath, outfpath);
+}
+
+int sm4_gcmf_decrypt_file(sm4_gcmf_context * ctx, char *infpath, char *outfpath) {
+	return gcmf_decrypt_file(ctx, infpath, outfpath);
+}

+ 124 - 0
components/SM/src/sm4/sm4_lcl.h

@@ -0,0 +1,124 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#ifndef HEADER_SM4_LCL_H
+#define HEADER_SM4_LCL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint8_t  SBOX[256];
+#if 0
+extern uint32_t SBOX32L[256 * 256];
+extern uint32_t SBOX32H[256 * 256];
+#endif
+
+
+#define GET32(pc)  (					\
+	((uint32_t)(pc)[0] << 24) ^			\
+	((uint32_t)(pc)[1] << 16) ^			\
+	((uint32_t)(pc)[2] <<  8) ^			\
+	((uint32_t)(pc)[3]))
+
+#define PUT32(st, ct)					\
+	(ct)[0] = (uint8_t)((st) >> 24);		\
+	(ct)[1] = (uint8_t)((st) >> 16);		\
+	(ct)[2] = (uint8_t)((st) >>  8);		\
+	(ct)[3] = (uint8_t)(st)
+
+#define ROT32(x,i)					\
+	(((x) << i) | ((x) >> (32-i)))
+
+#define S32(A)						\
+	((SBOX[((A) >> 24)       ] << 24) ^		\
+	 (SBOX[((A) >> 16) & 0xff] << 16) ^		\
+	 (SBOX[((A) >>  8) & 0xff] <<  8) ^		\
+	 (SBOX[((A))       & 0xff]))
+
+#define ROUNDS(x0, x1, x2, x3, x4)		\
+	ROUND(x0, x1, x2, x3, x4, 0);		\
+	ROUND(x1, x2, x3, x4, x0, 1);		\
+	ROUND(x2, x3, x4, x0, x1, 2);		\
+	ROUND(x3, x4, x0, x1, x2, 3);		\
+	ROUND(x4, x0, x1, x2, x3, 4);		\
+	ROUND(x0, x1, x2, x3, x4, 5);		\
+	ROUND(x1, x2, x3, x4, x0, 6);		\
+	ROUND(x2, x3, x4, x0, x1, 7);		\
+	ROUND(x3, x4, x0, x1, x2, 8);		\
+	ROUND(x4, x0, x1, x2, x3, 9);		\
+	ROUND(x0, x1, x2, x3, x4, 10);		\
+	ROUND(x1, x2, x3, x4, x0, 11);		\
+	ROUND(x2, x3, x4, x0, x1, 12);		\
+	ROUND(x3, x4, x0, x1, x2, 13);		\
+	ROUND(x4, x0, x1, x2, x3, 14);		\
+	ROUND(x0, x1, x2, x3, x4, 15);		\
+	ROUND(x1, x2, x3, x4, x0, 16);		\
+	ROUND(x2, x3, x4, x0, x1, 17);		\
+	ROUND(x3, x4, x0, x1, x2, 18);		\
+	ROUND(x4, x0, x1, x2, x3, 19);		\
+	ROUND(x0, x1, x2, x3, x4, 20);		\
+	ROUND(x1, x2, x3, x4, x0, 21);		\
+	ROUND(x2, x3, x4, x0, x1, 22);		\
+	ROUND(x3, x4, x0, x1, x2, 23);		\
+	ROUND(x4, x0, x1, x2, x3, 24);		\
+	ROUND(x0, x1, x2, x3, x4, 25);		\
+	ROUND(x1, x2, x3, x4, x0, 26);		\
+	ROUND(x2, x3, x4, x0, x1, 27);		\
+	ROUND(x3, x4, x0, x1, x2, 28);		\
+	ROUND(x4, x0, x1, x2, x3, 29);		\
+	ROUND(x0, x1, x2, x3, x4, 30);		\
+	ROUND(x1, x2, x3, x4, x0, 31)
+
+void sm4_init_sbox32(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 58 - 0
components/SM/src/sm4/sm4_ofb.c

@@ -0,0 +1,58 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <sm4/sm4.h>
+#include <openssl/modes.h>
+
+
+void sm4_ofb128_encrypt(const unsigned char *in, unsigned char *out,
+	size_t len, const sm4_key_t *key, unsigned char *iv, int *num)
+{
+	CRYPTO_ofb128_encrypt(in, out, len, key, iv, num, (block128_f)sm4_encrypt);
+}

+ 220 - 0
components/SM/src/sm4/sm4_setkey.c

@@ -0,0 +1,220 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <sm4/sm4.h>
+#include "sm4_lcl.h"
+
+#ifdef DUMMY_ROUND
+	#include <string.h>
+	#include <stdbool.h>
+	#include <internal/ssl_random.h>
+#endif
+
+#ifdef SIMPLE_EXTERNAL_ENCODINGS
+    #include <internal/ssl_random.h>
+#endif //SIMPLE_EXTERNAL_ENCODINGS
+
+static uint32_t FK[4] = {
+	0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc,
+};
+
+static uint32_t CK[32] = {
+	0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
+	0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
+	0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
+	0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
+	0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
+	0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
+	0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
+	0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
+};
+
+#define L32_(x)					\
+	((x) ^ 					\
+	ROT32((x), 13) ^			\
+	ROT32((x), 23))
+
+#define ENC_ROUND(x0, x1, x2, x3, x4, i)	\
+	x4 = x1 ^ x2 ^ x3 ^ *(CK + i);		\
+	x4 = S32(x4);				\
+	x4 = x0 ^ L32_(x4);			\
+	*(rk + i) = x4
+
+#define DEC_ROUND(x0, x1, x2, x3, x4, i)	\
+	x4 = x1 ^ x2 ^ x3 ^ *(CK + i);		\
+	x4 = S32(x4);				\
+	x4 = x0 ^ L32_(x4);			\
+	*(rk + 31 - i) = x4
+
+#ifdef DUMMY_ROUND
+#define ENC_DUMMY_ROUND(x0, x1, x2, x3, x4, i)	\
+	x4 = x1 ^ x2 ^ x3 ^ *(dummyKey + i);		\
+	x4 = S32(x4);				\
+	x4 = x0 ^ L32_(x4);
+#endif
+
+void sm4_set_encrypt_key(sm4_key_t *key, const unsigned char *user_key)
+{
+
+	uint32_t *rk = key->rk;
+	uint32_t x0, x1, x2, x3, x4;
+    int _i;
+    u8 et[256];
+
+	x0 = GET32(user_key     ) ^ FK[0];
+	x1 = GET32(user_key  + 4) ^ FK[1];
+	x2 = GET32(user_key  + 8) ^ FK[2];
+	x3 = GET32(user_key + 12) ^ FK[3];
+
+#ifdef SIMPLE_EXTERNAL_ENCODINGS
+    
+    for (_i = 0; _i < 256; _i++) {
+        key->G[1][_i] = key->F[SM4_NUM_ROUNDS][_i] = et[_i] = _i;
+        key->F[0][_i] = _i;
+    }
+    
+    for (_i = 1; _i < SM4_NUM_ROUNDS; _i++) {
+        int _j;
+        ssl_random_shuffle_u8(et, 256);
+        memcpy(key->F[_i], et, 256);
+        for (_j = 0; _j < 256; _j++) {
+            key->G[_i+1][ key->F[_i][_j] ] = _j;
+        }
+    }
+#endif //SIMPLE_EXTERNAL_ENCODINGS
+
+
+#ifndef DUMMY_ROUND
+    
+    #define ROUND ENC_ROUND
+	ROUNDS(x0, x1, x2, x3, x4);
+
+	x0 = x1 = x2 = x3 = x4 = 0;
+#else 
+
+#define ROUND ENC_DUMMY_ROUND
+	int r = 1;
+    uint32_t s[2][5];
+
+ 	// 0xf31a34ed, 0xb7b4cc7c, 0xfba9f4bf, 0x5e89d810, 0xf31a34ed, 0xb7b4cc7c, 0xfba9f4bf, 0x5e89d810,
+	// xor                                 0x1294e0d3, 0x563a1842, 0x1a272081, 0xbf070c2e
+	// k0                                  0x63e591a2, 0x274b6933, 0x6b5651f0, 0xce767d5f
+	// final 0x71717171
+    const uint32_t beta[4] = {0xf31a34ed, 0xb7b4cc7c, 0xfba9f4bf, 0x5e89d810};
+    const uint32_t k0[4] = {0x63e591a2, 0x274b6933, 0x6b5651f0, 0xce767d5f};
+
+    memcpy(s[1], beta, 4*sizeof(uint32_t));
+
+    uint32_t dummyKey[SM4_NUM_ROUNDS+4];
+
+    memcpy(dummyKey+4, CK, SM4_NUM_ROUNDS*sizeof(uint32_t));
+    memcpy(dummyKey, k0, 4*sizeof(uint32_t));
+
+    s[0][0] = x0;
+    s[0][1] = x1;
+    s[0][2] = x2;
+    s[0][3] = x3;
+
+    int sm4_rounds = SM4_NUM_ROUNDS/4;
+
+
+	enum _CONST_INT{
+        E_RANDOM_NUMS = 100
+    };
+    
+    int random_list[E_RANDOM_NUMS];
+    
+    int rcnt = E_RANDOM_NUMS;
+
+    while(r <= sm4_rounds ) {
+
+        if (rcnt >= E_RANDOM_NUMS)  {
+            l_random_list(NULL, random_list, E_RANDOM_NUMS);
+            rcnt = 0;
+        }   
+        bool lambda  = ((random_list[rcnt++] %2)==1);  
+
+        int kai = lambda*r;
+        int tlambda = !lambda;  //turn lambda
+        ROUND(s[tlambda][0], s[tlambda][1], s[tlambda][2], s[tlambda][3], s[tlambda][4], 4*kai + 0);
+        ROUND(s[tlambda][1], s[tlambda][2], s[tlambda][3], s[tlambda][4], s[tlambda][0], 4*kai + 1);
+        ROUND(s[tlambda][2], s[tlambda][3], s[tlambda][4], s[tlambda][0], s[tlambda][1], 4*kai + 2);
+        ROUND(s[tlambda][3], s[tlambda][4], s[tlambda][0], s[tlambda][1], s[tlambda][2], 4*kai + 3);
+
+        s[tlambda][3] = s[tlambda][2];
+        s[tlambda][2] = s[tlambda][1];
+        s[tlambda][1] = s[tlambda][0];
+        s[tlambda][0] = s[tlambda][4];
+
+        rk[4*r - 4] = s[0][0] = s[0][0] ^ s[1][0] ^ beta[0];
+        rk[4*r - 3] = s[0][1] = s[0][1] ^ s[1][1] ^ beta[1];
+        rk[4*r - 2] = s[0][2] = s[0][2] ^ s[1][2] ^ beta[2];
+        rk[4*r - 1] = s[0][3] = s[0][3] ^ s[1][3] ^ beta[3];
+
+        r = r + lambda;
+    }
+#endif   // end of DUMMY_ROUND
+}
+
+void sm4_set_decrypt_key(sm4_key_t *key, const unsigned char *user_key)
+{
+	uint32_t *rk = key->rk;
+	uint32_t x0, x1, x2, x3, x4;
+
+	x0 = GET32(user_key     ) ^ FK[0];
+	x1 = GET32(user_key  + 4) ^ FK[1];
+	x2 = GET32(user_key  + 8) ^ FK[2];
+	x3 = GET32(user_key + 12) ^ FK[3];
+
+#undef ROUND
+#define ROUND DEC_ROUND
+	ROUNDS(x0, x1, x2, x3, x4);
+
+	x0 = x1 = x2 = x3 = x4 = 0;
+}

+ 91 - 0
components/SM/src/sm4/sm4_wrap.c

@@ -0,0 +1,91 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <sm4/sm4.h>
+#include <openssl/modes.h>
+
+/** Wrapping according to RFC 3394 section 2.2.1.
+ *
+ *  @param[in]  key    Key value.
+ *  @param[in]  iv     IV value. Length = 8 bytes. NULL = use default_iv.
+ *  @param[in]  in     Plaintext as n 64-bit blocks, n >= 2.
+ *  @param[in]  inlen  Length of in.
+ *  @param[out] out    Ciphertext. Minimal buffer length = (inlen + 8) bytes.
+ *                     Input and output buffers can overlap if block function
+ *                     supports that.
+ *  @return            0 if inlen does not consist of n 64-bit blocks, n >= 2.
+ *                     or if inlen > CRYPTO128_WRAP_MAX.
+ *                     Output length if wrapping succeeded.
+ */
+int sm4_wrap_key(sm4_key_t *key, const unsigned char *iv,
+	unsigned char *out, const unsigned char *in, unsigned int inlen)
+{
+	return CRYPTO_128_wrap(key, iv, out, in, inlen, (block128_f)sm4_encrypt);
+}
+
+/** Unwrapping according to RFC 3394 section 2.2.2 steps 1-2.
+ *  The IV check (step 3) is responsibility of the caller.
+ *
+ *  @param[in]  key    Key value.
+ *  @param[out] iv     Unchecked IV value. Minimal buffer length = 8 bytes.
+ *  @param[out] out    Plaintext without IV.
+ *                     Minimal buffer length = (inlen - 8) bytes.
+ *                     Input and output buffers can overlap if block function
+ *                     supports that.
+ *  @param[in]  in     Ciphertext as n 64-bit blocks.
+ *  @param[in]  inlen  Length of in.
+ *  @return            0 if inlen is out of range [24, CRYPTO128_WRAP_MAX]
+ *                     or if inlen is not a multiple of 8.
+ *                     Output length otherwise.
+ */
+int sm4_unwrap_key(sm4_key_t *key, const unsigned char *iv,
+	unsigned char *out, const unsigned char *in, unsigned int inlen)
+{
+	return CRYPTO_128_unwrap(key, iv, out, in, inlen, (block128_f)sm4_encrypt);
+}

+ 85 - 0
components/SM/src/sm4/sm4speed.c.bak

@@ -0,0 +1,85 @@
+/* ====================================================================
+ * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the GmSSL Project.
+ *    (http://gmssl.org/)"
+ *
+ * 4. The name "GmSSL Project" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact
+ *    guanzhi1980@gmail.com.
+ *
+ * 5. Products derived from this software may not be called "GmSSL"
+ *    nor may "GmSSL" appear in their names without prior written
+ *    permission of the GmSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the GmSSL Project
+ *    (http://gmssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <openmp.h>
+#include <AisinoSSL/sm4/sm4.h>
+
+
+int main(int argc, char **argv)
+{
+	sm4_key_t sm4_key;
+	unsigned char user_key[16] = {
+		0x11,  0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+		0x11,  0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+	};
+	size_t buflen = SM4_BLOCK_SIZE * 8 * 3 * 1000 * 1000;
+	unsigned char *buf = NULL;
+	unsigned char *p;
+	int i;
+
+
+	if (!(buf = (unsigned char *)malloc(buflen))) {
+		fprintf(stderr, "malloc failed\n");
+		return -1;
+	}
+
+	sm4_set_encrypt_key(&sm4_key, user_key);
+
+	#pragma omp parallel for
+	for (i = 0, p = buf; i < buflen/(SM4_BLOCK_SIZE * 16); i++, p += SM4_BLOCK_SIZE * 16) {
+		sm4_encrypt_16blocks(&sm4_key, p, p);
+	}
+
+	return 0;
+}

+ 1 - 1
components/mbedtls/include/mbedtls/config.h

@@ -37,7 +37,7 @@
  * This section sets system specific settings.
  * \{
  */
-
+#define ECP_DP_SM2_256V1_ENABLED
 /**
  * \def MBEDTLS_HAVE_ASM
  *

+ 3 - 1
components/mbedtls/include/mbedtls/ecp.h

@@ -81,7 +81,8 @@
     defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || \
     defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \
     defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \
-    defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
+    defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) || \
+    defined(ECP_DP_SM2_256V1_ENABLED)
 #define MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED
 #endif
 #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || \
@@ -133,6 +134,7 @@ typedef enum
     MBEDTLS_ECP_DP_SECP224K1,      /*!< Domain parameters for 224-bit "Koblitz" curve. */
     MBEDTLS_ECP_DP_SECP256K1,      /*!< Domain parameters for 256-bit "Koblitz" curve. */
     MBEDTLS_ECP_DP_CURVE448,       /*!< Domain parameters for Curve448. */
+    ECP_DP_SM2_256V1,           /*SM2 256*/
 } mbedtls_ecp_group_id;
 
 /**

+ 3 - 0
components/mbedtls/library/ecp.c

@@ -542,6 +542,9 @@ static const mbedtls_ecp_curve_info ecp_supported_curves[] =
 #if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
     { MBEDTLS_ECP_DP_CURVE448,     30,     448,    "x448"              },
 #endif
+//#if defined(ECP_DP_SM2_256V1_ENABLED)
+    {ECP_DP_SM2_256V1,              2,     256,    "sm2_256v1"         },
+//#endif
     { MBEDTLS_ECP_DP_NONE,          0,     0,      NULL                },
 };
 

+ 61 - 4
components/mbedtls/library/ecp_curves.c

@@ -515,6 +515,56 @@ static const mbedtls_mpi_uint brainpoolP512r1_n[] = {
 };
 #endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */
 
+/* sm2 */
+//#if defined(ECP_DP_SM2_256V1_ENABLED)
+
+static const mbedtls_mpi_uint sm2_256v1_p[] = {
+    MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF),
+    MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
+    MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF),
+
+};
+
+/* a */
+static const mbedtls_mpi_uint sm2_256v1_a[] = {
+    MBEDTLS_BYTES_TO_T_UINT_8(0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF),
+    MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
+    MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF),
+};
+
+/* b */
+static const mbedtls_mpi_uint sm2_256v1_b[] = {
+    MBEDTLS_BYTES_TO_T_UINT_8(0x93, 0x0E, 0x94, 0x4D, 0x41, 0xBD, 0xBC, 0xDD),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x92, 0x8F, 0xAB, 0x15, 0xF5, 0x89, 0x97, 0xF3),
+    MBEDTLS_BYTES_TO_T_UINT_8(0xA7, 0x09, 0x65, 0xCF, 0x4B, 0x9E, 0x5A, 0x4D),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x34, 0x5E, 0x9F, 0x9D, 0x9E, 0xFA, 0xE9, 0x28),
+};
+/* x */
+static const mbedtls_mpi_uint sm2_256v1_gx[] = {
+    MBEDTLS_BYTES_TO_T_UINT_8(0xC7, 0x74, 0x4C, 0x33, 0x89, 0x45, 0x5A, 0x71),
+    MBEDTLS_BYTES_TO_T_UINT_8(0xE1, 0x0B, 0x66, 0xF2, 0xBF, 0x0B, 0xE3, 0x8F),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x94, 0xC9, 0x39, 0x6A, 0x46, 0x04, 0x99, 0x5F),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x19, 0x81, 0x19, 0x1F, 0x2C, 0xAE, 0xC4, 0x32),
+};
+/* y */
+static const mbedtls_mpi_uint sm2_256v1_gy[] = {
+    MBEDTLS_BYTES_TO_T_UINT_8(0xA0, 0xF0, 0x39, 0x21, 0xE5, 0x32, 0xDF, 0x02),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x40, 0x47, 0x2A, 0xC6, 0x7C, 0x87, 0xA9, 0xD0),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x53, 0x21, 0x69, 0x6B, 0xE3, 0xCE, 0xBD, 0x59),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x9C, 0x77, 0xF6, 0xF4, 0xA2, 0x36, 0x37, 0xBC),
+};
+/* n */
+static const mbedtls_mpi_uint sm2_256v1_n[] = {
+    MBEDTLS_BYTES_TO_T_UINT_8(0x23, 0x41, 0xD5, 0x39, 0x09, 0xF4, 0xBB, 0x53),
+    MBEDTLS_BYTES_TO_T_UINT_8(0x2B, 0x05, 0xC6, 0x21, 0x6B, 0xDF, 0x03, 0x72),
+    MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF),
+    MBEDTLS_BYTES_TO_T_UINT_8(0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF),
+};
+
+//#endif  /*end sm2 */
+
 #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) ||   \
     defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) ||   \
     defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ||   \
@@ -525,7 +575,8 @@ static const mbedtls_mpi_uint brainpoolP512r1_n[] = {
     defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)   ||   \
     defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) ||   \
     defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) ||   \
-    defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
+    defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ||   \
+    defined(ECP_DP_SM2_256V1_ENABLED)
 /* For these curves, we build the group parameters dynamically. */
 #define ECP_LOAD_GROUP
 #endif
@@ -831,6 +882,11 @@ int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id )
             return( ecp_use_curve448( grp ) );
 #endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */
 
+//#if defined(ECP_DP_SM2_256V1_ENABLED)
+        case ECP_DP_SM2_256V1:
+            //todo
+            return (LOAD_GROUP_A(sm2_256v1));
+//#endif
         default:
             grp->id = MBEDTLS_ECP_DP_NONE;
             return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
@@ -1337,9 +1393,10 @@ cleanup:
 }
 #endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */
 
-#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) ||   \
-    defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) ||   \
-    defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
+#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \
+    defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \
+    defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)  || \
+    defined(ECP_DP_SM2_256V1_ENABLED)
 /*
  * Fast quasi-reduction modulo P = 2^s - R,
  * with R about 33 bits, used by the Koblitz curves.

+ 59 - 0
demo/sm/main.lua

@@ -0,0 +1,59 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "smdemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+sys.taskInit(function()
+
+    sys.wait(3000)
+    log.info("sm", "start")
+
+    local originStr = "encryption standard"
+    local pkx = "191BFF8148006EEA72D857CB974DB9F4903B3CA3655D8D597AD4663F5044DCB1"
+    local pky = "E2F7888AF1FCD8C653A8059CD2F379855389F71A7709E2C1EE1E914C855EF119"
+    local private = "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0"
+    local rand = "4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F"
+    local encodeStr = sm.sm2encrypt(pkx,pky,rand,originStr,private)
+    print(originStr,"encrypt",string.toHex(encodeStr))
+    log.info("testsm.sm2decrypt",sm.sm2decrypt(private,encodeStr,pkx,pky))
+
+    encodeStr = sm.sm3update("lqlq666lqlq946")
+    log.info("testsm.sm3update",string.toHex(encodeStr))
+
+    originStr = "AES128 ECB ZeroPadding test"
+    --加密模式:ECB;填充方式:ZeroPadding;密钥:1234567890123456;密钥长度:128 bit
+    encodeStr = sm.sm4encrypt("ECB","ZERO",originStr,"1234567890123456")
+    print(originStr,"encrypt",string.toHex(encodeStr))
+    log.info("testsm.sm4decrypt",sm.sm4decrypt("ECB","ZERO",encodeStr,"1234567890123456"))
+
+    originStr = "AES128 ECB Pkcs5Padding test"
+    --加密模式:ECB;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:128 bit
+    encodeStr = sm.sm4encrypt("ECB","PKCS5",originStr,"1234567890123456")
+    print(originStr,"encrypt",string.toHex(encodeStr))
+    log.info("testsm.sm4decrypt",sm.sm4decrypt("ECB","PKCS5",encodeStr,"1234567890123456"))
+
+    originStr = "AES256 CBC Pkcs5Padding test"
+    --加密模式:CBC;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:256 bit;偏移量:1234567890666666
+    encodeStr = sm.sm4encrypt("CBC","PKCS5",originStr,"1234567890123456","1234567890666666")
+    print(originStr,"encrypt",string.toHex(encodeStr))
+    log.info("testsm.sm4decrypt",sm.sm4decrypt("CBC","PKCS5",encodeStr,"1234567890123456","1234567890666666"))
+
+    log.info("sm", "ALL Done")
+    sys.wait(100000)
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 1 - 0
luat/include/luat_libs.h

@@ -57,6 +57,7 @@ LUAMOD_API int luaopen_pack( lua_State *L );
 LUAMOD_API int luaopen_mqttcore( lua_State *L );
 /** crypto库*/
 LUAMOD_API int luaopen_crypto( lua_State *L );
+LUAMOD_API int luaopen_sm( lua_State *L );
 /** 功耗调整 */
 LUAMOD_API int luaopen_pm( lua_State *L);
 LUAMOD_API int luaopen_m2m( lua_State *L);

+ 479 - 0
luat/modules/luat_lib_sm.c

@@ -0,0 +1,479 @@
+
+/*
+@module  sm
+@summary 国密算法
+@version 1.0
+@date    2020.07.03
+@demo sm
+@tag LUAT_USE_SM
+*/
+#include "luat_base.h"
+#include "luat_malloc.h"
+#include "luat_str.h"
+#include <time.h>
+#include "luat_zbuff.h"
+#include "sm2.h"
+#include "sm3.h"
+#include "sm4.h"
+
+#define LUAT_LOG_TAG "sm"
+#include "luat_log.h"
+#define SM3_DIGEST_LENGTH    32
+#define SM4_BLOCK_LEN 16
+#define SM2_STR_LEN 300
+#define HEX_CODE 16
+
+static int myrand(void *ctx, unsigned char *msg, size_t size)
+{
+	mbedtls_mpi k;
+	mbedtls_mpi_init(&k);
+	mbedtls_mpi_read_string(&k, HEX_CODE,
+							ctx);
+	mbedtls_mpi_write_binary(&k, msg, size);
+	mbedtls_mpi_free(&k);
+	return 0;
+}
+
+static void DeletePaddingBuf(luaL_Buffer *B, uint8_t *pPadding, size_t nBufLen, uint8_t *pBuf, uint8_t pPaddLen)
+{
+    uint8_t nPadLen;
+    if((strcmp(pPadding, "PKCS5")==0) || (strcmp(pPadding, "PKCS7")==0))
+    {
+        nPadLen = *(pBuf+nBufLen-1);
+        //printf("aes DeletePaddingBuf length=%d\n", nPadLen);
+        if((pPaddLen-nPadLen) >= 0)
+        {
+            luaL_addlstring(B, pBuf, nBufLen-nPadLen);
+        }
+    }
+    else if(strcmp(pPadding, "ZERO")==0)
+    {                        
+        uint8_t *pEnd = pBuf+nBufLen-1;
+        nPadLen = 0;
+        while(1)
+        {
+            if(*pEnd == 0)
+            {
+                nPadLen++;
+                if(nPadLen == pPaddLen)
+                {
+                    break;
+                }
+                pEnd--;
+            }
+            else
+            {
+                break;
+            }
+        }
+        //printf("aes DeletePaddingBuf length=%d\n", nPadLen);
+        if((pPaddLen-nPadLen) >= 0)
+        {
+            luaL_addlstring(B, pBuf, nBufLen-nPadLen);
+        }
+    }
+    else
+    {
+        luaL_addlstring(B, pBuf, nBufLen);
+    }
+}
+
+
+/*
+sm2算法加密
+@api sm.sm2encrypt(pkx,pky,rand,data)
+@string 公钥x,必选
+@string 公钥y,必选
+@string 随机数,必选
+@string 待计算的数据,必选
+@return 
+@usage
+local originStr = "encryption standard"
+local pkx = "435B39CCA8F3B508C1488AFC67BE491A0F7BA07E581A0E4849A5CF70628A7E0A"
+local pky = "75DDBA78F15FEECB4C7895E2C1CDF5FE01DEBB2CDBADF45399CCF77BBA076A42"
+local private = "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0"
+local rand = "4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F"
+local encodeStr = sm.sm2encrypt(pkx,pky,rand,originStr)
+print(originStr,"encrypt",string.toHex(encodeStr))
+log.info("testsm.sm2decrypt",sm.sm2decrypt(private,encodeStr))
+*/
+static int l_sm2_encrypt(lua_State *L)
+{    
+    size_t randLen = 0;
+    size_t pkxLen = 0;
+    size_t pkyLen = 0;
+    size_t pBufLen = 0;
+    uint8_t *pkx = lua_tolstring(L, 1,&pkxLen);
+    uint8_t *pky = lua_tolstring(L, 2,&pkyLen);
+    uint8_t *rand = lua_tolstring(L, 3,&randLen);
+    uint8_t *pBuf = lua_tolstring(L, 4,&pBufLen);
+
+    //检查参数合法性
+    if((pkxLen!=64))
+    {
+        return luaL_error(L, "invalid pkx password length=%d", pkxLen);
+    }
+    if((pkyLen!=64))
+    {
+        return luaL_error(L, "invalid pky password length=%d", pkyLen);
+    }
+    if((randLen!=64))
+    {
+        return luaL_error(L, "invalid rand length=%d", randLen);
+    }
+    
+    unsigned char *out = calloc(SM2_STR_LEN, sizeof(unsigned char));
+    int ret = 0;
+    size_t olen = 0;
+    sm2_context sm2;
+	sm2_init(&sm2);
+
+    //set key
+	sm2_read_string_public(&sm2, pkx, pky);
+
+    ret = sm2_do_encrypt(&sm2, (const unsigned char *)pBuf, pBufLen, out, SM2_STR_LEN, &olen,
+							 myrand, rand);
+
+    luaL_Buffer b;
+    luaL_buffinit( L, &b );                         
+    luaL_addlstring(&b, out, olen);
+    luaL_pushresult( &b );
+
+    sm2_free(&sm2);
+    free(out);
+    return 1;
+}
+
+/*
+sm2算法解密
+@api sm.sm2decrypt(private,data)
+@string 私钥,必选
+@string 待计算的数据,必选
+@return 
+@usage
+local originStr = "encryption standard"
+local pkx = "435B39CCA8F3B508C1488AFC67BE491A0F7BA07E581A0E4849A5CF70628A7E0A"
+local pky = "75DDBA78F15FEECB4C7895E2C1CDF5FE01DEBB2CDBADF45399CCF77BBA076A42"
+local private = "1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0"
+local rand = "4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F"
+local encodeStr = sm.sm2encrypt(pkx,pky,rand,originStr)
+print(originStr,"encrypt",string.toHex(encodeStr))
+log.info("testsm.sm2decrypt",sm.sm2decrypt(private,encodeStr))
+*/
+static int l_sm2_decrypt(lua_State *L)
+{    
+    size_t privateLen = 0;
+    size_t pBufLen = 0;
+    uint8_t *private = lua_tolstring(L, 1,&privateLen);
+    uint8_t *pBuf = lua_tolstring(L, 2,&pBufLen);
+
+    //检查参数合法性
+    if((privateLen!=64))
+    {
+        return luaL_error(L, "invalid private password length=%d", privateLen);
+    }
+    
+    unsigned char *out = calloc(SM2_STR_LEN, sizeof(unsigned char));
+    int ret = 0;
+    size_t olen = 0;
+    sm2_context sm2;
+	sm2_init(&sm2);
+
+    //set key
+    sm2_read_string_private(&sm2, private);
+
+    ret = sm2_do_decrypt(&sm2, pBuf, pBufLen, out, SM2_STR_LEN, &olen);
+
+    luaL_Buffer b;
+    luaL_buffinit( L, &b );                         
+    luaL_addlstring(&b, out, olen);
+    luaL_pushresult( &b );
+
+    sm2_free(&sm2);
+    free(out);
+    return 1;
+}
+
+/*
+流式sm3算法加密
+@api sm.sm3update(data)
+@string 待计算的数据,必选
+@return 
+@usage
+local encodeStr = sm.sm3update("lqlq666lqlq946")
+log.info("testsm.sm3update",string.toHex(encodeStr))
+*/
+static int l_sm3_update(lua_State *L)
+{
+    sm3_context ctx;
+    size_t inputLen;
+    uint8_t out[SM3_DIGEST_LENGTH];
+	uint32_t i = 0;
+    luaL_Buffer b;
+    luaL_buffinit(L, &b);  
+
+    const char *inputData = lua_tolstring(L,1,&inputLen);
+    sm3_init(&ctx);
+    sm3_starts(&ctx);
+    sm3_update(&ctx,(unsigned char *)inputData, inputLen);
+    memset(out, 0, SM3_DIGEST_LENGTH);   
+    sm3_finish(&ctx, out);
+    sm3_free(&ctx);
+
+    luaL_addlstring(&b, out, SM3_DIGEST_LENGTH);
+    luaL_pushresult(&b);
+    
+    return 1;
+}
+
+/*
+SM4加密算法
+@api sm.sm4encrypt(mode,padding,originStr,password)
+@number  加密模式   
+@number  填充方式 
+@string  加密的字符串
+@string  密钥
+@return string 加密后的数据
+@usage
+local originStr = "AES128 ECB ZeroPadding test"
+--加密模式:ECB;填充方式:ZeroPadding;密钥:1234567890123456;密钥长度:128 bit
+local encodeStr = sm.sm4encrypt("ECB","ZERO",originStr,"1234567890123456")
+print(originStr,"encrypt",string.toHex(encodeStr))
+log.info("testsm.decrypt",sm.sm4decrypt("ECB","ZERO",encodeStr,"1234567890123456"))
+
+originStr = "AES128 ECB Pkcs5Padding test"
+--加密模式:ECB;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:128 bit
+encodeStr = sm.sm4encrypt("ECB","PKCS5",originStr,"1234567890123456")
+print(originStr,"encrypt",string.toHex(encodeStr))
+log.info("testsm.decrypt",sm.sm4decrypt("ECB","PKCS5",encodeStr,"1234567890123456"))
+
+originStr = "AES256 CBC Pkcs5Padding test"
+--加密模式:CBC;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:256 bit;偏移量:1234567890666666
+encodeStr = sm.sm4encrypt("CBC","PKCS5",originStr,"1234567890123456","1234567890666666")
+print(originStr,"encrypt",string.toHex(encodeStr))
+log.info("testsm.decrypt",sm.sm4decrypt("CBC","PKCS5",encodeStr,"1234567890123456","1234567890666666"))
+*/
+static int l_sm4_encrypt(lua_State *L)
+{    
+    uint8_t *pMode = luaL_checkstring(L, 1);
+    uint8_t *pPadding = luaL_checkstring(L, 2);
+    size_t nBufLen = 0;
+    uint8_t *pBuf = lua_tolstring(L, 3, &nBufLen);
+    size_t nPswdLen = 0;
+    uint8_t *pPassword = lua_tolstring(L, 4, &nPswdLen);
+    size_t nIVLen = 0;
+    uint8_t *pIV =  lua_tolstring(L, 5, &nIVLen);
+
+    int nPadLen = SM4_BLOCK_LEN-(nBufLen%SM4_BLOCK_LEN);
+    uint8_t pPadBuf[SM4_BLOCK_LEN] = {0};
+    uint8_t *pInBuf = NULL;
+	
+    //检查参数合法性
+    if((nPswdLen!=16))
+    {
+        return luaL_error(L, "invalid password length=%d, only support AES128,AES192,AES256", nPswdLen);
+    }
+    if((strcmp(pMode, "ECB")!=0) && (strcmp(pMode, "CBC")!=0))
+    {
+        return luaL_error(L, "invalid mode=%s, only support ECB,CBC,CTR", pMode);
+    }
+    if((strcmp(pPadding, "NONE")!=0) && (strcmp(pPadding, "PKCS5")!=0) && (strcmp(pPadding, "PKCS7")!=0) && (strcmp(pPadding, "ZERO")!=0))
+    {
+        return luaL_error(L, "invalid padding=%s, only support NONE,PKCS5,PKCS7,ZERO", pPadding);
+    }
+    if(((strcmp(pMode, "CBC")==0)) && (nIVLen!=16))
+    {
+        return luaL_error(L, "invalid iv length=%d, only support 16", nIVLen);
+    }
+
+    //构造填充数据
+    if((strcmp(pPadding, "PKCS5")==0) || (strcmp(pPadding, "PKCS7")==0))
+    {
+        memset(pPadBuf, nPadLen, sizeof(pPadBuf));
+    }
+    else if(strcmp(pPadding, "ZERO")==0)
+    {
+        memset(pPadBuf, 0, sizeof(pPadBuf));
+    }   
+	else if(strcmp(pPadding, "NONE")==0)
+    {
+    	if((strcmp(pMode, "CBC")==0) || (strcmp(pMode, "ECB")==0)){
+	        if(nBufLen%SM4_BLOCK_LEN != 0)
+	        {
+	            return luaL_error(L, "buf len should be multiple of 16, len=%d", nBufLen);
+	        }
+        }
+        nPadLen = 0;
+    }
+
+    //加密
+    {       
+        luaL_Buffer b;
+        uint32_t nRmnLen;
+        luaL_buffinit( L, &b );
+
+         //原始数据和填充数据拼接在一起
+        if (strcmp(pPadding, "NONE")!=0)
+        {
+            pInBuf = malloc(nBufLen+nPadLen);
+            if(pInBuf == NULL)
+            {
+                //LLOGD("aes_encrypt malloc error!!!\n");
+                luaL_pushresult( &b );
+                return 1;
+            }
+            memcpy(pInBuf, pBuf, nBufLen);
+            memcpy(pInBuf+nBufLen, pPadBuf, nPadLen); 
+            nBufLen += nPadLen;
+            nRmnLen = nBufLen;
+        }
+        else
+        {
+            pInBuf =  malloc(nBufLen);
+			nRmnLen = nBufLen;
+            if(pInBuf == NULL)
+            {
+                //LLOGD("aes_encrypt malloc error!!!\n");
+                luaL_pushresult( &b );
+                return 1;
+            }
+            memcpy(pInBuf, pBuf, nBufLen);
+        }
+
+		SM4_KEY sm4_key;
+        memset(&sm4_key,0,sizeof(SM4_KEY));
+		sm4_set_encrypt_key(&sm4_key,pPassword);
+
+        if(strcmp(pMode, "ECB") == 0)
+        {
+            //开始分组加密,每16字节一组
+            while(nRmnLen>0)
+            {
+                sm4_ecb_encrypt(pInBuf+nBufLen-nRmnLen,pInBuf+nBufLen-nRmnLen,&sm4_key,1);	
+                luaL_addlstring(&b, pInBuf+nBufLen-nRmnLen, SM4_BLOCK_LEN);
+                nRmnLen -= SM4_BLOCK_LEN;
+            }
+        }
+        else if((strcmp(pMode, "CBC") == 0))
+        {
+            //待加密数据一次性传入
+            sm4_cbc_encrypt(pInBuf,pInBuf,nBufLen,&sm4_key,pIV,1);
+            luaL_addlstring(&b, pInBuf, nBufLen);
+        }
+
+        if(pInBuf != NULL)
+        {
+            free(pInBuf);
+            pInBuf = NULL;
+        }
+
+        luaL_pushresult( &b );
+        return 1;
+    }   
+}
+
+
+/*
+SM4解密算法
+@api sm.sm4_decrypt(mode,padding,encodeStr,password)
+@number  加密模式   
+@number  填充方式 
+@string  已加密的字符串
+@string  密钥
+@return string 解密的字符串
+@usage
+*/
+static int l_sm4_decrypt(lua_State *L)
+{    
+    
+    uint8_t *pMode = luaL_checkstring(L, 1);
+    uint8_t *pPadding = luaL_checkstring(L, 2);
+    size_t nBufLen = 0;
+    uint8_t *pBuf = lua_tolstring(L, 3, &nBufLen);
+    size_t nPswdLen = 0;
+    uint8_t *pPassword = lua_tolstring(L, 4, &nPswdLen);
+    size_t nIVLen = 0;
+    uint8_t *pIV =  lua_tolstring(L, 5, &nIVLen);
+
+    //检查参数合法性
+    if((strcmp(pMode, "CBC")==0) || (strcmp(pMode, "ECB")==0)){
+	    if((nBufLen % 16) != 0){
+			return luaL_error(L, "invalid BufLen length=%d, BufLen must be Integer multiples of 16", nBufLen);
+		}
+	}
+    if((nPswdLen!=16))
+    {
+        return luaL_error(L, "invalid password length=%d, only support AES128,AES192,AES256", nPswdLen);
+    }
+    if((strcmp(pMode, "ECB")!=0) && (strcmp(pMode, "CBC")!=0))
+    {
+        return luaL_error(L, "invalid mode=%s, only support ECB,CBC,CTR", pMode);
+    }
+    if((strcmp(pPadding, "NONE")!=0) && (strcmp(pPadding, "PKCS5")!=0) && (strcmp(pPadding, "PKCS7")!=0) && (strcmp(pPadding, "ZERO")!=0))
+    {
+        return luaL_error(L, "invalid padding=%s, only support NONE,PKCS5,PKCS7,ZERO", pPadding);
+    }
+    if(((strcmp(pMode, "CBC")==0)) && (nIVLen!=16)) 
+    {
+        return luaL_error(L, "invalid iv length=%d, only support 16", nIVLen);
+    }    
+    
+    //解密
+    {       
+        luaL_Buffer b;
+        uint32_t nRmnLen;
+        memset(b.initb,0,LUAL_BUFFERSIZE);
+        luaL_buffinit( L, &b );
+
+        nRmnLen = nBufLen;
+		SM4_KEY sm4_key;
+        memset(&sm4_key,0,sizeof(SM4_KEY));
+        sm4_set_decrypt_key(&sm4_key,pPassword);
+
+        if(strcmp(pMode, "ECB") == 0)
+        {
+            //开始分组解密,每16字节一组
+            while(nRmnLen>0)
+            {
+                sm4_ecb_encrypt(pBuf+nBufLen-nRmnLen,pBuf+nBufLen-nRmnLen,&sm4_key,0);
+                //删除填充数据
+                if(nRmnLen==SM4_BLOCK_LEN)
+                {
+                    DeletePaddingBuf(&b, pPadding, SM4_BLOCK_LEN, pBuf+nBufLen-nRmnLen, SM4_BLOCK_LEN);
+                }
+                else
+                {
+                    luaL_addlstring(&b, pBuf+nBufLen-nRmnLen, SM4_BLOCK_LEN);
+                }
+                nRmnLen -= SM4_BLOCK_LEN;
+            }
+        }
+        else if((strcmp(pMode, "CBC") == 0))
+        {
+            //待解密数据一次性传入
+            sm4_cbc_encrypt(pBuf,pBuf,nBufLen,&sm4_key,pIV,0);
+            DeletePaddingBuf(&b, pPadding, nBufLen, pBuf, SM4_BLOCK_LEN);
+        }
+		
+        luaL_pushresult( &b );
+        return 1;
+    }    
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_sm[] =
+{
+    { "sm2encrypt",      ROREG_FUNC(l_sm2_encrypt)},
+    { "sm2decrypt",      ROREG_FUNC(l_sm2_decrypt)},
+    { "sm3update",      ROREG_FUNC(l_sm3_update)},
+    { "sm4encrypt",      ROREG_FUNC(l_sm4_encrypt)},
+    { "sm4decrypt",      ROREG_FUNC(l_sm4_decrypt)},
+
+	{ NULL,             ROREG_INT(0) }
+};
+
+LUAMOD_API int luaopen_sm( lua_State *L ) {
+    luat_newlib2(L, reg_sm);
+    return 1;
+}
+

+ 3 - 0
luat/modules/luat_lib_vmx.c

@@ -68,6 +68,9 @@ static const luaL_Reg loadedlibs[] = {
 #endif
 #ifdef LUAT_USE_ADC
   {"adc",   luaopen_adc},
+#endif
+#ifdef LUAT_USE_SM
+  {"sm",   luaopen_sm},
 #endif
   {NULL, NULL}
 };