生活随笔
收集整理的這篇文章主要介紹了
国密SM2/SM3算法在单片机平台上的实现(C语言)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最新發現資源文件中sm2.c 654行(KDF函數中)的i++需要刪除,現在CSDN付費資源不能修改,請下載的同學自行刪除這行,十分抱歉!
?????在網上搜過關于SM2/SM3的資源,很少有在單片機上實現的代碼。主要是因為大數運算基本都用 Miracl/Openssl庫,移植到嵌入式平臺上很麻煩。所以索性自己動手寫了一下Fp域(質數域)下的SM2算法實現(動態申請內存)。包括SM2算法三步曲——數字簽名,秘鑰交換和公鑰加密,以及SM3哈希雜湊算法的實現。由于SM3算法比較簡單,所以本文主要介紹SM2算法。本文所有代碼參考國家密碼管理局官方文檔https://sca.gov.cn/sca/xwdt/2010-12/17/1002386/files/b791a9f908bb4803875ab6aeeb7b4e03.pdf 完整代碼點這里。有任何問題可以私信聯系。
1. 國密SM2介紹
?????SM2是國家密碼管理局于2010年12月17日發布的橢圓曲線公鑰密碼算法。SM2算法和RSA算法都是公鑰密碼算法,SM2算法是一種更先進安全的算法,在我們國家商用密碼體系中被用來替換RSA算法。SM2是ECC(Elliptic Curve Cryptosystem)算法的一種,基于橢圓曲線離散對數問題,計算復雜度是指數級,求解難度較大,同等安全程度要求下,橢圓曲線密碼較其他公鑰秒速昂發所需密鑰長度小很多。
?????隨著密碼技術和計算機技術的發展,目前常用的1024位RSA算法面臨嚴重的安全威脅,我們國家密碼管理部門經過研究,決定采用SM2橢圓曲線算法替換RSA算法。
2. SM2數字簽名算法
?????數字簽名算法由一個簽名者對數據產生數字簽名,并由一個驗證者驗證簽名的可靠性。每個簽名者有一個公鑰和一個私鑰,其中私鑰用于產生簽名,驗證者用簽名者的公鑰驗證簽名。在簽名的生成過程之前,要用密碼雜湊函數對M ̄\overline{M}M (包含ZA_AA?和待簽消息M)進行壓縮;在驗證過程之前,要用密碼雜湊函數對M ̄\overline{M}M’(包含ZA_AA?和驗證消息M′)進行壓縮。
2.1 數字簽名生成算法流程:
1. SM2Signature
* SM2Sign(char* message
, int messageSizeInBit
, char* IDA
, uint16_t ENTLAInBit
, EccPoint
* G
, EccPoint
* pubKey
, uint64_t* privKey
)
2. {
3.
4. uint8_t* Z
= malloc(2 + ENTLAInBit
/ 8 + 32 + 32 + 32 + 32 + 32 + 32), * ZA
= malloc(32);
5. uint256_t tmpN
= { 0 };
6. SM2Signature
* result
= malloc(sizeof(SM2Signature
));
7.
8. for (int i
= 0; i
< 4; i
++)
9. {
10. tmpN
[i
] = ellipticCurve_n
[3 - i
];
11. }
12. Z
[0] = ENTLAInBit
>> 8;
13. Z
[1] = ENTLAInBit
& 0xff;
14. memcpy(Z
+ 2, IDA
, ENTLAInBit
/ 8);
15. Uint256ToString(ZA
, Ec
->a
);
16. memcpy(Z
+ 2 + ENTLAInBit
/ 8, ZA
, 32);
17. Uint256ToString(ZA
, Ec
->b
);
18. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32, ZA
, 32);
19. Uint256ToString(ZA
, G
->x
);
20. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32 * 2, ZA
, 32);
21. Uint256ToString(ZA
, G
->y
);
22. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32 * 3, ZA
, 32);
23. Uint256ToString(ZA
, pubKey
->x
);
24. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32 * 4, ZA
, 32);
25. Uint256ToString(ZA
, pubKey
->y
);
26. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32 * 5, ZA
, 32);
27. SM3(Z
, 2 + ENTLAInBit
/ 8 + 32 + 32 + 32 + 32 + 32 + 32, ZA
);
28. free(Z
);
29.
30. uint8_t* M_
= malloc(messageSizeInBit
/ 8 + 32), * e
= malloc(32);
31. memcpy(M_
, ZA
, 32);
32. memcpy(M_
+ 32, message
, messageSizeInBit
/ 8);
33. SM3(M_
, messageSizeInBit
/ 8 + 32, e
);
34. free(M_
);
35.
36. uint8_t* x1
= malloc(32), * y1
= malloc(32), * r
= malloc(32), * s
= malloc(32);
37. uint256_t randomK
= { 0 }, tmpE
= { 0 }, tmpX
= { 0 }, tmpR
= { 0 }, num1
= { 1 };
38. EccPoint
* point1
= malloc(sizeof(EccPoint
));
39. GetRandomNumber(randomK
, tmpN
);
40. #ifdef DEBUG_MODE
41. for (int i
= 0; i
< 4; i
++)
42. {
43. randomK
[i
] = exRandomK
[3 - i
];
44. }
45. #endif
46.
47. CurvePointMul(point1
, G
, randomK
);
48. Uint256ToString(x1
, point1
->x
);
49. Uint256ToString(y1
, point1
->y
);
50. free(point1
);
51. StringToUint256(tmpE
, e
);
52. StringToUint256(tmpX
, x1
);
53. vli_modAdd(tmpR
, tmpE
, tmpX
, tmpN
);
54. Uint256ToString(r
, tmpR
);
55.
56. vli_modAdd(tmpE
, num1
, privKey
, tmpN
);
57. vli_modInv(tmpX
, tmpE
, tmpN
);
58. vli_modMult(tmpE
, tmpR
, privKey
, tmpN
);
59. vli_modSub(tmpE
, randomK
, tmpE
, tmpN
);
60. vli_modMult(tmpX
, tmpX
, tmpE
, tmpN
);
61. Uint256ToString(s
, tmpX
);
62. memcpy(result
->r
, r
, 32);
63. memcpy(result
->s
, s
, 32);
64. free(ZA
);
65. free(e
);
66. free(x1
);
67. free(y1
);
68. free(r
);
69. free(s
);
70.
71. return result
;
72. }
2.2 數字簽名的驗證算法及流程
注:如果ZA_AA?不是用戶A所對應的雜湊值,驗證自然通不過。
1. BOOL
SM2SignatureVerify(char* message
, int messageSizeInBit
, SM2Signature
* sign
, char* IDA
, uint16_t ENTLAInBit
, EccPoint
* G
, EccPoint
* pubKey
)
2. {
3. uint256_t tmp
= { 0 }, tmpN
= { 0 }, num1
= { 1 };
4.
5. for (int i
= 0; i
< 4; i
++)
6. {
7. tmpN
[i
] = ellipticCurve_n
[3 - i
];
8. }
9. vli_modSub(tmpN
, tmpN
, num1
, Ec
->p
);
10. StringToUint256(tmp
, sign
->r
);
11. if (IsZeroUint256(tmp
) || vli_cmp(tmp
, tmpN
) >= 0)
12. {
13. return FALSE
;
14. }
15. StringToUint256(tmp
, sign
->s
);
16. if (IsZeroUint256(tmp
) || vli_cmp(tmp
, tmpN
) >= 0)
17. {
18. return FALSE
;
19. }
20. vli_modAdd(tmpN
, tmpN
, num1
, Ec
->p
);
21.
22.
23. uint8_t* Z
= malloc(2 + ENTLAInBit
/ 8 + 32 + 32 + 32 + 32 + 32 + 32), * ZA
= malloc(32);
24.
25. Z
[0] = ENTLAInBit
>> 8;
26. Z
[1] = ENTLAInBit
& 0xff;
27. memcpy(Z
+ 2, IDA
, ENTLAInBit
/ 8);
28. Uint256ToString(ZA
, Ec
->a
);
29. memcpy(Z
+ 2 + ENTLAInBit
/ 8, ZA
, 32);
30. Uint256ToString(ZA
, Ec
->b
);
31. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32, ZA
, 32);
32. Uint256ToString(ZA
, G
->x
);
33. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32 * 2, ZA
, 32);
34. Uint256ToString(ZA
, G
->y
);
35. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32 * 3, ZA
, 32);
36. Uint256ToString(ZA
, pubKey
->x
);
37. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32 * 4, ZA
, 32);
38. Uint256ToString(ZA
, pubKey
->y
);
39. memcpy(Z
+ 2 + ENTLAInBit
/ 8 + 32 * 5, ZA
, 32);
40. SM3(Z
, 2 + ENTLAInBit
/ 8 + 32 + 32 + 32 + 32 + 32 + 32, ZA
);
41. free(Z
);
42.
43. uint8_t* M_
= malloc(messageSizeInBit
/ 8 + 32), * e
= malloc(32);
44. memcpy(M_
, ZA
, 32);
45. memcpy(M_
+ 32, message
, messageSizeInBit
/ 8);
46. SM3(M_
, messageSizeInBit
/ 8 + 32, e
);
47. free(M_
);
48.
49. uint256_t tmpR
= { 0 }, tmpS
= { 0 }, tmpT
= { 0 };
50.
51. StringToUint256(tmpR
, sign
->r
);
52. StringToUint256(tmpS
, sign
->s
);
53. vli_modAdd(tmpT
, tmpR
, tmpS
, tmpN
);
54.
55. EccPoint
* point0
= malloc(sizeof(EccPoint
)), * point00
= malloc(sizeof(EccPoint
)),
56. * point1
= malloc(sizeof(EccPoint
));
57.
58. CurvePointMul(point0
, G
, tmpS
);
59. CurvePointMul(point00
, pubKey
, tmpT
);
60. CurvePointAdd(point1
, point0
, point00
);
61. free(point0
);
62. free(point00
);
63.
64. uint8_t* r
= malloc(32);
65. StringToUint256(tmpT
, e
);
66. vli_modAdd(tmpR
, tmpT
, point1
->x
, tmpN
);
67. Uint256ToString(r
, tmpR
);
68. free(ZA
);
69. free(e
);
70. free(point1
);
71.
72. for (int i
= 0; i
< 32; i
++)
73. {
74. if (r
[i
] != sign
->r
[i
])
75. {
76. free(r
);
77. return FALSE
;
78. }
79. }
80. free(r
);
81. return TRUE
;
82. }
3. 秘鑰交換協議
?????密鑰交換協議是兩個用戶A和B通過交互的信息傳遞,用各自的私鑰和對方的公鑰來商定一個只有他們知道的秘密密鑰。這個共享的秘密密鑰通常用在某個對稱密碼算法中。該密鑰交換協議能夠用于密鑰管理和協商。
注:如果ZA_AA?、ZB_BB?不是用戶A和B所對應的雜湊值,則自然不能達成一致的共享秘密值。
1. BOOL KeyExchangeCheck
= TRUE
;
2. BOOL
SM2KeyExchange(char* IDA
, uint32_t ENTLAInBit
, char* IDB
, uint32_t ENTLBInBit
, EccPoint
* G
, int klenInBit
)
3. {
4. EccPoint
* RA
= malloc(sizeof(EccPoint
)), * V
= malloc(sizeof(EccPoint
)),
5. * U
= malloc(sizeof(EccPoint
)),
6. * pubKeyA
= malloc(sizeof(EccPoint
)), * pubKeyB
= malloc(sizeof(EccPoint
)),
7. * RB
= malloc(sizeof(EccPoint
));
8. uint256_t tB
= { 0 }, privKeyA
= { 0 }, privKeyB
= { 0 };
9. uint8_t* tmp
= malloc(2 + ENTLAInBit
/ 8 + 32 * 6), * tmp1
= malloc(32);
10.
11. GenerateKeys(privKeyA
, pubKeyA
, G
);
12. GenerateKeys(privKeyB
, pubKeyB
, G
);
13. if (!(IsValidPoint(pubKeyA
, Ec
) && IsValidPoint(pubKeyB
, Ec
)))
14. {
15. return FALSE
;
16. }
17.
18. #ifdef DEBUG_MODE
19. for (int i
= 0; i
< 4; i
++)
20. {
21. privKeyA
[i
] = exPrivateKey_A
[3 - i
];
22. privKeyB
[i
] = exPrivateKey_B
[3 - i
];
23. pubKeyA
->x
[i
] = exPublicKey_Ax
[3 - i
];
24. pubKeyA
->y
[i
] = exPublicKey_Ay
[3 - i
];
25. pubKeyB
->x
[i
] = exPublicKey_Bx
[3 - i
];
26. pubKeyB
->y
[i
] = exPublicKey_By
[3 - i
];
27. }
28. #endif
29.
30. KeyExchangeAOriginalInfoDef infoA
=
31. { {0},{0},privKeyA
[0],privKeyA
[1],privKeyA
[2],privKeyA
[3],pubKeyA
,pubKeyB
,0,1,{0},G
};
32. KeyExchangeBOriginalInfoDef infoB
=
33. { {0},{0},privKeyB
[0],privKeyB
[1],privKeyB
[2],privKeyB
[3],pubKeyA
,pubKeyB
,0,1,{0},G
};
34.
35. for (int i
= 0; i
< 4; i
++)
36. {
37. infoA
.n
[i
] = ellipticCurve_n
[3 - i
];
38. infoB
.n
[i
] = ellipticCurve_n
[3 - i
];
39. }
40. infoA
.w
= (int)(GetMSB(infoA
.n
) / 2 + 1) - 1;
41. infoB
.w
= infoA
.w
;
42.
43. tmp
[0] = ENTLAInBit
>> 8;
44. tmp
[1] = ENTLAInBit
& 0xff;
45. memcpy(tmp
+ 2, IDA
, ENTLAInBit
/ 8);
46. Uint256ToString(tmp1
, Ec
->a
);
47. memcpy(tmp
+ 2 + ENTLAInBit
/ 8, tmp1
, 32);
48. Uint256ToString(tmp1
, Ec
->b
);
49. memcpy(tmp
+ 2 + ENTLAInBit
/ 8 + 32, tmp1
, 32);
50. Uint256ToString(tmp1
, G
->x
);
51. memcpy(tmp
+ 2 + ENTLAInBit
/ 8 + 32 * 2, tmp1
, 32);
52. Uint256ToString(tmp1
, G
->y
);
53. memcpy(tmp
+ 2 + ENTLAInBit
/ 8 + 32 * 3, tmp1
, 32);
54. Uint256ToString(tmp1
, pubKeyA
->x
);
55. memcpy(tmp
+ 2 + ENTLAInBit
/ 8 + 32 * 4, tmp1
, 32);
56. Uint256ToString(tmp1
, pubKeyA
->y
);
57. memcpy(tmp
+ 2 + ENTLAInBit
/ 8 + 32 * 5, tmp1
, 32);
58. SM3(tmp
, 2 + ENTLAInBit
/ 8 + 32 * 6, infoA
.ZA
);
59. memcpy(infoB
.ZA
, infoA
.ZA
, 32);
60.
61. tmp
[0] = ENTLBInBit
>> 8;
62. tmp
[1] = ENTLBInBit
& 0xff;
63. memcpy(tmp
+ 2, IDB
, ENTLBInBit
/ 8);
64. Uint256ToString(tmp1
, Ec
->a
);
65. memcpy(tmp
+ 2 + ENTLBInBit
/ 8, tmp1
, 32);
66. Uint256ToString(tmp1
, Ec
->b
);
67. memcpy(tmp
+ 2 + ENTLBInBit
/ 8 + 32, tmp1
, 32);
68. Uint256ToString(tmp1
, G
->x
);
69. memcpy(tmp
+ 2 + ENTLBInBit
/ 8 + 32 * 2, tmp1
, 32);
70. Uint256ToString(tmp1
, G
->y
);
71. memcpy(tmp
+ 2 + ENTLBInBit
/ 8 + 32 * 3, tmp1
, 32);
72. Uint256ToString(tmp1
, pubKeyB
->x
);
73. memcpy(tmp
+ 2 + ENTLBInBit
/ 8 + 32 * 4, tmp1
, 32);
74. Uint256ToString(tmp1
, pubKeyB
->y
);
75. memcpy(tmp
+ 2 + ENTLBInBit
/ 8 + 32 * 5, tmp1
, 32);
76. SM3(tmp
, 2 + ENTLBInBit
/ 8 + 32 * 6, infoB
.ZB
);
77. memcpy(infoA
.ZB
, infoB
.ZB
, 32);
78. free(tmp
);
79. free(tmp1
);
80.
81. uint256_t rA
= { 0 };
82. SM2KeyExchange_AStep1To3(RA
, rA
, infoA
);
83.
84. SM2KeyExchange_BStep1To4(tB
, RB
, infoB
);
85. if (!IsValidPoint(RA
, Ec
))
86. {
87. return FALSE
;
88. }
89. SM2KeyExchange_BStep5To6(V
, tB
, RA
, infoB
);
90. if (IsZeroPoint(V
))
91. {
92. return FALSE
;
93. }
94.
95. uint8_t* SB
= malloc(32), * KB
= malloc(klenInBit
/ 8);
96. SM2KeyExchange_BStep7To9(KB
, SB
, *V
, klenInBit
, *RA
, *RB
, infoB
);
97.
98. uint256_t tA
= { 0 };
99. SM2KeyExchange_AStep4To5(tA
, RA
, rA
, infoA
);
100.
101. if (IsZeroPoint(RB
))
102. {
103. return FALSE
;
104. }
105.
106. SM2KeyExchange_AStep6To7(U
, tA
, RB
, infoA
);
107. if (IsZeroPoint(U
))
108. {
109. return FALSE
;
110. }
111. uint8_t* S1
= malloc(32), * KA
= malloc(klenInBit
/ 8);
112. SM2KeyExchange_AStep8To9(KA
, S1
, *U
, klenInBit
, *RA
, *RB
, infoA
);
113.
114. if (KeyExchangeCheck
)
115. {
116. for (int i
= 0; i
< 32; i
++)
117. {
118. if (S1
[i
] != SB
[i
])
119. {
120. return FALSE
;
121. }
122. }
123. }
124.
125. uint8_t* SA
= malloc(32);
126. SM2KeyExchange_AStep10(SA
, *U
, *RA
, *RB
, infoA
);
127.
128. uint8_t* S2
= malloc(32);
129. SM2KeyExchange_BStep10(S2
, *V
, *RA
, *RB
, infoB
);
130.
131. if (KeyExchangeCheck
)
132. {
133. for (int i
= 0; i
< 32; i
++)
134. {
135. if (S2
[i
] != SA
[i
])
136. {
137. return FALSE
;
138. }
139. }
140. }
141. free(RA
);
142. free(V
);
143. free(U
);
144. free(pubKeyA
);
145. free(pubKeyB
);
146. free(RB
);
147. free(SB
);
148. free(KB
);
149. free(S1
);
150. free(KA
);
151. free(SA
);
152. free(S2
);
153.
154. return TRUE
;
155. }
4. 公鑰加密算法
?????公鑰加密算法規定發送者用接收者的公鑰將消息加密成密文,接收者用自已的私鑰對收到的密文進行解密還原成原始消息。
4.1 加密算法
1. uint8_t* SM2Encrypt(char* messagePlain
, int messageSizeInBit
, EccPoint
* pubKey
)
2. {
3. uint256_t randomK
= { 0 };
4. EccPoint
* pointC1
= malloc(sizeof(EccPoint
)), * kPb
= malloc(sizeof(EccPoint
));
5. uint8_t* t
= malloc(messageSizeInBit
/ 8), * x2
= malloc(64), * y2
= malloc(32),
6. * C1
= malloc(65), * x1
= malloc(32), * y1
= malloc(32),
7. * C2
= malloc(messageSizeInBit
/ 8), * C3
= malloc(64 + messageSizeInBit
/ 8),
8. * C
= malloc(65 + messageSizeInBit
/ 8 + 32);
9. GetRandomNumber(randomK
, Ec
->p
);
10. #ifdef DEBUG_MODE
11. for (int i
= 0; i
< 4; i
++)
12. {
13. randomK
[i
] = exRandomK
[3 - i
];
14. }
15. #endif
16. CalculateC1(pointC1
, randomK
, G
);
17. Uint256ToString(x1
, pointC1
->x
);
18. Uint256ToString(y1
, pointC1
->y
);
19. C1
[0] = 0x04;
20. memcpy(C1
+ 1, x1
, 32);
21. memcpy(C1
+ 33, y1
, 32);
22.
23. CalculateKPb(kPb
, randomK
, pubKey
);
24. Uint256ToString(x2
, kPb
->x
);
25. Uint256ToString(y2
, kPb
->y
);
26.
27. memcpy(C3
, x2
, 32);
28. memcpy(C3
+ 32, messagePlain
, messageSizeInBit
/ 8);
29. memcpy(C3
+ 32 + messageSizeInBit
/ 8, y2
, 32);
30.
31. memcpy(x2
+ 32, y2
, 32);
32. KDF(t
, x2
, 64 * 8, messageSizeInBit
);
33. CalculateC2(C2
, messagePlain
, t
, messageSizeInBit
/ 8);
34. SM3((uint8_t*)C3
, 64 + messageSizeInBit
/ 8, (uint8_t*)C3
);
35.
36. memcpy(C
, C1
, 65);
37. memcpy(C
+ 65, C2
, messageSizeInBit
/ 8);
38. memcpy(C
+ 65 + messageSizeInBit
/ 8, C3
, 32);
39. free(pointC1
);
40. free(kPb
);
41. free(t
);
42. free(x2
);
43. free(y2
);
44. free(C1
);
45. free(x1
);
46. free(y1
);
47. free(C2
);
48. free(C3
);
49.
50. return C
;
51. }
4.2 解密算法
1. uint8_t* SM2Decrypt(char* C
, int lenInByte
, uint64_t* privKey
)
2. {
3. EccPoint
* pointC1
= malloc(sizeof(EccPoint
)), * point2
= malloc(sizeof(EccPoint
));
4. int lenOfMsg
= lenInByte
- 65 - 32;
5. uint8_t* C2
= malloc(lenOfMsg
+ 1), * msg
= malloc(lenOfMsg
+ 1),
6. * x1
= malloc(32), * y1
= malloc(32),
7. * x2
= malloc(64), * y2
= malloc(32), * t
= malloc(lenOfMsg
);
8.
9. msg
[lenInByte
- 65 - 32] = '\0';
10. memcpy(C2
, C
+ 65, lenInByte
- 65 - 32);
11. memcpy(x1
, C
+ 1, 32);
12. memcpy(y1
, C
+ 1 + 32, 32);
13. StringToUint256(pointC1
->x
, x1
);
14. StringToUint256(pointC1
->y
, y1
);
15. CurvePointMul(point2
, pointC1
, privKey
);
16. Uint256ToString(x2
, point2
->x
);
17. Uint256ToString(y2
, point2
->y
);
18. memcpy(x2
+ 32, y2
, 32);
19. KDF(t
, x2
, 64 * 8, (lenInByte
- 65 - 32) * 8);
20. CalculateMessage(msg
, C2
, t
, lenOfMsg
);
21. free(pointC1
);
22. free(point2
);
23. free(C2
);
24. free(x1
);
25. free(y1
);
26. free(x2
);
27. free(y2
);
28. free(t
);
29.
30. return msg
;
31. }
總結
以上是生活随笔為你收集整理的国密SM2/SM3算法在单片机平台上的实现(C语言)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。