SM2是國密局推出的一種他們自己說具有自主知識產權的非對稱商用密碼算法。本身是基于ECC橢圓曲線算法的,所以要講SM2, 先要弄懂ECC。
完全理解ECC算法需要一定的數學功底,因為涉及到射影平面坐標系,齊次方程求解, 曲線的運算規則等概念。
本篇的主旨還是希望能以簡單通俗的語言,講清楚PBOC3.0認證過程中,所用到的SM2的相關概念,包括它的實現,使用等。
1、橢圓曲線到底是什么樣的
圖1
圖2
上面是兩個不同橢圓曲線在坐標系中的幾何表示, 不過這個坐標系不是二維坐標系,而是射影坐標系。可以用空間思維想像一下(但是注意不是三維坐標系),打個比方,你晚上站在一個路燈前面,地上有你的影子,你本身是在一個二維坐標系(把你想像成一個紙片),和你的影子一起構成一個射影坐標系。
曲線的每一個點, 用三個參量表示, (X,Y,Z)。我們知道在二維坐標系里的每個圖形都遵循一個方程,比如直接的二元一次方程是y=kx+b, 圓的方程是(x-a)2+(y-b)2=r2, 橢圓曲線在射影坐標系里也有自己的定義:
Y2Z+a1XYZ+a3YZ2=X3+a2X2Z+a4XZ2+a6Z3
所有橢圓曲線上的點都滿足上述方程,a1,a2,a3,a4,a6是系數,決定曲線的形狀和位置。
二維坐標和射影坐標有一個對應關系,即x=X/Z, y=Y/Z, 這樣就可以把上面的方程轉成普通的二維坐標系方程:
y2+a1xy+a3y= x3+a2x2+a4x+a6
2、離散的橢圓曲線
上面的坐標系都是基于實數的,橢圓曲線看起來都是平滑的,如果我們限制曲線的點都必須是整數,曲線就變成離散的了,如圖3所示:
圖3
再進一步限制,要求整數必須大于0, 小于某個大整數P, 這樣就形成了一個有限域Fp.然后我們在這個有限域里定義一些點與點之間的加減乘除運算規則,比如A點加B點得到C點(記做A+B≡C (mod p)),或者A點乘以n得到K點(記做A×n≡K (mod p))。至于具體規則細節可以不用關心,只要知道有這樣的操作即可。
選一條曲線,比如
y2=x3+ax+b
把它定義在Fp上, 要求a,b滿足:
4a3+27b2≠0 (mod p)
我們把這樣的曲線記為Ep(a,b)
加解密是基于這樣的數學難題,K=kG,其中 K,G為Ep(a,b)上的點,k是整數,小于G點(注意區分,不是我們平常說的那個意思)的階(不用關心什么是點的階)。給定k和G,計算K很容易;但給定K和G,求k就困難了。這樣,G就叫做基點,k是私鑰,K是公鑰。
最后總結。描述一條Fp上的橢圓曲線,有六個參量: T=(p,a,b,G,n,h)。
p 、a 、b 用來確定一條橢圓曲線, G為基點, n為點G的階, h 是橢圓曲線上所有點的個數m與n相除的整數部分)
知識準備階段知道這么多就可以了。
二、SM2在PBOC認證中的使用
1、簽名和驗簽的原理
前面提到根據系數的不同,ECC曲線可以有很多,SM2使用其中一種,這就表明它的曲線方程,以及前面說到的六個參量都是固定的。根據國密局給出的規范定義如下:
[cpp] view plain copyy2=x3+ax+b p=FFFFFFFE FFFFFFFFFFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF a=FFFFFFFE FFFFFFFFFFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC b=28E9FA9E 9D9F5E344D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93 n=FFFFFFFE FFFFFFFFFFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123 Gx=32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7 Gy=BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0這里容易引起一個誤解,會認為參數都固定了,公私鑰是不是只能有一對?當然不是,注意前面提到的K=kG的模型,K才是公鑰,所以公鑰其實是曲線在離散坐標系中,滿足條件的一個曲線上的點??梢杂泻芏鄠€。另外, 從這幾個參量可以獲知PBOC 3.0的公鑰長度都是256位。
基于這種離散橢圓曲線原理的SM2算法一般有三種用法,簽名驗簽,加解密, 密鑰交換。PBOC 3.0中的脫機數據認證只用到簽名驗簽的功能。終端關心的是如何驗簽,卡片則要考慮如何實現生成簽名。
2、基于openssl實現sm2
這里給出一個基于openssl的sm2實現, 如果不了解openssl,可以先搜索一下相關知識,這里不講解。openssl已經實現ECC算法接口,也就是核心已經有了,實現sm2其實并不難,關鍵是理解它里面各種接口如何使用。下面就分析一個終端驗簽的sm2實現。另外需要說明這里給出的只是代碼片段,僅供理解用。
函數接口
[cpp] view plain copyint SM2_Verify(BYTE* Px,BYTE* Py, BYTE* DataIn,DWord DataLen, BYTE* sigrs)前兩個參數是K的坐標值,也就是公鑰。Datain和datalen分別是明文數據和其長度,最后一個參數是待驗證的簽名。
曲線的參數常量定義如下:
[cpp] view plain copy//////////////////////////////////////////////////////////////// static const char *group_p ="FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"; static const char *group_a ="FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"; static const char *group_b ="28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"; static const char *group_Gx ="32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"; static const char *group_Gy ="BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"; static const char *group_n = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"; static const char *ENTL_ID ="008031323334353637383132333435363738"; #define SM2_KEY_LENGTH 32 //256位曲線 ////////////////////////////////////////////////////////////////ENTL_ID是pboc規范中指定的用于SM3產生摘要的報文頭數據。
[cpp] view plain copystrcpy(szBuff, ENTL_ID); strcat(szBuff,group_a); strcat(szBuff,group_b); strcat(szBuff,group_Gx); strcat(szBuff,group_Gy); AscToBcd(szDataForDigest,(unsigned char *)szBuff, nLen); …. SM3(szDataForDigest,nLen+SM2_KEY_LENGTH*2, digestZA); memcpy(szDataForDigest,digestZA, ECC_LENGTH); memcpy(szDataForDigest+ECC_LENGTH,DataIn, DataLen); SM3(szDataForDigest,DataLen+ECC_LENGTH, digestH); 第一步,對上述數據用sm3做摘要,摘要的結果與數據拼接后再做摘要。[cpp] view plain copyp = BN_new(); a = BN_new(); b = BN_new(); group = EC_GROUP_new(EC_GFp_mont_method()); BN_hex2bn(&p, group_p)) BN_hex2bn(&a, group_a)) BN_hex2bn(&b, group_b)) 這里是把定義的曲線常量轉換成大數表式,這樣才能使用openssl中的接口。Group是ECC中的曲線組,它是ECC算法的核心,為什么這么說呢? 因為這個group里的所有字段就確定了曲線的所有信息, 后面會看到,這里只是用EC_GROUP_new生成一個空的group, 然后由p,a,b等參數來填充group, 再以這個group為基礎去生成曲線上的點。
[cpp] view plain copyif (!EC_GROUP_set_curve_GFp(group, p, a, b,ctx)) { gotoerr_PRocess; } P = EC_POINT_new(group); Q = EC_POINT_new(group); R = EC_POINT_new(group); if (!P || !Q || !R) { gotoerr_process; } 這一段就確定了group的所有信息,并且根據group生成三個曲線上的點(點一定在曲線上,這個很重要)。[cpp] view plain copy<span style="white-space:pre"> </span>x = BN_new(); y= BN_new(); z= BN_new(); if(!x || !y || !z) { gotoerr_process; } //Gx if(!BN_hex2bn(&x, group_Gx)) { gotoerr_process; } if(!EC_POINT_set_compressed_coordinates_GFp(group, P, x, 0, ctx)) { gotoerr_process; } if(!BN_hex2bn(&z, group_n)) { gotoerr_process; } if(!EC_GROUP_set_generator(group, P, z, BN_value_one())) { gotoerr_process; } if(!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) { gotoerr_process; }這一段首先是設置n到group, n前面講過,是曲線的階。另外就是由G點坐標x,y確定點P,這里我其實也有點不太明白,G點坐標y本來就是已知的,為什么要再通過曲線變換表式生成y,是不是想要對比前面的group信息是否正確?只是為了校驗?
[cpp] view plain copyif ((eckey = EC_KEY_new()) == NULL) { gotoerr_process; } if(EC_KEY_set_group(eckey, group) == 0) { gotoerr_process; } EC_KEY_set_public_key(eckey, P); if(!EC_KEY_check_key(eckey)) { gotoerr_process; } if(SM2_do_verify(1, digestH, SM2_KEY_LENGTH, signature, sig_len, eckey) != 1) { gotoerr_process; }這段比較好理解,生成公鑰eckey,并由eckey最終驗簽。驗簽的執行函數sm2_do_verify有點復雜,這里不做過多的解釋(其實是我解釋不清楚, 哇哈哈),在一個國外的網站上找到一個比較好的描述,拿過來用用。
3、脫機數據認證使用sm2的具體流程
我假設看這篇文章的人對PBOC 2.0中基于RSA國際算法的脫機數據認證流程已經比較了解,相關概念不再過多描述,重點關注二者的差異性。
另外,簡單說一下sm3,因為下面會用到。sm3是一個類似hash的雜湊算法,即給定一個輸入(一般很長),產生一個固定長度的輸出(sm3是32個字節,hash是20個字節)。它有兩個特點:
1 不可逆性,即無法由輸出推導出輸入。
2 不同的輸入,產生不同的輸出。
下面就拿終端SDA認證卡片來看看sm2如何在pboc中使用的。
首先,發卡行公鑰等數據(還包括公鑰,算法標識,有效期等信息)被CA私鑰簽名(注意不是加密)生成發卡行公鑰證書,這個證書會個人化到ic卡中。這些數據如下圖所示:
圖4
簽名其實就是對這個表里的數據做一系列運算,最終生成一個64字節的數據,分別由各32字節的r和s拼接而成(r和s只是個符號而已,沒有特別意思)。這64字節的簽名拼接到圖4后面就是發卡行公鑰證書。
這里與國際算法的公鑰證書就有明顯的區別了。國際算法證書是密文的,發卡行公鑰用rsa加密。而國密的公鑰證書完全是明文。用數據舉例,下面這些數據來自pboc3.0的卡片送檢指南,就是檢測時要求個人化到卡里的數據。
[plain] view plain copy【發卡行公鑰】 : 173A31DD681C6F8FE3BA6C354AD3924A4ADFD15EB0581BC1B37A1EB1C88DA29B47155F62FCF4CCCD201B134351A049D77E81F6A6C66E9CB32664F41348DA11F 【CA哈希值】(r||s) : 3499A2A0A7FED8F74F119B416FF728BA98EF0A32A36BCCB8D0110623D466425CA44C68F8E49121D9BFA9484CAEF9B476C5EB576D1A8DD6BC4A0986AF4134ABAF 【Tag_90 】(發卡行公鑰證書) : 1262280001122000000204001140173A31DD681C6F8FE3BA6C354AD3924A4ADFD15EB0581BC1B37A1EB1C88DA29B47155F62FCF4CCCD201B134351A049D77E86A6C66E9CB32664F41348DA11F63499A2A0A7FED8F74F119B416FF728BA98EF0A32A36BCCB8D0110623D466425CA44C68F8E49121D9BFA9484CAEF9B476C5E56D1A8DD6BC4A0986AF4134ABAF可以自己的解析一下,看看是否和上面表格中的數據一致, 并且都是明文。
終端在讀記錄階段獲取發卡行公鑰證書,國際算法需要用rsa公鑰解密整個證書,然后驗證hash,通過后取出發卡行公鑰。而國密算法,終端只要用sm2公鑰驗64字節的簽名,通過后直接取明文發卡行公鑰,所以國密的驗簽的動作其實就相當于國際里的rsa解密和hash對比兩個動作。
接著終端進行靜態數據簽名的驗證,情況類似,對于國密,這些數據都是明文形式,后面拼接64字節的sm2簽名,這64字節是用發卡行私鑰對明文數據簽名得到的。終端要做的就是拿剛剛獲取的發卡行公鑰對這64字節數據驗證即可,驗證通過就表示SDA通過。
四、PBOC為什么要選擇國密
首先從技術角度,實現同樣的計算復雜度,ECC的計算量相對RSA較小,所以效率高。RSA現在在不斷的增加模長,目前都用到了2048位。并不是說現在一定要用2048位才是安全的,只是它的安全性更高,破解難度更大,這個要綜合考慮,位數高也意味著成本高。有些不差錢的大公司比如谷歌就已經未雨綢繆的把2048位用在了它們的Gmail郵箱服務中。PBOC3.0 認證中目前只用到1984位,其實也是相對安全的。
不過這個觀點目前還存在爭議。前段時間在清華大學聽了一個關于密碼算法的課,清華有個教授認為sm2并不見得比rsa更高級,只是sm2的原理比rsa難理解,所以大部分人認為它會相對安全些。一旦橢圓曲線被大家研究透了,sm2的光環也可能就此褪去。當然這個也是他個人的觀點。
另外一個因素,要從國家戰略的角度考慮,RSA之前一直被傳與美國安全局合作,在算法中加入后門,這種事是寧可信其有的。國密算法咱起碼是自己研發的東西,所有的過程細節都一清二楚, 不用擔收后門的事情。
央行現在非常重視國產安全芯片的推進工作,前些天央行的李曉楓還公開強調未來金融IC卡芯片要國產化,國密算法是其中很關鍵的一步。未來國產芯片加國密算法,才會有真正自主, 安全的國產金融IC卡產品。
轉自:http://blog.csdn.net/pony_maggie/article/details/39780825
新聞熱點
疑難解答