1. 程式人生 > 實用技巧 >ECC橢圓曲線加密演算法—加解密(SageMath實現)

ECC橢圓曲線加密演算法—加解密(SageMath實現)

簡介

ECC橢圓曲線加密,它的安全性基於橢圓曲線上的離散對數問題。

比特幣和目前的二代居民身份證都採用了ECC作為加密演算法。

ECC演算法如下:

  橢圓曲線Ep(a,b)(p為模數),基點G(x,y),G點的階數n,私鑰k,公鑰K(x,y),隨機整數r,明文為一點m(x,y),密文為兩點c1(x,y)和c2(x,y)
  (其中基點G,明文m,密文c1、c2都是橢圓曲線E上的點)
  選擇私鑰k(k<n)
  得到公鑰K = k*G
  選擇隨機整數r(r<n)
  加密:
  c1 = m+r*K
  c2 = r*G
  解密:
  m = c1-k*c2

關於橢圓曲線的更多知識,可以參考Kalafinaian師傅的文章:https://www.cnblogs.com/Kalafinaian/p/7392505.html

SageMath可以直接計算橢圓曲線加法和橢圓曲線乘法。

橢圓曲線運算(SageMath):

'''
點u(x,y),整數a,點v(x,y),點w(x,y)
'''
a_inv = inverse_mod(a,fn) #(a_inv是a關於模fn的乘法逆元)
v = a*u
u = v*a_inv
w = u+v

加解密指令碼

SageMath加密指令碼:

'''
加密
橢圓曲線選取時,模數p應是一個大質數,基點G的階數n也是一個質數
ECC所用的橢圓曲線有幾個固定的標準,如Secp256k1、Secp256r1等
'''
p = 520175694996894336551855254801109133456102894612986723725313
a = 7313143
b = 5531089
E = EllipticCurve(GF(p),[a,b]) #建立橢圓曲線E
G = E(383309911918352312476143108415504173014998255339380791655106,365034016619404037733940422396977249819924073858533741027266) #取E上一點G作為基點
n = G.order() #G的階數
k = 96001
K = k*G
r = 3832553
m = E(241330684417215700597612930059577361280847040371713971023550,301180098343646945961237431316562958402801995883635720461075) #取E上一點m作為明文
c1 = m+r*K
c2 = r*G
print(c1)
print(c2)

SageMath解密指令碼:

'''
解密
'''
p = 520175694996894336551855254801109133456102894612986723725313
a = 7313143
b = 5531089
k = 96001
E = EllipticCurve(GF(p),[a,b]) #建立橢圓曲線E
c1 = E(213171155481617068291988259947180811072847218811482928670200,333462777376055187119428452085848783067407022110626513498729)
c2 = E(247740071423759529826985384384091435482909076542019443791998,66144246525423465426174688710291899454558908519475124801279)
m =  m = c1-k*c2
print(m)

其他

使用Crypto.PublicKey.ECC生成ECC金鑰:

from Crypto.PublicKey import ECC

#生成ECC金鑰
key = ECC.generate(curve='NIST P-256') #使用橢圓曲線NIST P-256

#輸出金鑰(包括私鑰k,基點G)
print(key)

#公鑰(point_x,point_y是基點G的座標)
print(key.public_key())

#橢圓曲線
print(key.curve)

#私鑰k
print(key.d)

#匯出為pem金鑰檔案
print(key.export_key(format='PEM'))

#匯入金鑰檔案
key = ECC.import_key(f.read())

橢圓曲線Secp256r1和Secp256k1:

'''
Secp256r1(NIST P-256)
'''
#p =2^224(2^32 − 1) + 2^192 + 2^96 − 1
p = 115792089210356248762697446949407573530086143415290314195533631308867097853951
a =115792089210356248762697446949407573530086143415290314195533631308867097853948
b =41058363725152142129326129780047268409114441015993725554835256314039467401291

'''
Secp256k1(比特幣使用)
'''
#p = 2^256 − 2^32 − 2^9 − 2^8 − 2^7 − 2^6 − 2^4 − 1 = 2^256 – 2^32 – 977 
p = 115792089237316195423570985008687907853269984665640564039457584007908834671663
a = 0
b = 7

SageMath取橢圓曲線上隨機一點:

  E = EllipticCurve(GF(p),[a,b])
  E.random_point() #取橢圓曲線E上隨機一點