• <tr id="yyy80"></tr>
  • <sup id="yyy80"></sup>
  • <tfoot id="yyy80"><noscript id="yyy80"></noscript></tfoot>
  • 99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

    支持國產密碼算法的OpenSSL設計實現及應用

    2018-02-28 02:51:04蔡成杭
    信息安全研究 2018年2期
    關鍵詞:國密源代碼公鑰

    蔡成杭

    (北京江南天安科技有限公司 北京 100088)

    OpenSSL[1]是一套應用廣泛的、開源的支持傳輸層安全協議的密碼學基礎庫和工具集合,囊括主要的密碼算法、常用的密鑰和證書封裝管理功能及SSL/TLS協議,并提供豐富的API,以供應用系統(tǒng)集成、程序開發(fā)、測試或其他目的使用.它廣泛地集成在各種類型的操作系統(tǒng)中(Linux、BSD家族、MacOS等),即使某些操作系統(tǒng)(Windows、傳統(tǒng)的Unix等)沒有將其集成為組件,通過源代碼下載,也可以十分輕松地構建OpenSSL的開發(fā)及應用環(huán)境.

    作為基礎組件之一,OpenSSL簡潔、明了、豐富的應用接口,可簡單、便捷地構筑安全領域等方面的應用,從而深受廣大IT愛好者的喜愛.因此,基于OpenSSL的應用十分廣泛,特別是涉及到安全功能的應用系統(tǒng)和中間件,許多都是基于OpenSSL來構建的.如我們常用的SSH,Apache,Tomcat,Nginx,MySQL等知名系統(tǒng),都是依賴OpenSSL來構建其安全體系的.

    在中國,也有大量的安全領域的應用是依賴OpenSSL來構造的.但原始OpenSSL中并不包含符合中國標準的商用密碼算法(簡稱國密)和安全通信協議,構建的安全應用也不符合中國商用密碼行業(yè)標準,不利于國產密碼的推廣.因此,通過對OpenSSL的改造,讓OpenSSL支持國產密碼算法及通信協議,這是十分必要的.

    江南天安于2017年推出了天安版國密OpenSSL,將國產密碼算法及國密TLS協議[2]集成進OpenSSL中,實現了支持國產密碼認證體系以及國密TLS(以下簡稱CNTLS)協議,可替換原來基于OpenSSL的上層應用,也可在此基礎上便捷地構建符合國密標準的應用系統(tǒng).

    本文以OpenSSL的穩(wěn)定版本1.0.2h為例,詳細介紹支持國產密碼算法的OpenSSL在CentOS 6.5操作系統(tǒng)中的實現及應用.

    1 國產密碼OpenSSL的實現

    國產密碼OpenSSL除具備原始OpenSSL的功能特色外,同時兼具著以下幾點:

    1) 支持國產密碼算法,提供國產密碼算法開發(fā)和應用接口;

    2) 包含國產密碼算法的對象標識符;

    3) 支持國產密碼認證體系;

    4) 實現國密TLS協議,提供國密TLS協議的開發(fā)和應用接口;

    5) 支持以引擎或內置的方式,實現需硬件支持的國產密碼算法,如:SM1,SSF33等.

    1.1 國產密碼OpenSSL的系統(tǒng)架構

    國產密碼OpenSSL的系統(tǒng)架構如圖1所示,可粗略分為:基礎函數庫、EVP密碼算法封裝接口庫、X509/PKCS認證接口庫、SSL/TLS/CNTLS協議接口庫、應用及開發(fā)接口等.

    圖1 國產密碼OpenSSL系統(tǒng)架構及依賴關系圖

    圖1中,基礎函數庫包括:國際對稱加密算法、信息摘要算法、公開密鑰算法的軟實現;國產對稱加密算法SM4[3]、信息摘要算法SM3[4]、公開密鑰算法SM2[5](可視為橢圓曲線公鑰算法[6]的一條特定曲線)的軟實現;硬件加速或實現引擎接口;錯誤處理接口;BIO抽象輸入/輸出接口;數據結構等等.

    EVP密碼算法封裝接口庫包括:對國際密碼算法、國產密碼算法、硬件實現算法的統(tǒng)一調用接口,它依賴于基礎函數庫,同時也提供信息摘要、自動完成公鑰算法的數字簽名和驗證以及數字信封等等接口,供X509/PKCS,SSL/TLS/CNTLS接口庫調用.

    X509/PKCS接口庫:X509或PKCS認證體系的標準接口庫,此接口庫需支持國密碼認證體系.

    SSL/TLS/CNTLS接口庫:提供SSL/TLS/標準接口,同時添加支持CNTLS的API及支持雙證書體系(目前只支持RSA和SM2的雙證書)的接口API.

    1.2 國產密碼算法對象標識的集成

    國產密碼算法對象標識[7]簡稱國密OID,用來在OpenSSL及標準的X509/PKCS認證體系中標識國產密碼算法及國產密碼算法的使用方式.

    在原始的OpenSSL中集成國產密碼算法對象標識,需要在OpenSSL的原代碼中作如下修改:

    1) 編輯OpenSSL源代碼目錄crypto/objects中的objects.txt文件,并在其尾部添加如下數行:

    1 2 156 10197 1:SM-SCHEME:sm-scheme

    sm-scheme 102 :SM1:sm1

    :SM1-CBC:sm1-cbc

    :SM1-ECB:sm1-ecb

    :SM1-CFB:sm1-cfb

    :SM1-OFB:sm1-ofb

    sm-scheme 103 :SSF33:ssf33

    :SSF33-CBC:ssf33-cbc

    :SSF33-ECB:ssf33-ecb

    :SSF33-CFB:ssf33-cfb

    :SSF33-OFB:ssf33-ofb

    sm-scheme 104 :SM4:sm4

    :SM4-CBC:sm4-cbc

    :SM4-ECB:sm4-ecb

    :SM4-CFB:sm4-cfb

    :SM4-OFB:sm4-ofb

    sm-scheme 201 :ZUC:zuc

    :EEA3-128:eea3-128

    :EIA3-128:eia3-128

    sm-scheme 301 :SM2:sm2

    sm2 1 :sm2signature

    sm2 2 :sm2keyagreement

    sm2 3 :sm2encrypt

    sm-scheme 401 :SM3:sm3

    sm3 1 :SM3-DIGEST:sm3-digest

    sm3 2 :HMAC-SM3:hmac-sm3

    sm-scheme 501:SM2-SM3:sm3WithSM2Sign

    sm-scheme 504:RSA-SM3:sm3WithRSAEncryption

    sm-scheme 504:RSA-SM3-2:sm3WithRSA

    2) 編輯OpenSSL源代碼目錄crypto/objects中的obj_xref.txt文件,并在其尾部添加如下數行:

    sm3WithRSAEncryption sm3 rsaEncryption

    sm3WithRSA sm3 rsa

    sm3WithSM2Sign sm3 X9_62_id_ecPublicKey

    3) 進入OpenSSL源代碼目錄crypto/objects,依次執(zhí)行如下2條命令:

    perl objects.pl objects.txt obj_mac.num obj_mac.h

    perl objxref.pl obj_mac.num obj_xref.txt > obj_xref.h

    這樣即可將國產密碼算法及其使用方法的對象標識添加到OpenSSL中.

    1.3 國產密碼算法的OpenSSL實現

    國產密碼算法已經公開的算法有:SM2公鑰算法、SM3信息摘要算法、SM4對稱密碼算法、祖沖之流密碼算法和SM9標識密碼算法.

    本文只介紹SM2、SM3和SM4算法的OpenSSL實現,這些算法也是目前應用最為廣泛的國產密碼算法.同時,為兼顧被大量使用的SM1和SSF33算法,實現了SM1和SSF33算法的EVP接口,以便在需要時,通過引擎的方式來使用硬件實現SM1和SSF33算法.

    1.3.1SM4算法的實現

    在國產密碼OpenSSL中,SM4對稱加密算法的實現分為基礎庫軟實現和EVP封裝接口實現2個部分.

    1.3.1.1SM4基礎庫軟實現

    SM4算法原理及FK,CK,SBOX的值請參見:GM/T 0002—2012 《SM4分組密碼算法》,這里不再贅述.

    1) 定義SM4密鑰數據結構及常量,如下:

    struct sm4_key_st

    {

    uint32_t key[32];

    };

    typedef struct sm4_key_st SM4_KEY;

    const unsigned FK[4]={…};

    const unsigned CK[32]={…};

    const unsigned char SBOX[25]={…};

    2) 定義相關的宏(也可以用函數實現)

    32 b循環(huán)位移:

    #define RSL(A, I) (((A)<<(I))|((A)>>(32-(I))))

    密鑰擴展線性變換:

    #define LCK(A) ((A)^(RSL((A), 13))^(RSL((A), 23)))

    輪密鑰生成:

    #define KERF_K(K0, K1, K2, K3, K4, CK, RK)

    K4=(K1)^(K2)^(K3)^(CK), K4=NT(K4),

    RK=K4=(K0)^LCK(K4)

    加解密線性變換:

    #define LC(A) ((A)^

    (RSL((A), 2))^(RSL((A), 10))^

    (RSL((A), 18))^(RSL((A), 24)))

    加解密非線性變換:

    #define NT(A)

    ((SBOX[((A)>>24)]<<24)|

    (SBOX[(((A)>>16) & 0xFF)]<<16)|

    (SBOX[(((A)>>8) & 0xFF)]<<8)|

    (SBOX[((A) & 0xFF)]))

    加解密輪處理:

    #define RF_E(X0, X1, X2, X3, X4, RK)

    X4=(X1)^(X2)^(X3)^(RK),

    X4=NT(X4),

    X4=(X0)^LC(X4)

    3) 實現密鑰初始化函數

    int SM4_set_key(const unsigned char*userKey, size_t length, SM4_KEY*key)

    {

    unsigned*rk=key->key;

    unsigned K[5];

    int loop;

    for (loop=0; loop<4; loop++)

    {

    K[i]=__bswap_32(*((unsigned*)

    (userKey+i*4))); /*需包含

    endian.h*/

    K[i] ^=FK[i];

    }

    for (loop=0; loop<32; loop++)

    KERF_K(K[loop %5], K[(loop+1)

    %5], K[(loop+2) %5],

    K[(loop+3) %5],K[(loop+4) %5],

    CK[loop], rk[loop]);

    return 1;

    }

    4) 實現SM4加密函數

    void SM4_encrypt(const unsigned char*in, unsigned char*out, const SM4_KEY*key)

    {

    const unsigned*rk=key->key;

    unsigned X[5];

    int loop;

    for (loop=0; loop<4; loop++)

    X[loop]=__bswap_32(*((unsigned*)

    (in+loop*4)));

    for (loop=0; loop<32; loop++)

    RF_E(X[loop %5], X[(loop+1) %5],

    X[(loop+2) %5], X[(loop+3) %5],

    X[(loop+4) %5], rk[loop]);

    for ((loop=0; loop<4; loop++)

    *((unsigned*)(out+loop*4))=

    X[loop];

    }

    5) 實現SM4解密函數

    void SM4_decrypt(const unsigned char*in, unsigned char*out, const SM4_KEY*key)

    {

    const unsigned*rk=key->key;

    unsigned X[5];

    int loop;

    for (loop=0; loop<4; loop++)

    X[loop]=__bswap_32(*((unsigned*)

    (in+loop*4)));

    for (loop=0; loop<32; loop++)

    RF_E(X[loop %5], X[(loop+1) %5],

    X[(loop+2) %5], X[(loop+3) %5],

    X[(loop+4) %5], rk[31-loop]);

    for ((loop=0; loop<4; loop++)

    *((unsigned*)(out+loop*4))=

    X[loop];

    }

    到此為止,SM4基礎軟實現已經完成.需要注意的是,在此實現的源代碼中,需要包括頭文件endian.h,否則是找不到函數__bswap_32的.

    1.3.1.2SM4EVP封裝接口實現

    SM4的EVP封裝接口需要實現4種加密模式,分別是ECB,CBC,CFB和OFB模式.其實現過程如下.

    1) 定義EVP封裝的SM4數據結構如下:

    typedef struct { SM4_KEY ks;} EVP_SM4_KEY;

    2) 實現EVP_CIPHER結構的成員函數init:

    static int sm4_init(EVP_CIPHER_CTX*ctx, const unsigned char*key, const unsigned char*iv, int enc)

    {

    EVP_SM4_KEY*dat=(EVP_SM4_KEY*)

    ctx->cipher_data;

    SM4_set_key(key, 16, &(dat->ks));

    return 1;

    }

    3) 實現EVP_CIPHER結構的成員函數do_cipher,因為要實現4種模式,因此要實現4種版的do_cipher:

    static int sm4_cbc(EVP_CIPHER_CTX*ctx, unsigned char*out, const unsigned char*in, size_t inl)

    {

    if (ctx->encrypt)

    CRYPTO_cbc128_encrypt(in,out,length,

    &((EVP_SM4_KEY*)ctx->

    cipher_data)->ks,

    ctx->iv,

    (block128_f) SM4_encrypt);

    else

    CRYPTO_cbc128_decrypt(in,out,length,

    &((EVP_SM4_KEY*)ctx->

    cipher_data)->ks,

    ctx->iv,

    (block128_f) SM4_decrypt);

    return 1;

    }

    static int sm4_ecb(EVP_CIPHER_CTX*ctx, unsigned char*out, const unsigned char*in, size_t inl)

    {

    size_t i, bl;

    bl=ctx->cipher->block_size;

    if (inl

    return 1;

    inl-=bl;

    if (ctx->encrypt)

    for (i=0; i<=inl; i+=bl)

    SM4_encrypt(in+i, out+i,

    &((EVP_SM4_KEY*)ctx->

    cipher_data)->ks);

    else

    for (i=0; i<=inl; i+=bl)

    SM4_decrypt(in+i, out+i,

    &((EVP_SM4_KEY*)ctx->

    cipher_data)->ks);

    return 1;

    }

    static int sm4_cfb(EVP_CIPHER_CTX*ctx, unsigned char*out, const unsigned char*in, size_t inl)

    {

    CRYPTO_cfb128_encrypt(in,out,inl,

    &((EVP_SM4_KEY*)ctx->

    cipher_data)->ks,

    ctx->iv,

    &ctx->num,

    ctx->encrypt,

    (block128_f) SM4_encrypt);

    return 1;

    }

    static int sm4_ofb(EVP_CIPHER_CTX*ctx, unsigned char*out, const unsigned char*in, size_t inl)

    {

    CRYPTO_ofb128_encrypt(in,out,inl,

    &((EVP_SM4_KEY*)ctx->

    cipher_data)->ks,

    ctx->iv,

    &ctx->num,

    (block128_f) SM4_encrypt);

    return 1;

    }

    4) 填充EVP_CIPHER結構,實現SM4的4種EVP封閉接口:

    static const EVP_CIPHER sm4_ecb={

    NID_sm4_ecb,

    16,16, 0, EVP_CIPH_ECB_MODE,

    sm4_init, sm4_ecb, NULL,

    sizeof(EVP_SM4_KEY),

    NULL, NULL, NULL, NULL

    };

    const EVP_CIPHER*EVP_sm4_ecb(void) { return &sm4_ecb; }

    static const EVP_CIPHER sm4_cbc={

    NID_sm4_cbc,

    16, 16, 16, EVP_CIPH_CBC_MODE,

    sm4_init, sm4_cbc, NULL,

    sizeof(EVP_SM4_KEY),

    NULL, NULL, NULL, NULL

    };

    const EVP_CIPHER*EVP_sm4_cbc(void) {return &sm4_cbc;}

    static const EVP_CIPHER sm4_cfb={

    NID_sm4_cfb,

    1, 16, 16, EVP_CIPH_CFB_MODE,

    sm4_init, sm4_cfb, NULL,

    sizeof(EVP_SM4_KEY),

    NULL, NULL, NULL, NULL

    };

    const EVP_CIPHER*EVP_sm4_cfb(void) {return &sm4_cfb;}

    static const EVP_CIPHER sm4_ofb={

    NID_sm4_ofb,

    1, 16, 16, EVP_CIPH_OFB_MODE,

    sm4_init, sm4_ofb, NULL,

    sizeof(EVP_SM4_KEY),

    NULL, NULL, NULL, NULL

    };

    const EVP_CIPHER*EVP_sm4_ofb(void) {return &sm4_ofb;}

    5) 修改OpenSSL源代碼目錄crypto/evp中的evp.h,并添加對SM4 EVP封裝接口的4種模式的定義,如下所示:

    const EVP_CIPHER*EVP_sm4_ecb(void);

    const EVP_CIPHER*EVP_sm4_cbc(void)

    const EVP_CIPHER*EVP_sm4_cfb(void)

    const EVP_CIPHER*EVP_sm4_ofb(void)

    6) 修改OpenSSL源代碼目錄crypto/evp中的c_allc.c,并將SM4 EVP封裝接口的4種模式加入到OpenSSL系統(tǒng)中去,如下所示:

    EVP_add_cipher(EVP_sm4_cbc());

    EVP_add_cipher(EVP_sm4_cfb());

    EVP_add_cipher(EVP_sm4_ecb());

    EVP_add_cipher(EVP_sm4_ofb());

    EVP_add_cipher_alias(SN_sm4_cbc, ″SM4″);

    其中,在EVP封裝的接口中,EVP_sm4_cbc作為SM4的默認算法.

    1.3.2SM1和SSF33的EVP接口

    參照SM4 EVP封裝接口的實現,實現SM1和SSF33的EVP接口,并將其中的EVP_CIPHER的成員函數init,do_cipher置NULL(空)即可.

    1.3.3SM3摘要算法的實現

    在國產密碼OpenSSL中,SM3作為信息摘要函數,也分為基礎庫軟實現和EVP封裝接口的實現.

    1.3.3.1SM3基礎庫軟實現

    SM3算法的原理請參見GM/T 0004—2012 《SM3密碼雜湊算法》.

    1) 定義SM3算法的結構如下所示:

    typedef struct SM3state_st

    {

    SM3_LONG digest[8];

    SM3_LONG Nl, Nh;

    SM3_LONG data[64];

    unsigned int num;

    } SM3_CTX;

    2) 實現SM3初始化函數如下所示:

    int SM3_Init(SM3_CTX*c)

    {

    memset(c, 0, sizeof(SM3_CTX));

    c->digest[0]=0x7380166F;

    c->digest[1]=0x4914B2B9;

    c->digest[2]=0x172442D7;

    c->digest[3]=0xDA8A0600;

    c->digest[4]=0xA96F30BC;

    c->digest[5]=0x163138AA;

    c->digest[6]=0xE38DEE4D;

    c->digest[7]=0xB0FB0E4E;

    return 1;

    }

    3) 在SM3實現的源代碼文件中,通過如下定義來實現SM3算法:

    static void SM3_block_data_order(SM3_CTX*ctx, const void*in, size_t num);

    #define DATA_ORDER_IS_BIG_ENDIAN

    #define HASH_LONG SM3_LONG

    #define HASH_CTX SM3_CTX

    #define HASH_CBLOCK SM3_CBLOCK

    #define HASH_MAKE_STRING(c, s) do

    {

    SM3_LONG ll;

    unsigned int nn;

    for (nn=0; nn

    4; nn++)

    {

    ll=(c)->digest[nn];

    (void)HOST_l2c(ll, (s));

    }

    } while (0)

    #define HASH_UPDATE SM3_Update

    #define HASH_TRANSFORM SM3_Transform

    #define HASH_FINAL SM3_Final

    #define HASH_BLOCK_DATA_ORDER SM3_block_data_order

    #include ″md32_common.h″

    4) 在SM3_block_data_order函數中,實現消息擴展及消息壓縮如下:

    #define RSL(A, I) (((A)<<(I))|((A)>>(32-(I))))

    #define FF0_15(X, Y, Z) ((X)^(Y)^(Z))

    #define FF16_63(X, Y, Z) (((X) & (Y))|((X) & (Z))|((Y) & (Z)))

    #define GG0_15(X, Y, Z) ((X)^(Y)^(Z))

    #define P0(X) ((X)^RSL((X), 9)^RSL((X), 17))

    #define P1(X) ((X)^RSL((X), 15)^RSL((X), 23))

    static void SM3_block_data_order(SM3_CTX*ctx, const void*in, size_t num)

    {

    int j;

    SM3_LONG W[68], W1[64];

    SM3_LONG A, B, C, D, E, F, G, H, SS1, SS2, TT1, TT2, T0_15, T16_63;

    const unsigned char*pblock=(const unsigned char*)in;

    while (num--)

    {

    for (j=0; j<16; j++) {

    HOST_c2l(pblock, W[j]);

    }

    for (j=16; j<68; j++) {

    W[j]=W[j-16]^W[j-9]^

    RSL(W[j-3], 15);

    W[j]=P1(W[j])^

    RSL(W[j-13], 7)^W[j-6];

    }

    for (j=0; j<64; j++) {

    W1[j]=W[j]^W[j+4];

    }

    A=ctx->digest[0],

    B=ctx->digest[1],

    C=ctx->digest[2],

    D=ctx->digest[3];

    E=ctx->digest[4],

    F=ctx->digest[5],

    G=ctx->digest[6],

    H=ctx->digest[7];

    T0_15=0x79CC4519, T16_63=

    0x7A879D8A;

    for (j=0; j<16; j++) {

    SS1=RSL(A, 12)+E+

    RSL(T0_15, j),

    SS1=RSL(SS1, 7);

    SS2=SS1^RSL(A, 12);

    TT1=FF0_15(A, B, C)+D+

    SS2+W1[j];

    TT2=GG0_15(E, F, G)+H+

    SS1+W[j];

    D=C;

    C=RSL(B, 9);

    B=A;

    A=TT1;

    H=G;

    G=RSL(F, 19);

    F=E;

    E=P0(TT2);

    }

    for (j=16; j<64; j++) {

    SS1=RSL(A, 12)+E+

    RSL(T16_63, (j % 32)),

    SS1=RSL(SS1, 7);

    SS2=SS1^RSL(A, 12);

    TT1=FF16_63(A, B, C)+D+

    SS2+W1[j];

    TT2=GG16_63(E, F, G)+H+

    SS1+W[j];

    D=C;

    C=RSL(B, 9);

    B=A;

    A=TT1;

    H=G;

    G=RSL(F, 19);

    F=E;

    E=P0(TT2);

    }

    ctx->digest[0] ^=A;

    ctx->digest[1] ^=B;

    ctx->digest[2] ^=C;

    ctx->digest[3] ^=D;

    ctx->digest[4] ^=E;

    ctx->digest[5] ^=F;

    ctx->digest[6] ^=G;

    ctx->digest[7] ^=H;

    }

    }

    到此為止,SM3信息摘要算法的基礎庫軟實現完成.

    1.3.3.2SM3EVP封裝接口實現

    SM3算法EVP封裝接口的實現,首先需要實現結構EVP_MD的成員函數init,update,final;然后需要填充EVP_MD的數據結構的每一項,實現EVP_sm3();然后在evp.h中申明EVP_sm3(void)接口,最后在c_alld.c文件中,將EVP_sm3()加載到OpenSSL的EVP接口庫中.

    1) EVP_MD成員函數的實現

    static int init(EVP_MD_CTX*ctx)

    {

    return SM3_Init(ctx->md_data);

    }

    static int update(EVP_MD_CTX*ctx, const void*data, size_t count)

    {

    return SM3_Update(ctx->md_data,

    data, count);

    }

    static int final(EVP_MD_CTX*ctx,

    unsigned char*md)

    {

    return SM3_Final(md, ctx->md_data);

    }

    2) 填充EVP_MD結構,并實現EVP_sm3()

    static const EVP_MD sm3_md={

    NID_sm3,

    0, 32,

    EVP_MD_FLAG_PKEY_METHOD_SIGNATURE|EVP_MD_FLAG_DIGALGID_ABSENT,

    init, update, final,

    NULL,

    NULL,

    EVP_PKEY_NULL_method,

    64,

    sizeof(EVP_MD*)+sizeof(SM3_CTX),

    NULL

    };

    const EVP_MD*EVP_sm3(void) {return (&sm3_md);}

    3) 在OpenSSL源代碼目錄crypto/evp中,修改文件c_alld.c,以便加載EVP_sm3()接口

    EVP_add_digest(EVP_sm3());

    EVP_add_digest_alias(SN_sm3WithRSA Encryption, SN_sm3WithRSA).

    1.3.4SM2公鑰算法的實現

    國產密碼算法SM2公鑰算法是一條特定的曲線橢圓曲線公鑰算法,它基于ECC的通用算法,按照中國國家密碼管理局發(fā)布的GM/T 0003—2012 《SM2橢圓曲線公鑰密碼算法》標準,定義了SM2簽名[8]、驗證、公鑰加密[9]、私鑰解密、密鑰協商[10]算法5種算法.

    其中,SM2簽名/驗證算法,是對原始信息經過SM3算法做摘要后的結果進行處理的.按照GM/T 0003—2012 《SM2橢圓曲線公鑰密碼算法》(第二部分的6.1節(jié))要求,先要計算Z值,然后再將Z值和原始信息一起做摘要,最后對摘要值進行簽名/驗證.

    因此,SM2公鑰算法中還需要定義計算Z值的函數.

    1.3.4.1Z值的計算

    按照GM/T 0003—2012 《SM2橢圓曲線公鑰密碼算法》(第二部分的6.1節(jié))所述,Z值的計算如下:

    ZA=H256(ENT LA‖IDA‖a‖b‖xG‖xG‖

    xA‖yA),

    其中,H256指的是256 b的信息摘要算法,在國產密碼算法中,此處只取值為SM3信息摘要算法;ENT LA是指由可辨別標識IDA的位(bit)數,轉換而成的2 B;IDA為用戶可辨別標識,當此標識不存在或者未提供時,其值默認為:1234567812345678;a,b為素域橢圓曲線方程y2=x3+ax+b的參數[11]; a的值為FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC;b的值為28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93;xG,xG為基點坐標,其值為:Gx=32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7,Gy=BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0;xA,yA為簽名者的公鑰坐標.

    Z值計算函數原型為:int ECDSA_sm2_get_Z(const EC_KEY*ec_key, const EVP_MD*md, const char*uid, int uid_len, unsigned char*z_buf, size_t*z_len).

    其實現很簡單,在此略過.

    1.3.4.2SM2簽名驗證算法實現

    國產密碼OpenSSL中的SM2簽名、驗證算法函數,依據《GM/T 0003—2012 SM2橢圓曲線公鑰密碼算法 第2部分:數字簽名算法》中所述的原理,按照OpenSSL接口的方式,設計如下:

    1) 數字簽名生成函數

    ① 在OpenSSL中,SM2簽名的對象是經過SM3做過摘要的結果,因此,其原型設計為

    ECDSA_SIG*sm2_do_sign(const unsigned char*dgst, int dgst_len, EC_KEY*eckey),

    其中,dgst為信息摘要值,長度為32 B;eckey為簽名的SM2密鑰對;成功簽名后返回ECDSA_SIG數據結構,否則返回NULL值.

    ② 函數的簽名過程和其實現代碼如下.

    S0:將輸入的參數摘要值的數據類型轉換為整數e;實現如下(e為大數變量):

    BN_bin2bn(dgst, dgst_len, e);

    S1:用隨機數發(fā)生器產生隨機數k ∈[1,n-1];實現如下(k為大數變量,order為SM2參數基點G的階):

    do {

    if (!BN_rand_range(k, order)) return

    NULL;

    } while (BN_is_zero(k));

    S2:計算橢圓曲線點(x1,y1)=[k]G,并將x1的數據類型轉換為整數;其實現為(group為SM2曲線的GROUP值,tmp_point為EC_POINT的變量,x1為大數變量):

    if (!EC_POINT_mul(group, tmp_point,

    k, NULL, NULL, NULL))

    return NULL;

    if (!EC_POINT_get_affine_coordinates_

    GFp(group, tmp_point, x1, NULL, NULL))

    return NULL;

    S3:計算r=(e+x1) modn,若r=0或r+k=n則返回S1;其實現為:

    if (!BN_mod_add(r, e, x1, order, NULL))

    return NULL;

    if (!BN_mod_add(x1, ret->r, k, order,

    NULL)) return NULL;

    if (BN_is_zero(r)‖BN_is_zero(x1)) goto

    S1;

    S4:計算s=((1+dA)-1*(k-r *dA)) mod n,若s=0則返回S1;其實現為(s為大數變量,d為SM2密鑰對中的私鑰):

    if (!BN_mod_add(x1, d, BN_value_one(),

    order, NULL)) return NULL;

    if (!BN_mod_inverse(s, x1, order,

    NULL)) return NULL;

    if (!BN_mod_mul(x1, r, d, order,

    NULL)) return NULL;

    if (!BN_mod_sub(x1, k, x1, order,

    NULL)) return NULL;

    if (!BN_mod_mul(s, s, x1, order,

    NULL)) return NULL

    if (BN_is_zero(ret->s)) goto S1;

    S5:將r, s的值填充ECDSA_SIG結構,返回ECDSA_SIG結構.實現如下:

    ECDSA_SIG*sig;

    sig->r=r;

    sig->s=s;

    return sig;

    2) 數字簽名驗證函數

    ① 國產密碼OpenSSL中,SM2數據簽名驗證函數的原型設計為

    int sm2_do_verify(const unsigned char*dgst, int dgst_len, const ECDSA_SIG*sig, EC_KEY*eckey),

    其中,dgst為原始信息的摘要值;sig為需要驗證的簽名值;驗證成功返回1,失敗返回0.

    ② 國產密碼OpenSSL中,SM2數據簽名驗證流程和實現代碼如下.

    B0:將輸入的摘要值轉換成 e1;實現如下(e1為大數變量):

    if (!BN_bin2bn(dgst, dgst_len, e1))

    return 0;

    B1:檢驗sig->r∈[1,n-1]是否成立,若不成立則驗證不通過;

    B2:檢驗sig->s∈[1,n-1]是否成立,若不成立則驗證不通過;實現如下(order為SM2曲線參數,為基點G的階):

    if (BN_is_zero(e1)) return 0;

    if (BN_ucmp(e1, order)>=0) return 0;

    B3:計算t=(sig->r+ sig->s) mod n,若t=0,則驗證不通過;

    if (!BN_mod_add(t, sig->r, sig->s,

    order, NULL)) return 0;

    if (BN_is_zero(t)) return 0;

    B4:計算橢圓曲線點(x1, y1)=[sig->s]G+[t]PA;其實現如下(group為SM2曲線的GROUP值,point為EC_POINT類型變量,pub_key為驗證用的SM2公鑰):

    if (!EC_POINT_mul(group, point, sig->

    s, pub_key, t, NULL)) return 0;

    B5:將x1的數據類型轉換為整數,計算R=(e1+x1) mod n,檢驗R=sig->r是否成立,若成立則驗證通過;否則驗證不通過,其實現如下(R為大數變量):

    if (!EC_POINT_get_affine_coordinates_

    GFp(group, point, x1, NULL, NULL))

    return 0;

    if (!BN_nnmod(x1, x1, order, NULL))

    return 0;

    if (!BN_mod_add(R, e1, x1, order,

    NULL)) return 0;

    return (BN_ucmp(R, sig->r)==0);

    1.3.4.3SM2公鑰加密及密鑰協商算法實現

    SM2公鑰加密算法包括:公鑰加密算法、私鑰解密算法,其原理可參見《GM/T 0003—2012 SM2橢圓曲線公鑰密碼算法 第4部分:公鑰加密算法》.其中涉及到密鑰派生函數KDF,可依據ANSI X9.63—2001規(guī)范實現(與OpenSSL 1.0.2h中ECDH_KDF_X9_62的實現兼容).設計其原型為:

    SM2ENC*sm2_encrypt(const unsigned char*in, size_t inlen, const EVP_MD*md, EC_KEY*ec_key);

    int sm2_decrypt(unsigned char*out, size_t*outlen, const SM2ENC*in, const EVP_MD*md, EC_KEY*ec_key);

    int KDF_GMT003_2012(unsigned char*out, size_t outlen, const unsigned char*Z, size_t Zlen, const unsigned char*SharedInfo, size_t SharedInfolen, const EVP_MD*md);

    其中,SM2ENC的數據結構為:

    struct sm2enc_st {

    ASN1_INTEGER*x;

    ASN1_INTEGER*y;

    ASN1_OCTET_STRING*m;

    ASN1_OCTET_STRING*c;

    };

    typedef struct sm2enc_st SM2ENC;

    SM2密鑰協商算法的原理可參見《GM/T 0003—2012 SM2橢圓曲線公鑰密碼算法 第3部分:密鑰交換協議》.在OpenSSL中的設計原型為:

    int SM2Kap_compute_key(void*out, size_t outlen, int server;

    const char*peer_uid, int peer_uid_len, const char*self_uid, int self_uid_len;

    const EC_KEY*peer_ecdhe_key, const EC_KEY*self_ecdhe_key;

    const EC_KEY*peer_pub_key, const EC_KEY*self_eckey, const EVP_MD*md).

    其中:out為協商的結果,其輸出長度由outlen指定;server為指示出己方是發(fā)起方/響應方標識,0為發(fā)起方;非0為響應方;peer_uid為對方可辨別標識,其長度由peer_uid_len指定;如果此項為NULL,或者peer_uid_len為0,此標識取默認值:1234567812345678;self_uid為己方可辨別標識,其長度由self_uid_len指定,如果此項為NULL,或者self_uid_len為0,此標識取默認值:1234567812345678;peer_ecdhe_key為對方SM2臨時公鑰;self_ecdhe_key為己方SM2臨時公鑰;peer_pub_key為對方SM2證書公鑰;self_eckey為己方SM2私鑰;md為指定的摘要算法,對于SM2來說,此值默認為EVP_sm3().

    協商成功返回1,否則返回0或者負值.

    由于篇幅所限,本節(jié)所有函數根沒有給出實現.如果有需要此源碼部分,可從https://github.com/jntass/TASSL獲取.

    1.3.4.4SM2公鑰算法EVP接口實現

    首先,國產密碼OpenSSL將SM2視為ECC的一條特定曲線,因此需要將SM2的算法內置于ECC之中;也就是說,需要實現ECDSA調用接口、ECDH調用接口、EVP_PKEY的調用接口.

    1) ECDSA調用接口

    在OpenSSL源代碼目錄crypto/ecdsa的ecs_ossl.c文件,需要對函數:ecdsa_do_sign,ecdsa_do_verify以及對ecdsa_sign_setup作出修改;修改方式如下:

    在函數ecdsa_do_sign的變量申明之后,添加如下語句:

    if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey))==NID_sm2)

    return sm2_do_sign(dgst, dlen, a, b, eckey);

    在函數ecdsa_do_verify的變量申明之后,添加如下語句:

    if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey))==NID_sm2)

    return sm2_do_verify(dgst, dgst_len, sig, eckey);

    在函數ecdsa_sign_setup的變量申明之后,添加如下語句:

    if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey))==NID_sm2)

    return 1;

    這樣即可實現ECDSA自動調用SM2的簽名驗證算法.

    2) ECDH調用接口

    SM2由于不支持ECDH算法,而由SM2密鑰協商取而代之,因此,需要防止SM2曲線運用于ECDH算法中.修改方式如下:

    在OpenSSL源代碼目錄crypto/ecdh的ech_ossl.c中,修改ecdh_compute_key函數,在其變量申明之后,添加如下語句:

    if (EC_GROUP_get_curve_name(EC_KEY_get0_group(ecdh))==NID_sm2)

    return-1;

    3) EVP_PKEY的調用接口

    此接口是通過修改OpenSSL源代碼目錄crypto/ec中的文件ec_pmeth.c來實現的,其實現方法為:

    ① 數據結構EVP_PKEY_EC的尾部,添加如下成員:

    int server;

    char*peer_id;

    char*self_id;

    int peerid_len;

    int selfid_len;

    EC_KEY*peer_ecdhe_key;

    EC_KEY*self_ecdhe_key;

    int encdata_format;

    ② 在函數pkey_ec_init,pkey_ec_copy,pkey_ec_cleanup中需要對所添加的成員進行初始化或者清理工作;

    ③ 需要添加pkey_ec_encrypt和pkey_ec_decrypt,以便實現EVP對SM2公鑰加密以及私鑰解密的調用;

    ④ 需要定義一些宏,以實現EVP接口對SM2的參數設置,并且在pkey_ec_ctrl中實現相關宏的功能,具體宏定義如下:

    # define EVP_PKEY_CTRL_SET_PEER_ID (EVP_PKEY_ALG_CTRL+11)

    # define EVP_PKEY_CTRL_SET_SELF_ID (EVP_PKEY_ALG_CTRL+12)

    # define EVP_PKEY_CTRL_SET_SERVER (EVP_PKEY_ALG_CTRL+13)

    # define EVP_PKEY_CTRL_SET_PEER_ECDHE (EVP_PKEY_ALG_CTRL+14)

    # define EVP_PKEY_CTRL_GEN_SELF_ECDHE (EVP_PKEY_ALG_CTRL+15)

    # define EVP_PKEY_CTRL_GET_SELF_ECDHE (EVP_PKEY_ALG_CTRL+16)

    # define EVP_PKEY_CTRL_SET_SELF_ECDHE (EVP_PKEY_ALG_CTRL+17)

    # define EVP_PKEY_CTRL_SET_ENCDATA (EVP_PKEY_ALG_CTRL+18)

    # define EVP_PKEY_CTX_set_sm2_peer_id(ctx, uid, uid_len)

    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,

    EVP_PKEY_CTRL_SET_PEER_ID, uid_len, (void*)uid)

    # define EVP_PKEY_CTX_set_sm2_self_id(ctx, uid, uid_len)

    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,

    EVP_PKEY_CTRL_SET_SELF_ID, uid_len, (void*)uid);

    # define EVP_PKEY_CTX_set_sm2_server_tag(ctx, tag)

    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,

    EVP_PKEY_CTRL_SET_SERVER, tag, NULL)

    # define EVP_PKEY_CTX_set_sm2_peer_ecdhe(ctx, ecdhe)

    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE,

    EVP_PKEY_CTRL_SET_PEER_ECDHE, 0, (void*)ecdhe)

    # define EVP_PKEY_CTX_gen_sm2_ecdhe_key(ctx, ecdhe)

    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE|

    EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_GEN_SELF_ECDHE, 0, (void*)ecdhe)

    # define EVP_PKEY_CTX_get_sm2_ecdhe_key(ctx, ecdhe)

    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE|

    EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_GET_SELF_ECDHE, 0, (void*)ecdhe)

    # define EVP_PKEY_CTX_set_sm2_ecdhe_key(ctx, ecdhe)

    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_DERIVE|

    EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_SET_SELF_ECDHE, 0, (void*)ecdhe)

    # define EVP_PKEY_CTX_set_sm2_encdata_format(ctx, format)

    EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_ENCRYPT|

    EVP_PKEY_OP_DECRYPT, EVP_PKEY_CTRL_SET_ENCDATA, format, NULL)

    ⑤ 需要修改pkey_ec_kdf_derive函數,增加對SM2密鑰協商的支持,修改方式為在其變量申明之后,添加如下代碼:

    if (EC_GROUP_get_curve_name(EC_KEY_get0_group(ctx->pkey->pkey.ec))==NID_sm2)

    {

    if (!ctx->pkey‖!ctx->peerkey)

    return 0;

    if (!key‖(*keylen==0))

    return 0;

    outlen=*keylen;

    ret=SM2Kap_compute_key(key, outlen,

    dctx->server, dctx->peer_id,

    dctx->peerid_len, dctx->self_id,

    dctx->selfid_len,

    dctx->peer_ecdhe_key, dctx->

    self_ecdhe_key, ctx->peerkey->

    pkey.ec,

    ctx->pkey->pkey.ec, dctx->

    kdf_md);

    if (ret<=0)

    return ret;

    return 1;

    }

    ⑥ 需要在數據結構常量ec_pkey_meth中,對其成員encrypt,decrypt分別賦值為:pkey_ec_encrypt和pkey_ec_decrypt.

    4) 國產密碼OpenSSL中,SM2密鑰需要能夠自動完成對于原始信息的簽名和驗證功能,但由于SM2對原始信息簽名和驗證處理的特殊性,在做摘要之前,需要將簽名者的Z值對原始信息進行補償運算(即:將Z值與原始信息串接在一起),因此需要對OpenSSL源代碼目錄crypto/evp中的m_sigver.c進行修改,以完成SM2的自動簽名、驗證流程.修改方法如下:

    在do_sigver_init函數成功返回前,添加如下代碼:

    if (ctx->pctx->pkey->type==EVP_PKEY_EC) {

    if (EC_GROUP_get_curve_name(EC_KEY_get0_group(ctx->pctx->pkey->

    pkey.ec))

    ==NID_sm2) {

    unsigned char ex_dgst[EVP_MAX_MD_

    SIZE];

    size_t ex_dgstlen=EVP_MAX_MD_

    SIZE;

    if (!ECDSA_sm2_get_Z(ctx->pctx->

    pkey->pkey.ec, type, NULL,

    0, ex_dgst, &ex_dgstlen))

    return 0;

    if (!EVP_DigestUpdate(ctx, ex_dgst,

    ex_dgstlen))

    return 0;

    }

    }

    1.3.4.5將SM2曲線內置于OpenSSL中

    關于國產密碼OpenSSL中,SM2公鑰算法的實現其實有一個前提,那就是SM2曲線必須為OpenSSL所支持的曲線.

    原始的OpenSSL中,并不支持SM2曲線,因此需要通過修改源代碼的方式,將SM2曲線參數添加到OpenSSL中.

    實現方法是修改OpenSSL源代碼目錄crypto/ec中的文件ec_curve.c.首先在此文件的數據結構_ec_list_element_st之前,添加如下數據結構:

    static const struct {

    EC_CURVE_DATA h;

    unsigned char data[0+32*6];

    } _EC_SM2={

    {

    NID_X9_62_prime_field, 0, 32, 1

    },

    {

    /*not need seed*/

    /*p=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF*/

    0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,

    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,

    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

    /*a=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC*/

    0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,

    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,

    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,

    /*b=28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93*/

    0x28, 0xE9, 0xFA, 0x9E, 0x9D, 0x9F, 0x5E, 0x34,

    0x4D, 0x5A, 0x9E, 0x4B, 0xCF, 0x65, 0x09, 0xA7,

    0xF3, 0x97, 0x89, 0xF5, 0x15, 0xAB, 0x8F, 0x92,

    0xDD, 0xBC, 0xBD, 0x41, 0x4D, 0x94, 0x0E, 0x93,

    /*Gx=32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7*/

    0x32, 0xC4, 0xAE, 0x2C, 0x1F, 0x19, 0x81, 0x19,

    0x5F, 0x99, 0x04, 0x46, 0x6A, 0x39, 0xC9, 0x94,

    0x8F, 0xE3, 0x0B, 0xBF, 0xF2, 0x66, 0x0B, 0xE1,

    0x71, 0x5A, 0x45, 0x89, 0x33, 0x4C, 0x74, 0xC7,

    /*Gy=BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0*/

    0xBC, 0x37, 0x36, 0xA2, 0xF4, 0xF6, 0x77, 0x9C,

    0x59, 0xBD, 0xCE, 0xE3, 0x6B, 0x69, 0x21, 0x53,

    0xD0, 0xA9, 0x87, 0x7C, 0xC6, 0x2A, 0x47, 0x40,

    0x02, 0xDF, 0x32, 0xE5, 0x21, 0x39, 0xF0, 0xA0,

    /*n=FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123*/

    0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,

    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

    0x72, 0x03, 0xDF, 0x6B, 0x21, 0xC6, 0x05, 0x2B,

    0x53, 0xBB, 0xF4, 0x09, 0x39, 0xD5, 0x41, 0x23

    }

    };

    然后,在數據結構常量curve_list中,添加SM2曲線的數據(在任意正確位置都可以):

    {NID_sm2, &_EC_SM2.h, 0, ″SM2 curve over a 256 bit prime field″}.

    到此為止,OpenSSL中即可全面地對國產密碼算法SM2公鑰算法進行支持.

    1.4 其他國密算法

    如果需要國產密碼OpenSSL支持其他的國密算法,可以借鑒以上所述的方式來進行添加.

    1.5 國密TLS協議的實現

    國密TLS協議的實現需要根據GM/T 0024—2014《SSL VPN技術規(guī)范》,并實現國產密碼認證體系,在標準的SSL/TLS協議的基礎上來實現.

    通過對比標準的TLS1.1協議,國密TLS1.1協議有如下特點:

    1) 傳輸入層的版本號為0x0101,而不是標準的TLS1.1協議的0x0302;

    2) 需要雙證書支持,即簽名證書和加密證書同時工作,而標準的TLS協議無需雙證書支持;

    3) 客戶端需要獨立API接口來完成國密TLS的建鏈過程;

    4) 無需校驗對方是否支持SM2曲線,因為使用國密套件,對方一定會支持SM2曲線.

    1.5.1國密TLS協議握手流程

    國密TLS協議其實主要體現在建鏈過程之中.圖2所示,是完整的建鏈過程.同時,國密TLS協議也支持會話重用,重用流程如圖3所示.

    圖2 國密TLS協議握手流程

    圖3 會話重用流程

    1.5.2國產密碼雙證書認證體系的實現

    在OpenSSL實現的SSL/TLS中,設計有支持RSA的雙證書認證體系,但OpenSSL并沒有提供RSA雙證書體系的API;對于ECC的證書認證體系來說,其簽名和數據加密或密鑰協商均使用同一套證書與其對應的私鑰來完成.

    而國產密碼認證體系要求使用雙證書[12-14],無論是RSA證書還是SM2證書.因此,國密TLS協議中所屬套件均要求使用雙證書認證,即簽名證書與其對應的私鑰只用于簽名和驗證書;而數據加密或者密鑰協商需要使用加密或者密鑰協商證書與其對應的私鑰.

    要在OpenSSL中實現國密TLS協議,就必須要添加對ECC(SM2其實也是一種特定的ECC)的雙證書認證.

    至于SM2雙證書在何時使用,可參見圖2.在國密TLS協議的握手過程之中,ServerKeyExchange和ClientKeyExchange過程需要用到加密或密鑰協商證書進行密鑰協商;同時它也需要使用數字簽名證書(客戶端除外)進行數字簽名;客戶端CertificateVerify過程需要使用數字簽名證書進行數字簽名;而服務端GetClientKeyExchange和GetClientCertVerify過程需要使用數字簽名證書進行簽名驗證.

    在國產密碼OpenSSL中,原始的SSL/TLS證書認證體系API可直接用于數字簽名證書的認證接口;針對RSA和SM2證書,設計了如下的一套加密證書接口API:

    int SSL_use_enc_RSAPrivateKey(SSL*ssl, RSA*rsa);

    int SSL_use_enc_RSAPrivateKey_ASN1(SSL*ssl, unsigned char*d, long len);

    int SSL_use_enc_RSAPrivateKey_file(SSL*ssl, const char*file, int type);

    int SSL_use_enc_PrivateKey(SSL*ssl, EVP_PKEY*pkey);

    int SSL_use_enc_PrivateKey_ASN1(int type, SSL*ssl, const unsigned char*d, long len);

    int SSL_use_enc_PrivateKey_file(SSL*ssl, const char*file, int type);

    int SSL_CTX_use_enc_RSAPrivateKey(SSL_CTX*ctx, RSA*rsa);

    int SSL_CTX_use_enc_RSAPrivateKey_ASN1(SSL_CTX*ctx, const unsigned char*d, long len);

    int SSL_CTX_use_enc_RSAPrivateKey_file(SSL_CTX*ctx, const char*file, int type);

    int SSL_CTX_use_enc_PrivateKey(SSL_CTX*ctx, EVP_PKEY*pkey);

    int SSL_CTX_use_enc_PrivateKey_ASN1(int type, SSL_CTX*ctx, const unsigned char*d, long len)

    int SSL_CTX_use_enc_PrivateKey_file(SSL_CTX*ctx, const char*file, int type);

    而針對OpenSSL中經過適當修改后,可適應雙證書認證體系的API如下:

    int SSL_use_certificate(SSL*ssl, X509*x);

    int SSL_use_certificate_file(SSL*ssl, const char*file, int type);

    int SSL_use_certificate_ASN1(SSL*ssl, const unsigned char*d, int len);

    int SSL_CTX_use_certificate(SSL_CTX*ctx, X509*x);

    int SSL_CTX_use_certificate_file(SSL_CTX*ctx, const char*file, int type);

    int SSL_CTX_use_certificate_ASN1(SSL_CTX*ctx, int len,const unsigned char*d);

    由這2組API構成了國密TLS雙證書認證體系.

    1.5.3國密TLS套件的實現

    目前,國密TLS協議中定義了許多密碼套件,可用于建立國密TLS協議的鏈路.其中,SM9和RSA相關密碼套件由于使用不多或者有其局限性,這里不作論述,在此,著重說明ECC-SM4-SM3(EC-SM1-SM3和它相同,只不過SM1需要硬件支持)和ECDHE-SM4-SM3(ECDHE-SM1-SM3和它相同,只不過SM1需要硬件支持)這2個密碼套件的實現.

    在國產密碼OpenSSL中,ECC-SM4-SM3,ECDHE-SM4-SM3這2個密碼套件的實現,對于客戶端來說需要實現SendClientKeyExchange和Get ServerKeyExchange這2個過程;而對于服務端來說,需要實現Send ServerKeyExchange和GetClientKeyExchange這2個過程.

    1.5.3.1ECC-SM4-SM3密碼套件的實現

    ECC-SM4-SM3這個密碼套件是指客戶端無證書,或者客戶端只有驗證服務端證書的證書鏈(它一般指的是CA的證書),此時與國密TLS服務器所建的鏈就是使用ECC-SM4-SM3這個密碼套件.

    此時,SendServerKeyExchange過程作如下處理:

    1) 對客戶端隨機數+服務端隨機數+服務端加密/協商證書進行數字簽名;

    2) 發(fā)送此簽名的ASN1的編碼結果.

    Get ServerKeyExchange過程作如下處理:

    1) 取服務端加密證書;

    2) 對客戶端隨機數+服務端隨機數+服務端加密/協商證書進行簽名驗證;

    3) 成則繼續(xù),否則中斷握手.

    SendClientKeyExchange過程作如下處理:

    1) 在48 B的緩沖區(qū)中,填入0x0101(國密TLS的版本號)+46 B的隨機數,構成預主密鑰;

    2) 使用服務端加密證書對此預主密鑰加密;

    3) 發(fā)送加密結果的ASN1的編碼結果.

    GetClientKeyExchange過程作如下處理:

    1) 使用加密私鑰對客戶端發(fā)來的結果作解密運算,得到預主密鑰;

    2) 使用預主密鑰計算主密鑰;

    3) 保留主密鑰,以便會話重用.

    1.5.3.2ECDHE-SM4-SM3密碼套件的實現

    ECDHE-SM4-SM密碼套件是在服務端和客戶端之間,使用SM2密鑰協商協議,生成48 B主密鑰,然后再完成握手過程.

    此時,SendServerKeyExchange過程作如下處理:

    1) 生成服務端臨時SM2密鑰對,取臨時公鑰的字符串值;

    2) 對臨時公鑰的內容進行簽名;

    3) 將臨時公鑰和數字簽名發(fā)送給客戶端.

    Get ServerKeyExchange過程作如下處理:

    1) 取服務端發(fā)送的數據,并對其進行簽名驗證;如果驗證失敗則中斷握手過程;

    2) 取服務端臨時密鑰對并保存.

    SendClientKeyExchange過程作如下處理:

    1) 生成客戶端臨時公鑰;

    2) 使用默認ID為1234567812345678,調用SM2密鑰協商過程,生成48 B的預主密鑰;

    3) 向服務端發(fā)送客戶端的臨時公鑰.

    GetClientKeyExchange過程作如下處理:

    1) 取客戶端發(fā)送的臨時公鑰;

    2) 使用默認ID為1234567812345678,調用SM2密鑰協商過程,生成48 B的預主密鑰;

    3) 計算主密鑰并保存,以便會話重用.

    2 國產密碼OpenSSL的應用

    國產密碼OpenSSL在保留OpenSSL特性的同時,也將國產密碼的相關特性集成到其中,可以應用到許多方面.

    2.1 替換國產操作系統(tǒng)中的OpenSSL模塊

    在世界范圍內,OpenSSL的使用極其廣泛.我國也有大量的應用軟件、系統(tǒng)軟件是依賴于OpenSSL構建的.

    國產密碼OpenSSL不僅提供了國密算法函數,同時也保留了原版OpenSSL的所有功能特點,它可以無縫替換原版OpenSSL,包括命令行工具等等,從而實現應用軟件的密碼算法從國際算法到國密算法的遷移.

    目前在大部分國產操作系統(tǒng)中都集成了OpenSSL.通過使用國產密碼OpenSSL替換國產操作系統(tǒng)中原有的OpenSSL,以實現對國密算法的支持.

    2.2 學習和推廣國密算法

    通過對國密OpenSSL源碼的分析和理解、對其API的應用,再比照國密標準,可以更容易地學習國密算法和國密規(guī)范,讓國密OpenSSL的使用者更加廣泛地、自由地使用國密算法,體會國密算法的優(yōu)越性、安全性.

    通過國產密碼OpenSSL可以加深對國密認證體系的認識.國密OpenSSL的雙證書體系不僅僅應用于SM2證書,同樣也可以應用于RSA證書.使國密雙證書的認證體系可以有著更好的應用前景.

    2.3 構建支持SM2證書簽發(fā)的CA認證中心

    國產密碼OpenSSL已經實現了對國產密碼認證體系的支持,參照我國關于CA系統(tǒng)的相關標準,可以構建符合中國標準的CA系統(tǒng).

    2.4 與其他開源軟件配套使用

    國產密碼OpenSSL可以和nginx,HAproxy,apache等知名的開源軟件配套使用,從而構建支持國密算法的應用環(huán)境.具體構建方式為,將nginx,HAproxy等源代碼作適量修改,以支持國密雙證書體系及國密TLS協議,在國密OpenSSL的基礎上重新構建.

    3 結束語

    本著回報社會、推動國產密碼算法推廣的目的,江南天安已經將天安版國產密碼OpenSSL作為TaSSL項目開源(可以從https://github.com/jntass/TASSL獲取),本文中所有的實現,或者是未提供源代碼實現的部分都可以從TaSSL開源的項目中獲取,同時也有大量的示例程序,以供業(yè)界同仁參考,歡迎業(yè)界同仁和密碼技術愛好者下載使用,并且提供寶貴的意見.

    本文僅僅是拋磚引玉,志在引起OpenSSL愛好者對國密的興趣和熱情.由于篇幅所限,許多的話題言而未盡,愿與國密同仁及愛好者共勉之,一同為推動國密事業(yè)而努力.

    [1]OpenSSL Software Foundation. OpenSSL cryptography and SSL/TLS toolkit[OL]. [2018-01-15]. https://www.openssl.org

    [2]中華人民共和國密碼行業(yè)標準. GM/T 0024—2014 SSL VPN技術規(guī)范[S]. 北京: 中國標準出版社, 2012

    [3]中華人民共和國密碼行業(yè)標準. GM/T 0002—2012 SM4分組密碼算法[S]. 北京: 中國標準出版社, 2012

    [4]中華人民共和國密碼行業(yè)標準. GM/T 0004—2012 SM3密碼雜湊算法[S]. 北京: 中國標準出版社, 2012

    [5]中華人民共和國密碼行業(yè)標準. GM/T 0003—2012 SM2橢圓曲線公鑰密碼算法 第1部分: 總則[S]. 北京: 中國標準出版社, 2012

    [6]Daniel R L, Brown. SEC 1: Elliptic curve cryptography[OL]. 2009 [2018-01-15]. http://www.secg.org/sec1-v2.pdf

    [7]中華人民共和國密碼行業(yè)標準. GM/T 0006—2012 密碼應用標識規(guī)范[S]. 北京: 中國標準出版社, 2012

    [8]中華人民共和國密碼行業(yè)標準. GM/T 0003—2012 SM2橢圓曲線公鑰密碼算法 第2部分: 數字簽名算法[S]. 北京: 中國標準出版社, 2012

    [9]中華人民共和國密碼行業(yè)標準. GM/T 0003—2012 SM2橢圓曲線公鑰密碼算法 第4部分: 公鑰加密算法[S]. 北京: 中國標準出版社, 2012

    [10]中華人民共和國密碼行業(yè)標準. GM/T 0003—2012 SM2橢圓曲線公鑰密碼算法 第3部分: 密鑰交換協議[S]. 北京: 中國標準出版社, 2012

    [11]中華人民共和國密碼行業(yè)標準. GM/T 0003—2012 SM2橢圓曲線公鑰密碼算法 第5部分: 參數定義[S]. 北京: 中國標準出版社, 2012

    [12]中華人民共和國密碼行業(yè)標準. GM/T 0009—2012 SM2密碼算法使用規(guī)范[S]. 北京: 中國標準出版社, 2012

    [13]中華人民共和國密碼行業(yè)標準. GM/T 0014—2012 數字證書認證系統(tǒng)密碼協議規(guī)范[S]. 北京: 中國標準出版社, 2012

    [14]中華人民共和國密碼行業(yè)標準. GM/T 0015—2012 基于SM2密碼算法的數字證書格式規(guī)范[S]. 北京: 中國標準出版社, 2012

    猜你喜歡
    國密源代碼公鑰
    人工智能下復雜軟件源代碼缺陷精準校正
    計算機仿真(2023年8期)2023-09-20 11:23:42
    國密技術在智能燃氣表系統(tǒng)的應用與分析
    煤氣與熱力(2021年7期)2021-08-23 01:11:14
    基于TXL的源代碼插樁技術研究
    Hyperledger Fabric平臺的國密算法嵌入研究
    一種基于混沌的公鑰加密方案
    自助終端設備國密改造方法探究
    軟件源代碼非公知性司法鑒定方法探析
    基于國密算法的銀行移動營銷終端安全系統(tǒng)研究
    電子測試(2018年9期)2018-06-26 06:45:40
    HES:一種更小公鑰的同態(tài)加密算法
    揭秘龍湖產品“源代碼”
    久久婷婷成人综合色麻豆| 人人妻,人人澡人人爽秒播| 亚洲欧美一区二区三区黑人| 成年女人毛片免费观看观看9 | 男人操女人黄网站| 黄频高清免费视频| 中文字幕人妻丝袜一区二区| 国产精品久久久av美女十八| 纯流量卡能插随身wifi吗| 久热爱精品视频在线9| 免费在线观看视频国产中文字幕亚洲| 怎么达到女性高潮| 亚洲精品国产一区二区精华液| 一本色道久久久久久精品综合| 亚洲欧美一区二区三区黑人| 免费在线观看完整版高清| 在线观看一区二区三区激情| 国产精品av久久久久免费| 国产色视频综合| 欧美中文综合在线视频| 亚洲专区国产一区二区| 宅男免费午夜| 久久精品91无色码中文字幕| 捣出白浆h1v1| 黑人欧美特级aaaaaa片| www.熟女人妻精品国产| 精品国内亚洲2022精品成人 | 国产成人一区二区三区免费视频网站| av福利片在线| 日韩大片免费观看网站| 波多野结衣一区麻豆| 黄频高清免费视频| 人人妻人人澡人人爽人人夜夜| 一二三四社区在线视频社区8| 91成年电影在线观看| 国产有黄有色有爽视频| 啪啪无遮挡十八禁网站| av不卡在线播放| 欧美日韩黄片免| 国产伦理片在线播放av一区| 亚洲一卡2卡3卡4卡5卡精品中文| 亚洲av片天天在线观看| 老司机靠b影院| 国产精品98久久久久久宅男小说| 免费高清在线观看日韩| 一进一出好大好爽视频| 999久久久精品免费观看国产| 国产熟女午夜一区二区三区| 久久久久久免费高清国产稀缺| 91大片在线观看| 国产精品 国内视频| 妹子高潮喷水视频| 午夜久久久在线观看| 香蕉丝袜av| 日韩视频在线欧美| 97人妻天天添夜夜摸| 日日摸夜夜添夜夜添小说| 亚洲一区二区三区欧美精品| 一区福利在线观看| 免费在线观看视频国产中文字幕亚洲| 国产成人一区二区三区免费视频网站| 亚洲人成77777在线视频| 亚洲精品国产区一区二| 大码成人一级视频| 人妻一区二区av| 午夜福利视频精品| 欧美日韩中文字幕国产精品一区二区三区 | 老司机午夜福利在线观看视频 | 亚洲av片天天在线观看| 免费观看av网站的网址| 新久久久久国产一级毛片| 女人爽到高潮嗷嗷叫在线视频| 久久人妻av系列| 色婷婷av一区二区三区视频| 在线观看免费午夜福利视频| av福利片在线| 欧美精品一区二区免费开放| 99热国产这里只有精品6| 这个男人来自地球电影免费观看| 日韩中文字幕视频在线看片| 亚洲国产欧美网| 成人特级黄色片久久久久久久 | 俄罗斯特黄特色一大片| 亚洲天堂av无毛| 久久久精品94久久精品| 一二三四在线观看免费中文在| 久久久国产欧美日韩av| 99国产综合亚洲精品| 国产精品偷伦视频观看了| 精品一区二区三区四区五区乱码| 丁香六月欧美| av免费在线观看网站| 五月天丁香电影| 日韩中文字幕视频在线看片| 久久精品国产亚洲av高清一级| 自线自在国产av| 丰满迷人的少妇在线观看| 大香蕉久久成人网| 精品一区二区三卡| 男男h啪啪无遮挡| 18禁黄网站禁片午夜丰满| 欧美老熟妇乱子伦牲交| 乱人伦中国视频| 建设人人有责人人尽责人人享有的| 精品少妇一区二区三区视频日本电影| 国产精品1区2区在线观看. | 久久精品成人免费网站| 十分钟在线观看高清视频www| 亚洲成人手机| 每晚都被弄得嗷嗷叫到高潮| 男女无遮挡免费网站观看| 亚洲精品美女久久久久99蜜臀| 黄片播放在线免费| 久久久国产成人免费| 狠狠婷婷综合久久久久久88av| 一夜夜www| 黄色视频,在线免费观看| 18禁国产床啪视频网站| 国产激情久久老熟女| 日韩 欧美 亚洲 中文字幕| 少妇的丰满在线观看| 精品国产乱码久久久久久男人| 国产精品熟女久久久久浪| av超薄肉色丝袜交足视频| 亚洲精品国产区一区二| 久久精品国产综合久久久| 精品久久久久久电影网| 中文字幕人妻丝袜一区二区| 久久ye,这里只有精品| 午夜福利在线观看吧| 国产xxxxx性猛交| 下体分泌物呈黄色| 一级毛片女人18水好多| 91麻豆av在线| www.999成人在线观看| 精品亚洲乱码少妇综合久久| 亚洲熟女毛片儿| 欧美成人免费av一区二区三区 | 亚洲成人手机| 国产一区二区在线观看av| 亚洲性夜色夜夜综合| 美女高潮喷水抽搐中文字幕| 国产日韩欧美在线精品| 麻豆乱淫一区二区| 中文字幕av电影在线播放| 夫妻午夜视频| 在线观看免费午夜福利视频| 一边摸一边抽搐一进一小说 | 五月天丁香电影| 老熟妇乱子伦视频在线观看| 欧美精品亚洲一区二区| 黑人巨大精品欧美一区二区mp4| 狠狠精品人妻久久久久久综合| 日韩欧美一区视频在线观看| 纵有疾风起免费观看全集完整版| 91麻豆av在线| 欧美激情久久久久久爽电影 | av有码第一页| 日韩有码中文字幕| 丁香六月欧美| 18禁观看日本| 日韩制服丝袜自拍偷拍| 久久精品aⅴ一区二区三区四区| 91字幕亚洲| 岛国在线观看网站| 在线观看66精品国产| 女人爽到高潮嗷嗷叫在线视频| 少妇的丰满在线观看| 成人手机av| 一级,二级,三级黄色视频| 黄色视频,在线免费观看| 男女无遮挡免费网站观看| 动漫黄色视频在线观看| 天堂8中文在线网| 最新美女视频免费是黄的| 国产高清videossex| 国产1区2区3区精品| 黄色 视频免费看| 亚洲精品美女久久久久99蜜臀| 后天国语完整版免费观看| 国产精品一区二区免费欧美| 999精品在线视频| 国产日韩欧美在线精品| 色94色欧美一区二区| 亚洲人成电影免费在线| 亚洲中文日韩欧美视频| 成人av一区二区三区在线看| 老汉色av国产亚洲站长工具| 一区二区三区精品91| av一本久久久久| 黑人巨大精品欧美一区二区mp4| 精品人妻在线不人妻| 天天操日日干夜夜撸| 色综合欧美亚洲国产小说| 欧美国产精品va在线观看不卡| videos熟女内射| 91成年电影在线观看| 午夜福利在线免费观看网站| 免费在线观看完整版高清| 日本欧美视频一区| 色老头精品视频在线观看| 美女国产高潮福利片在线看| 国产免费视频播放在线视频| 国产成人av激情在线播放| 亚洲国产中文字幕在线视频| 最新的欧美精品一区二区| 91精品三级在线观看| 国产不卡av网站在线观看| 人人妻人人澡人人看| 久久中文字幕一级| 亚洲视频免费观看视频| 亚洲av成人不卡在线观看播放网| 麻豆乱淫一区二区| 两个人看的免费小视频| 精品国产一区二区久久| 久久久久久久久久久久大奶| 国内毛片毛片毛片毛片毛片| 他把我摸到了高潮在线观看 | 一级毛片女人18水好多| 日本vs欧美在线观看视频| 国产在线免费精品| 亚洲精品在线观看二区| 国产无遮挡羞羞视频在线观看| 午夜福利影视在线免费观看| 淫妇啪啪啪对白视频| 精品久久蜜臀av无| 如日韩欧美国产精品一区二区三区| bbb黄色大片| 69精品国产乱码久久久| 99香蕉大伊视频| 日本一区二区免费在线视频| 亚洲免费av在线视频| 男女高潮啪啪啪动态图| 曰老女人黄片| 午夜福利视频在线观看免费| 精品免费久久久久久久清纯 | 久久精品成人免费网站| 亚洲精品国产色婷婷电影| 精品少妇一区二区三区视频日本电影| 捣出白浆h1v1| 国产区一区二久久| 国产精品1区2区在线观看. | 宅男免费午夜| 国产精品亚洲av一区麻豆| 老熟妇乱子伦视频在线观看| 午夜福利,免费看| 久久人妻熟女aⅴ| 欧美日韩亚洲综合一区二区三区_| 亚洲人成77777在线视频| 捣出白浆h1v1| 黄色视频不卡| kizo精华| 日韩欧美一区视频在线观看| 十八禁高潮呻吟视频| 国产精品一区二区精品视频观看| 91大片在线观看| 50天的宝宝边吃奶边哭怎么回事| 美女扒开内裤让男人捅视频| 色综合欧美亚洲国产小说| 亚洲一码二码三码区别大吗| 91av网站免费观看| 欧美日韩成人在线一区二区| 最新美女视频免费是黄的| 99九九在线精品视频| 天天躁夜夜躁狠狠躁躁| 亚洲成人国产一区在线观看| 日韩熟女老妇一区二区性免费视频| 久久精品成人免费网站| 欧美国产精品一级二级三级| 欧美人与性动交α欧美软件| 超碰97精品在线观看| 啦啦啦 在线观看视频| 久久精品国产99精品国产亚洲性色 | 另类精品久久| 黄片小视频在线播放| 国产淫语在线视频| 老司机在亚洲福利影院| 激情视频va一区二区三区| 国产精品香港三级国产av潘金莲| 久久久水蜜桃国产精品网| a在线观看视频网站| 亚洲欧洲日产国产| 国产精品熟女久久久久浪| 无遮挡黄片免费观看| 精品国产一区二区三区久久久樱花| 国产区一区二久久| 国产在视频线精品| 嫩草影视91久久| 女人久久www免费人成看片| 青草久久国产| 国产精品免费大片| 亚洲色图av天堂| 日韩精品免费视频一区二区三区| 男女免费视频国产| 精品午夜福利视频在线观看一区 | 99精品在免费线老司机午夜| 午夜免费成人在线视频| 免费看十八禁软件| 色播在线永久视频| 国产av一区二区精品久久| 精品福利永久在线观看| 精品国产乱子伦一区二区三区| 无遮挡黄片免费观看| av超薄肉色丝袜交足视频| 久久人妻av系列| 精品国产超薄肉色丝袜足j| 麻豆乱淫一区二区| 欧美精品啪啪一区二区三区| 久久午夜综合久久蜜桃| 人人妻人人澡人人看| www.熟女人妻精品国产| 老司机深夜福利视频在线观看| 99久久精品国产亚洲精品| 精品国产国语对白av| 精品亚洲乱码少妇综合久久| 久久久欧美国产精品| 国产日韩欧美亚洲二区| 99re在线观看精品视频| 欧美变态另类bdsm刘玥| 亚洲熟女毛片儿| 久久婷婷成人综合色麻豆| 亚洲精品在线观看二区| 国产精品久久久av美女十八| 午夜福利免费观看在线| 久久亚洲真实| 精品午夜福利视频在线观看一区 | 午夜福利,免费看| 丝袜美腿诱惑在线| 国产黄色免费在线视频| 亚洲天堂av无毛| 久久久久久久久久久久大奶| 日韩中文字幕欧美一区二区| h视频一区二区三区| 亚洲欧美色中文字幕在线| 久久久欧美国产精品| 黑丝袜美女国产一区| 亚洲熟女精品中文字幕| 丰满人妻熟妇乱又伦精品不卡| 欧美人与性动交α欧美软件| 国产99久久九九免费精品| 一级a爱视频在线免费观看| 日本欧美视频一区| 国产欧美日韩一区二区三| 亚洲中文av在线| 男女免费视频国产| 国产精品一区二区在线观看99| 国产福利在线免费观看视频| 国产精品成人在线| 亚洲伊人久久精品综合| 免费久久久久久久精品成人欧美视频| 人人澡人人妻人| 成人永久免费在线观看视频 | 精品国产亚洲在线| 国产无遮挡羞羞视频在线观看| 三上悠亚av全集在线观看| 巨乳人妻的诱惑在线观看| 国产伦理片在线播放av一区| 久久国产精品大桥未久av| 中亚洲国语对白在线视频| 最黄视频免费看| 国产男女内射视频| 国产成人免费无遮挡视频| 国产精品久久久久成人av| 国产亚洲av高清不卡| 乱人伦中国视频| 十八禁网站免费在线| 亚洲国产欧美一区二区综合| 最新在线观看一区二区三区| 一级毛片精品| 不卡一级毛片| 人人澡人人妻人| 我的亚洲天堂| 岛国在线观看网站| av天堂在线播放| 亚洲精品国产精品久久久不卡| 久久99一区二区三区| 精品熟女少妇八av免费久了| 欧美日韩亚洲国产一区二区在线观看 | 熟女少妇亚洲综合色aaa.| 99九九在线精品视频| 飞空精品影院首页| 久久精品熟女亚洲av麻豆精品| 亚洲久久久国产精品| 久久国产精品大桥未久av| 精品熟女少妇八av免费久了| 日韩中文字幕视频在线看片| 我要看黄色一级片免费的| netflix在线观看网站| 成人精品一区二区免费| 欧美乱码精品一区二区三区| 日本黄色视频三级网站网址 | 亚洲五月色婷婷综合| 男女午夜视频在线观看| 99在线人妻在线中文字幕 | 成人18禁在线播放| 国产精品电影一区二区三区 | 狂野欧美激情性xxxx| 中文字幕最新亚洲高清| 国产精品免费视频内射| 久久国产精品男人的天堂亚洲| 中文字幕人妻丝袜制服| 少妇的丰满在线观看| 国产又色又爽无遮挡免费看| 欧美 亚洲 国产 日韩一| 国产成人免费观看mmmm| 正在播放国产对白刺激| 午夜日韩欧美国产| 国产精品久久久久成人av| 亚洲国产欧美日韩在线播放| 亚洲第一青青草原| 国产不卡一卡二| 欧美激情极品国产一区二区三区| 精品乱码久久久久久99久播| 国产成人精品在线电影| 成年人黄色毛片网站| 2018国产大陆天天弄谢| 91九色精品人成在线观看| 不卡一级毛片| 人妻一区二区av| 丝袜人妻中文字幕| 大码成人一级视频| 午夜91福利影院| 免费在线观看影片大全网站| 精品视频人人做人人爽| 亚洲av第一区精品v没综合| 成人国产av品久久久| 黄片小视频在线播放| 午夜激情久久久久久久| 精品亚洲成a人片在线观看| 欧美日韩福利视频一区二区| 嫩草影视91久久| 欧美日韩视频精品一区| 欧美成人免费av一区二区三区 | 欧美日韩亚洲高清精品| 又黄又粗又硬又大视频| 人成视频在线观看免费观看| 两性午夜刺激爽爽歪歪视频在线观看 | 国产精品影院久久| 一本—道久久a久久精品蜜桃钙片| 巨乳人妻的诱惑在线观看| 大码成人一级视频| 国产日韩欧美亚洲二区| av福利片在线| 老司机靠b影院| 中文字幕另类日韩欧美亚洲嫩草| 亚洲成人手机| 成人免费观看视频高清| 日日摸夜夜添夜夜添小说| 国产男靠女视频免费网站| 欧美精品一区二区大全| 精品国产乱子伦一区二区三区| 久久亚洲精品不卡| 老司机午夜福利在线观看视频 | 亚洲精品成人av观看孕妇| 中国美女看黄片| 国产老妇伦熟女老妇高清| 日韩三级视频一区二区三区| 黄片播放在线免费| 丁香欧美五月| 久久久国产一区二区| 99国产极品粉嫩在线观看| 视频在线观看一区二区三区| 热re99久久精品国产66热6| 中国美女看黄片| 美国免费a级毛片| 亚洲av日韩在线播放| 99国产精品一区二区三区| 极品教师在线免费播放| a级毛片黄视频| 精品免费久久久久久久清纯 | 欧美激情久久久久久爽电影 | 天堂中文最新版在线下载| 久久精品国产综合久久久| 狠狠狠狠99中文字幕| 一边摸一边抽搐一进一出视频| 国产亚洲精品久久久久5区| 午夜日韩欧美国产| videosex国产| 亚洲va日本ⅴa欧美va伊人久久| 欧美激情高清一区二区三区| 我要看黄色一级片免费的| 少妇裸体淫交视频免费看高清 | 少妇被粗大的猛进出69影院| 成年人黄色毛片网站| 亚洲va日本ⅴa欧美va伊人久久| 亚洲精华国产精华精| 亚洲 欧美一区二区三区| 午夜福利欧美成人| 亚洲avbb在线观看| 亚洲第一青青草原| 人人妻人人添人人爽欧美一区卜| 国产男女超爽视频在线观看| 精品国产国语对白av| 视频区欧美日本亚洲| 欧美精品啪啪一区二区三区| 国产成人精品无人区| 女人爽到高潮嗷嗷叫在线视频| 国产精品.久久久| 又黄又粗又硬又大视频| 纵有疾风起免费观看全集完整版| www日本在线高清视频| 午夜福利在线免费观看网站| av电影中文网址| 精品国产一区二区三区久久久樱花| 亚洲中文日韩欧美视频| 交换朋友夫妻互换小说| 国产老妇伦熟女老妇高清| 纵有疾风起免费观看全集完整版| 热re99久久精品国产66热6| 欧美日韩一级在线毛片| 999精品在线视频| 首页视频小说图片口味搜索| 欧美在线黄色| 日韩中文字幕视频在线看片| 深夜精品福利| 黄色毛片三级朝国网站| 午夜福利在线免费观看网站| 欧美国产精品va在线观看不卡| 国产成人精品无人区| 曰老女人黄片| 在线观看免费午夜福利视频| 午夜免费成人在线视频| 91麻豆av在线| 国产在线视频一区二区| 一区二区三区国产精品乱码| 91av网站免费观看| 中文字幕高清在线视频| 一本一本久久a久久精品综合妖精| 欧美另类亚洲清纯唯美| 美女福利国产在线| 亚洲欧美精品综合一区二区三区| 国产精品免费一区二区三区在线 | www日本在线高清视频| 欧美激情极品国产一区二区三区| 伦理电影免费视频| 天天影视国产精品| 99久久国产精品久久久| 亚洲精品一卡2卡三卡4卡5卡| 久久精品人人爽人人爽视色| 看免费av毛片| 国产不卡av网站在线观看| 在线av久久热| 欧美成人午夜精品| 久久人妻福利社区极品人妻图片| 一本久久精品| 日本黄色日本黄色录像| 两人在一起打扑克的视频| 国产一区二区三区视频了| 国产色视频综合| 亚洲五月色婷婷综合| 亚洲av日韩在线播放| 男男h啪啪无遮挡| kizo精华| 午夜老司机福利片| 丰满饥渴人妻一区二区三| 青草久久国产| 老熟妇仑乱视频hdxx| 极品人妻少妇av视频| 久久毛片免费看一区二区三区| 精品一区二区三区av网在线观看 | 一进一出抽搐动态| 亚洲伊人色综图| 大片电影免费在线观看免费| 亚洲av日韩精品久久久久久密| 国产成+人综合+亚洲专区| 欧美乱妇无乱码| 国产野战对白在线观看| 老司机福利观看| 男女床上黄色一级片免费看| 99国产精品99久久久久| 这个男人来自地球电影免费观看| 免费黄频网站在线观看国产| 丰满人妻熟妇乱又伦精品不卡| 黄色视频,在线免费观看| 一二三四在线观看免费中文在| 69精品国产乱码久久久| 午夜福利乱码中文字幕| 亚洲成人手机| av网站免费在线观看视频| 丝瓜视频免费看黄片| 91麻豆av在线| 亚洲av日韩精品久久久久久密| 免费日韩欧美在线观看| 国产极品粉嫩免费观看在线| 无遮挡黄片免费观看| 法律面前人人平等表现在哪些方面| 久久精品人人爽人人爽视色| 久久久久网色| 嫁个100分男人电影在线观看| 午夜视频精品福利| 欧美一级毛片孕妇| 久久精品熟女亚洲av麻豆精品| 国产aⅴ精品一区二区三区波| 国产一卡二卡三卡精品| 在线十欧美十亚洲十日本专区| 在线观看免费日韩欧美大片| videos熟女内射| 国产片内射在线| 日韩熟女老妇一区二区性免费视频| 女同久久另类99精品国产91| 日本wwww免费看| 在线观看人妻少妇| xxxhd国产人妻xxx| 久久人妻熟女aⅴ| 一级黄色大片毛片| 成人国产av品久久久| 电影成人av| 欧美 日韩 精品 国产| 在线av久久热| 他把我摸到了高潮在线观看 | 十八禁网站网址无遮挡| 久久 成人 亚洲| 欧美日韩黄片免| 欧美中文综合在线视频| 亚洲久久久国产精品|