0


SM2椭圆曲线公钥加密/解密算法

SM2简介

SM2是非对称加密算法

它是基于椭圆曲线密码的公钥密码算法标准,其秘钥长度256bit,包含数字签名、密钥交换和公钥加密,用于替换RSA/DH/ECDSA/ECDH等国际算法。可以满足电子认证服务系统等应用需求,由国家密码管理局于2010年12月17号发布。

非对称密码算法 asymmetric cryptographic algorithm
使用公钥进行加密而使用私钥进行解密的一类密码算法,已知公钥求私钥在计算上不可行。

密钥 key
确定密码函数运算的一个参数,它用于:
a) 加密或解密变换;
b) 同步产生共享秘密;
c) 数字签名的生成或验证。

私钥 private key
在非对称密码体制中,实体自己保持的、只有实体自身知道的一种密钥。

公钥 public key
在非对称密码体制中,实体的一种可以公开的密钥。

秘密密钥 secret key
在密码体制中收发双方共同拥有的、而第三方不知道的一种密钥。

杂凑函数 hash function
将一个比特串映射为一个固定长度比特串的函数。该函数满足如下性质:
a) 对于任意给定的输出,要找到其对应的输入,在计算上是不可行的;
b) 对于任意给定的输入,要找到输出相同的另一个输入,在计算上是不可行的。
杂凑函数的输出为杂凑值 hash value
注:计算可行性依赖于具体的安全需求和环境。

密钥派生函数(KDF) key derivation function
通过作用于共享秘密和双方都知道的其它参数,产生一个或多个共享秘密密钥的函数。

作用是从一个共享的秘密比特串中派生出密钥数据。在密钥协商过程中,密钥派生函数作用在密钥交换所获共享的秘密比特串上,从中产生所需的会话密钥或进一步加密所需的密钥数据。
密钥派生函数需要调用密码杂凑函数。
设密码杂凑函数为Hv( ),其输出是长度恰为v比特的杂凑值。

密钥派生函数

    K
   
   
    D
   
   
    F
   
   
    (
   
   
    Z
   
   
    ,
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    )
   
  
  
   KDF(Z, klen)
  
 
KDF(Z,klen):

输入:比特串Z,整数klen(表示要获得的密钥数据的比特长度,要求该值小于

    (
   
   
    232
   
   
    −
   
   
    1
   
   
    )
   
   
    v
   
   
    )
   
  
  
   (232-1)v)
  
 
(232−1)v)。

输出:长度为

    k
   
   
    l
   
   
    e
   
   
    n
   
  
  
   klen
  
 
klen的密钥数据比特串K。

a)初始化一个32比特构成的计数器

    c
   
   
    t
   
   
    =
   
   
    0
   
   
    x
   
   
    00000001
   
  
  
   ct=0x00000001
  
 
ct=0x00000001;

b)对i从1到

    ⌈
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
   
    ⌉
   
  
  
   ⌈klen/v⌉
  
 
⌈klen/v⌉执行:

b.1)计算

    H
   
   
    a
   
   
    i
   
   
    =
   
   
    H
   
   
    v
   
   
    (
   
   
    Z
   
   
    ∣
   
   
    ∣
   
   
    c
   
   
    t
   
   
    )
   
  
  
   Hai=Hv(Z || ct)
  
 
Hai=Hv(Z∣∣ct);

b.2)

    c
   
   
    t
   
   
    +
   
   
    +
   
  
  
   ct++
  
 
ct++;

c)若

    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
  
  
   klen/v
  
 
klen/v是整数,令

 
  
   
    H
   
   
    a
   
   
    !
   
   
    ⌈
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
   
    ⌉
   
   
    =
   
   
    H
   
   
    a
   
   
    ⌈
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
   
    ⌉
   
   
    ,否则令
   
   
    H
   
   
    a
   
   
    !
   
   
    ⌈
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
   
    ⌉
   
   
    为
   
   
    H
   
   
    a
   
   
    ⌈
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
   
    ⌉
   
   
    最左边的
   
   
    (
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    −
   
   
    (
   
   
    v
   
   
    ×
   
   
    ⌊
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
   
    ⌋
   
   
    )
   
   
    )
   
   
    比特
   
  
  
   Ha!⌈klen/v⌉ = Ha⌈klen/v⌉,否则令Ha!⌈klen/v⌉为Ha⌈klen/v⌉最左边的(klen − (v × ⌊klen/v⌋))比特
  
 
Ha!⌈klen/v⌉=Ha⌈klen/v⌉,否则令Ha!⌈klen/v⌉为Ha⌈klen/v⌉最左边的(klen−(v×⌊klen/v⌋))比特;

d)令

    K
   
   
    =
   
   
    H
   
   
    a
   
   
    1
   
   
    ∣
   
   
    ∣
   
   
    H
   
   
    a
   
   
    2
   
   
    ∣
   
   
    ∣
   
   
    ⋅
   
   
    ⋅
   
   
    ⋅
   
   
    ∣
   
   
    ∣
   
   
    H
   
   
    a
   
   
    ⌈
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
   
    ⌉
   
   
    −
   
   
    1
   
   
    ∣
   
   
    ∣
   
   
    H
   
   
    a
   
   
    !
   
   
    ⌈
   
   
    k
   
   
    l
   
   
    e
   
   
    n
   
   
    /
   
   
    v
   
   
    ⌉
   
  
  
   K = Ha1||Ha2|| · · · ||Ha⌈klen/v⌉−1||Ha!⌈klen/v⌉
  
 
K=Ha1∣∣Ha2∣∣⋅⋅⋅∣∣Ha⌈klen/v⌉−1∣∣Ha!⌈klen/v⌉

**

      P
     
     
      b
     
    
   
   
    P_b
   
  
 Pb​为用户B的公钥,
 
  
   
    
     
      d
     
     
      B
     
    
   
   
    d_B
   
  
 dB​为用户B的私钥**

加密算法

设需要发送的消息为比特串M,klen为M的比特长度。
为了对明文M进行加密,作为加密者的用户A应实现以下运算步骤:
A1:用随机数发生器产生随机数k∈[1,n-1];
A2:计算椭圆曲线点C1=[k]G=(x1,y1),将C1的数据类型转换为比特串;
A3:计算椭圆曲线点S=[h]PB,若S是无穷远点,则报错并退出;
A4:计算椭圆曲线点[k]PB=(x2,y2),将坐标x2、y2 的数据类型转换为比特串;
A5:计算t=KDF(x2 || y2, klen),若t为全0比特串,则返回A1;
A6:计算C2 = M ⊕ t;
A7:计算C3 =Hash(x2 || M || y2);
A8:输出密文C = C1 || C2 || C3。

解密算法

设klen为密文中C2的比特长度。
为了对密文C=C1 || C2 || C3 进行解密,作为解密者的用户B应实现以下运算步骤:
B1:从C中取出比特串C1,将C1的数据类型转换为椭圆曲线上的点,验证C1是否满足椭圆曲线方程,若不满足则报错并退出;
B2:计算椭圆曲线点S=[h]C1,若S是无穷远点,则报错并退出;
B3:计算[dB]C1=(x2,y2),将坐标x2、y2的数据类型转换为比特串;
B4:计算t=KDF(x2 || y2, klen),若t为全0比特串,则报错并退出;
B5:从C中取出比特串C2,计算M′ = C2 ⊕ t;
B6:计算u = Hash(x2 || M′ || y2),从C中取出比特串C3,若u ≠ C3,则报错并退出;
B7:输出明文M′。

具体细节参考
国家密码管理局关于发布《SM2椭圆曲线公钥密码算法》公告

加密和解密具体示例

椭圆曲线方程为:

     y
    
    
     2
    
   
   
    =
   
   
    
     x
    
    
     3
    
   
   
    +
   
   
    a
   
   
    x
   
   
    +
   
   
    b
   
  
  
   y^2 = x^3 + ax + b
  
 
y2=x3+ax+b

示例1:

     F
    
    
     p
    
   
   
    −
   
   
    256
   
  
  
   F_p-256
  
 
Fp​−256
素数p:
8542D69E 4C044F18 E8B92435 BF6FF7DE 45728391 5C45517D 722EDB8B 08F1DFC3
系数a:
787968B4 FA32C3FD 2417842E 73BBFEFF 2F3C848B 6831D7E0 EC65228B 3937E498
系数b:
63E4C6D3 B23B0C84 9CF84241 484BFE48 F61D59A5 B16BA06E 6E12D1DA 27C5249A
基点G=(xG,yG),其阶记为n。
坐标xG:
421DEBD6 1B62EAB6 746434EB C3CC315E 32220B3B ADD50BDC 4C4E6C14 7FEDD43D
坐标yG:
0680512B CBB42C07 D47349D2 153B70C4 E5D7FDFC BFA36EA1 A85841B9 E46E09A2
阶n:
8542D69E 4C044F18 E8B92435 BF6FF7DD 29772063 0485628D 5AE74EE7 C32E79B7

待加密的消息M:encryption standard

消息M的16进制表示:656E63 72797074 696F6E20 7374616E 64617264

私钥dB:
1649AB77 A00637BD 5E2EFE28 3FBF3535 34AA7F7C B89463F2 08DDBC29 20BB0DA0
公钥PB=(xB,yB):
坐标xB:
435B39CC A8F3B508 C1488AFC 67BE491A 0F7BA07E 581A0E48 49A5CF70 628A7E0A
坐标yB:
75DDBA78 F15FEECB 4C7895E2 C1CDF5FE 01DEBB2C DBADF453 99CCF77B BA076A42

加密各步骤中的有关值:

产生随机数k:
4C62EEFD 6ECFC2B9 5B92FD6C 3D957514 8AFA1742 5546D490 18E5388D 49DD7B4F
计算椭圆曲线点C1=[k]G=(x1,y1):
坐标x1:
245C26FB 68B1DDDD B12C4B6B F9F2B6D5 FE60A383 B0D18D1C 4144ABF1 7F6252E7
坐标y1:
76CB9264 C2A7E88E 52B19903 FDC47378 F605E368 11F5C074 23A24B84 400F01B8

在此C1选用未压缩的表示形式,点转换成字节串的形式为

    P
   
   
    C
   
   
    ∥
   
   
    
     x
    
    
     1
    
   
   
    ∥
   
   
    
     y
    
    
     1
    
   
  
  
   P C∥x_1∥y_1
  
 
PC∥x1​∥y1​,其中

 
  
   
    P
   
   
    C
   
  
  
   P C
  
 
PC为单一字节


 
  
   
    且
   
   
    P
   
   
    C
   
   
    =
   
   
    04
   
  
  
   且P C=04
  
 
且PC=04,仍记为C1。

计算椭圆曲线点

    [
   
   
    k
   
   
    ]
   
   
    P
   
   
    B
   
   
    =
   
   
    (
   
   
    x
   
   
    2
   
   
    ,
   
   
    y
   
   
    2
   
   
    )
   
   
    :
   
  
  
   [k]PB=(x2,y2):
  
 
[k]PB=(x2,y2):
坐标x2:
64D20D27 D0632957 F8028C1E 024F6B02 EDF23102 A566C932 AE8BD613 A8E865FE
坐标y2:
58D225EC A784AE30 0A81A2D4 8281A828 E1CEDF11 C4219099 84026537 5077BF78
消息M的比特长度klen=152
计算t=KDF(x2||y2, klen):
006E30 DAE231B0 71DFAD8A A379E902 64491603
计算C2=M⊕t:
650053 A89B41C4 18B0C3AA D00D886C 00286467
计算C3=Hash(x2 || M || y2): x2 || M || y2:
64D20D27 D0632957 F8028C1E 024F6B02 EDF23102 A566C932 AE8BD613 A8E865FE
656E6372 79707469 6F6E2073 74616E64 61726458 D225ECA7 84AE300A 81A2D482
81A828E1 CEDF11C4 21909984 02653750 77BF78
C3:
9C3D7360 C30156FA B7C80A02 76712DA9 D8094A63 4B766D3A 285E0748 0653426D

输出密文

    C
   
   
    =
   
   
    C
   
   
    1
   
   
    ∥
   
   
    C
   
   
    2
   
   
    ∥
   
   
    C
   
   
    3
   
   
    :
   
  
  
   C = C1∥C2∥C3:
  
 
C=C1∥C2∥C3:
04245C26 FB68B1DD DDB12C4B 6BF9F2B6 D5FE60A3 83B0D18D 1C4144AB F17F6252
E776CB92 64C2A7E8 8E52B199 03FDC473 78F605E3 6811F5C0 7423A24B 84400F01
B8650053 A89B41C4 18B0C3AA D00D886C 00286467 9C3D7360 C30156FA B7C80A02
76712DA9 D8094A63 4B766D3A 285E0748 0653426D

解密各步骤中的有关值:
计算椭圆曲线点

    [
   
   
    d
   
   
    B
   
   
    ]
   
   
    C
   
   
    1
   
   
    =
   
   
    (
   
   
    x
   
   
    2
   
   
    ,
   
   
    y
   
   
    2
   
   
    )
   
   
    :
   
  
  
   [dB]C1=(x2, y2):
  
 
[dB]C1=(x2,y2):
坐标x2:
64D20D27 D0632957 F8028C1E 024F6B02 EDF23102 A566C932 AE8BD613 A8E865FE
坐标y2:
58D225EC A784AE30 0A81A2D4 8281A828 E1CEDF11 C4219099 84026537 5077BF78
计算t = KDF(x2||y2,klen):
006E30 DAE231B0 71DFAD8A A379E902 64491603
计算M′ = C2 ⊕ t:
656E63 72797074 696F6E20 7374616E 64617264
计算u =Hash(x2||M′||y2):
9C3D7360 C30156FA B7C80A02 76712DA9 D8094A63 4B766D3A 285E0748 0653426D

明文M′:656E63 72797074 696F6E20 7374616E 64617264,即为:encryption standard

SM2密钥生成以及加密解密具体代码示例

from gmssl import sm2
import random
import math

defSM2_enc(plaintext, pk):
    ciphertext = sm2_crypt.encrypt(plaintext)return ciphertext

# SM2 decryptiondefSM2_dec(ciphertext, sk):
    plaintext = sm2_crypt.decrypt(ciphertext)return plaintext

# SM2 experiment with string# 密钥生成# key generationdefSM2_Mulyipoint(k, P, a, p):# 多倍点运算
    k_b =bin(k).replace('0b','')# 按2^i分层逐层运算
    i =len(k_b)-1
    R = P
    if i >0:
        k = k -2** i
        while i >0:
            R = SM2_Pluspoint(R, R, a, p)
            i -=1if k >0:
            R = SM2_Pluspoint(R, SM2_Mulyipoint(k, P, a, p), a, p)return R

defSM2_Pluspoint(P, Q, a, p):# 双倍点运算if(math.isinf(P[0])or math.isinf(P[1]))and(~math.isinf(Q[0])and~math.isinf(Q[1])):# OP = P
        R = Q
    elif(~math.isinf(P[0])and~math.isinf(P[1]))and(math.isinf(Q[0])or math.isinf(Q[1])):# PO = P
        R = P
    elif(math.isinf(P[0])or math.isinf(P[1]))and(math.isinf(Q[0])or math.isinf(Q[1])):# OO = O
        R =[float('inf'),float('inf')]else:if P != Q:
            l = SM2__Mod_Decimal(Q[1]- P[1], Q[0]- P[0], p)else:
            l = SM2__Mod_Decimal(3* P[0]**2+ a,2* P[1], p)
        x = SM2_Mod(l **2- P[0]- Q[0], p)
        y = SM2_Mod(l *(P[0]- x)- P[1], p)
        R =[x, y]return R

defSM2_Mod(a, b):# 摸运算if math.isinf(a):returnfloat('inf')else:return a % b

defSM2__Mod_Decimal(n, d, b):# 小数的模运算if d ==0:
        x =float('inf')elif n ==0:
        x =0else:
        a =bin(b -2).replace('0b','')
        y =1
        i =0while i <len(a):# n/d = x mod b => x = n*d^(b-2) mod b
            y =(y **2)% b  # 快速指数运算if a[i]=='1':
                y =(y * d)% b
            i +=1
        x =(y * n)% b
    return x

defkey_gen(a, p, n, G):# SM2密钥对的生成

    sk = random.randint(1, n -2)
    pk = SM2_Mulyipoint(sk, G, a, p)return sk, pk

defwrite_key():
    p =0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF
    a =0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC
    b =0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93
    n =0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
    Gx =0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7
    Gy =0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
    G =[Gx, Gy][sk, pk]= key_gen(a, p, n, G)
    fw =open("D:/d_B.txt",'w')
    fw.write("%X"% sk)

    fw =open("D:/P_B.txt",'w')
    fw.write("%X%X"%(pk[0], pk[1]))defexp_SM2_str(plaintext):
    plaintext_bytes =bytes(plaintext, encoding="utf8")return plaintext_bytes

if __name__ =='__main__':
    write_key()
    sf =open("D:\d_B.txt")
    sk =(sf.read())print("sk为:", sk)
    f =open("D:\P_B.txt")
    pk =(f.read())print("pk为:", pk)

    sm2_crypt = sm2.CryptSM2(public_key=pk, private_key=sk)print("请输入需要加密的内容:")
    plaintext =(input())
    plaintext_bytes = exp_SM2_str(plaintext)
    ciphertext = SM2_enc(plaintext_bytes, pk)print("密文为:", ciphertext)
    plaintext = SM2_dec(ciphertext, sk)print("明文为:", plaintext)

SM2椭圆曲线公钥密码算法推荐曲线参数

推荐使用素数域256位椭圆曲线。
椭圆曲线方程:

     y
    
    
     2
    
   
   
    =
   
   
    
     x
    
    
     3
    
   
   
    +
   
   
    a
   
   
    x
   
   
    +
   
   
    b
   
  
  
   y^2 = x^3 + ax + b
  
 
y2=x3+ax+b。

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

参考

https://sca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml
Python 在gmssl 下完成国密算法 SM2 十六进制公钥密钥随机生成

标签: 算法 安全

本文转载自: https://blog.csdn.net/tcsnMFSheng/article/details/126207375
版权归原作者 AHlien 所有, 如有侵权,请联系我们删除。

“SM2椭圆曲线公钥加密/解密算法”的评论:

还没有评论