1 前言
SM2、SM3、SM4 是中国国家密码管理局发布的商用密码算法,广泛用于国家标准的密码系统中。
关于应用场景:不绝对,可以根据使用需要选择加密算法。
1.1 SM国密算法场景
侧重点:
SM2 主要用于加密和签名。(SM2加密可逆)
SM3 主要用于数据完整性校验。(SM3加密不可逆,类似于md5)
SM4 侧重于数据加密。(SM4加密可逆)
具体场景:
SM2: 数据加密、数字签名、安全通信、身份验证、证书管理、区块链技术。
SM3: 数据完整性验证、数字签名、密码存储、区块链和加密货币、文件指纹。
SM4: 数据加密、网络安全、信息存储、移动设备和物联网、电子支付和金融服务。
通常可以结合使用。
2 SM2 椭圆曲线公钥密码算法
SM2 是基于椭圆曲线的公钥密码算法,类似于国际标准的ECC(Elliptic Curve Cryptography) 算法。
场景:密钥交换、数字签名、公钥加密等。
2.1 数据加密
公钥加密,私钥解密。
SM2 可以用于加密敏感数据,如个人信息、财务数据等。在传输数据时,可以使用接收方的公钥对数据进行加密,确保只有拥有相应私钥的接收方可以解密和访问原始数据。
具体个人信息场景:手机号、身份证等
2.2 数字签名
SM2 不仅可以用于加密数据,还可以用于数字签名。发送方使用私钥对数据进行签名,接收方可以使用发送方的公钥验证签名的真实性。这确保了数据的完整性和来源的可靠性。
2.3 安全通信
具体场景:在线支付、金融交易。
在需要安全通信的场景中(如在线支付、金融交易等),SM2 可以用于建立安全的通信通道,保护数据在传输过程中的安全性。
2.4 身份验证
SM2 可以用于身份验证,确保只有授权用户能够访问特定资源或服务。通过公钥加密挑战消息,只有拥有相应私钥的用户才能解密并响应,确认其身份。
2.5 证书管理
在 PKI(公钥基础设施)中,生成和管理数字证书,以验证公钥的所有者身份。
2.6 区块链技术
用于加密交易数据和身份信息,确保区块链参与者之间的数据交换安全可靠。
3 SM3 哈希算法
SM3是一种安全哈希算法,类似于国际上的 SHA-256。
场景:数据完整性验证、数字签名等
3.1 数据完整性验证
在传输或存储数据时,可以使用 SM3 计算数据的哈希值。接收方可以通过对接收到的数据重新计算哈希值并与原哈希值进行比较,以验证数据是否在传输过程中被篡改。
3.2 数字签名
在数字签名过程中,通常会先对待签名的数据计算哈希值,然后用私钥对哈希值进行签名。接收方通过用公钥解密签名,并重新计算数据的哈希值,以验证签名的真实性和数据的完整性。
与 SM2 一起使用,生成消息摘要,用于对数据进行数字签名。
3.3 密码存储
在用户注册或更改密码时,可以使用 SM3 哈希用户的密码并将哈希值存储在数据库中。当用户登录时,通过计算输入密码的哈希值并与存储的哈希值进行比较,从而验证用户身份。由于 SM3 是不可逆的,攻击者无法从存储的哈希值恢复原始密码。
3.4 区块链和加密货币
区块链中,每个区块都包含前一个区块的哈希值,从而形成一个链。SM3 可以用于计算区块的哈希,确保数据的不可篡改性和完整性。
在区块链技术中,SM3 用于计算区块哈希,确保区块链数据的完整性和安全性。
3.5 文件指纹/文件和数据认证
对于大文件,可以使用 SM3 生成文件的指纹(哈希值),以便在后续操作中快速比较文件是否相同,而不需要比较整个文件内容。
用于文件的哈希校验,确保文件在传输或存储过程中的安全性。
4 SM4 是一种分组对称算法
SM4是一种分组对称加密算法,类似于国际标准的 AES (Advanced Encryption Standard),它使用128位密钥进行数据加密。
场景:无线网络安全等。
4.1 数据加密
用于加密数据(如文件、消息等)以保护敏感信息,适用于存储和传输。
4.2 网络安全
在 VPN(虚拟专用网络)、SSL/TLS 等网络安全协议中,确保数据传输的安全性。
4.3 信息存储
用于数据库加密和文件系统加密,保护存储在磁盘上的敏感数据。
4.4 移动设备和物联网
适用于移动设备和 IoT 设备中的数据保护,确保数据在设备间传输时的安全性。
4.5 电子支付和金融服务
在金融行业中,确保交易数据的安全性和保密性。
5 Python 实战案例
测试环境:Python3.10.9
pip install gmssl==3.2.2
5.1 SM2 算法
深入理解 SM2、SM3 和 SM4 国密加密算法:Python 实现案例解析
SM2算法可逆。
场景:手机、身份证号等必要时间可以查询的。
from gmssl import sm2
private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'
public_key = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207'
text = "有勇氣的牛排 www.couragesteak.com"
print("原始數據:", text)
sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key, asn1=False)
data = text.encode('utf-8')
enc_data = sm2_crypt.encrypt(data)
print("加密數據: ", enc_data)
decrypted_data = sm2_crypt.decrypt(enc_data)
print("解密后數據:", decrypted_data.decode('utf-8'))

5.2 SM3 算法
SM3 哈希算法是不可逆的。
from gmssl import sm3, func
def compute_sm3_hash(data: str) -> str:
"""
计算字符串的 SM3 哈希值
:param data: 输入字符串
:return: SM3 哈希值 (16 进制字符串)
"""
data_bytes = data.encode('utf-8')
hash_value = sm3.sm3_hash(func.bytes_to_list(data_bytes))
return hash_value
if __name__ == "__main__":
input_data = "有勇氣的牛排 www.couragesteak.com"
sm3_hash = compute_sm3_hash(input_data)
print("输入数据:", input_data)
print("SM3 哈希值:", sm3_hash)

5.3 SM4 算法
from gmssl import sm4
class SM4Crypt:
def __init__(self, key: bytes, mode: str = 'ECB'):
"""
初始化 SM4 加密/解密对象
:param key: 加密密钥(16 字节长度)
:param mode: 加密模式('ECB' 或 'CBC')
"""
self.key = key
self.mode = mode
if mode == 'ECB':
self.sm4_crypt = sm4.CryptSM4(mode=sm4.SM4_ENCRYPT)
elif mode == 'CBC':
self.sm4_crypt = sm4.CryptSM4(mode=sm4.SM4_DECRYPT)
def encrypt(self, data: bytes) -> bytes:
"""
加密数据
:param data: 待加密的字节数据
:return: 加密后的字节数据
"""
self.sm4_crypt.set_key(self.key, sm4.SM4_ENCRYPT)
encrypted_data = self.sm4_crypt.crypt_ecb(data) if self.mode == 'ECB' else self.sm4_crypt.crypt_cbc(data)
return encrypted_data
def decrypt(self, enc_data: bytes) -> bytes:
"""
解密数据
:param enc_data: 加密后的字节数据
:return: 解密后的字节数据
"""
self.sm4_crypt.set_key(self.key, sm4.SM4_DECRYPT)
decrypted_data = self.sm4_crypt.crypt_ecb(enc_data) if self.mode == 'ECB' else self.sm4_crypt.crypt_cbc(
enc_data)
return decrypted_data
if __name__ == "__main__":
key = b'0123456789abcdef'
user_data = "有勇氣的牛排 www.couragesteak.com"
print("原始数据:", user_data)
sm4_util = SM4Crypt(key=key, mode='ECB')
encrypted_data = sm4_util.encrypt(user_data.encode('utf-8'))
print("加密后的数据:", encrypted_data)
decrypted_data = sm4_util.decrypt(encrypted_data)
print("解密后的数据:", decrypted_data.decode('utf-8'))

<h2><a id="1__0"></a>1 前言</h2>
<p>SM2、SM3、SM4 是中国国家密码管理局发布的商用密码算法,广泛用于国家标准的密码系统中。</p>
<p>关于应用场景:不绝对,可以根据使用需要选择加密算法。</p>
<h3><a id="11_SM_6"></a>1.1 SM国密算法场景</h3>
<p><strong>侧重点:</strong></p>
<p>SM2 主要用于加密和签名。(SM2加密可逆)</p>
<p>SM3 主要用于数据完整性校验。(SM3加密不可逆,类似于md5)</p>
<p>SM4 侧重于数据加密。(SM4加密可逆)</p>
<p><strong>具体场景:</strong></p>
<p>SM2: 数据加密、数字签名、安全通信、身份验证、证书管理、区块链技术。</p>
<p>SM3: 数据完整性验证、数字签名、密码存储、区块链和加密货币、文件指纹。</p>
<p>SM4: 数据加密、网络安全、信息存储、移动设备和物联网、电子支付和金融服务。</p>
<p>通常可以结合使用。</p>
<h2><a id="2_SM2__26"></a>2 SM2 椭圆曲线公钥密码算法</h2>
<p>SM2 是基于椭圆曲线的公钥密码算法,类似于国际标准的ECC(Elliptic Curve Cryptography) 算法。</p>
<p>场景:密钥交换、数字签名、公钥加密等。</p>
<h3><a id="21__32"></a>2.1 数据加密</h3>
<p>公钥加密,私钥解密。</p>
<p>SM2 可以用于加密敏感数据,如<strong>个人信息、财务数据</strong>等。在传输数据时,可以使用接收方的公钥对数据进行加密,确保只有拥有相应私钥的接收方可以解密和访问原始数据。</p>
<p>具体个人信息场景:手机号、身份证等</p>
<h3><a id="22__40"></a>2.2 数字签名</h3>
<p>SM2 不仅可以用于加密数据,还可以用于数字签名。发送方使用私钥对数据进行签名,接收方可以使用发送方的公钥验证签名的真实性。这确保了数据的完整性和来源的可靠性。</p>
<h3><a id="23__44"></a>2.3 安全通信</h3>
<p>具体场景:在线支付、金融交易。</p>
<p>在需要安全通信的场景中(如在线支付、金融交易等),SM2 可以用于建立安全的通信通道,保护数据在传输过程中的安全性。</p>
<h3><a id="24__50"></a>2.4 身份验证</h3>
<p>SM2 可以用于身份验证,确保只有授权用户能够访问特定资源或服务。通过公钥加密挑战消息,只有拥有相应私钥的用户才能解密并响应,确认其身份。</p>
<h3><a id="25__54"></a>2.5 证书管理</h3>
<p>在 PKI(公钥基础设施)中,生成和管理数字证书,以验证公钥的所有者身份。</p>
<h3><a id="26__58"></a>2.6 区块链技术</h3>
<p>用于加密交易数据和身份信息,确保区块链参与者之间的数据交换安全可靠。</p>
<h2><a id="3_SM3__62"></a>3 SM3 哈希算法</h2>
<p>SM3是一种安全哈希算法,类似于国际上的 SHA-256。</p>
<p>场景:数据完整性验证、数字签名等</p>
<h3><a id="31__68"></a>3.1 数据完整性验证</h3>
<p>在传输或存储数据时,可以使用 SM3 计算数据的哈希值。接收方可以通过对接收到的数据重新计算哈希值并与原哈希值进行比较,以验证数据是否在传输过程中被篡改。</p>
<h3><a id="32__72"></a>3.2 数字签名</h3>
<p>在数字签名过程中,通常会先对待签名的数据计算哈希值,然后用私钥对哈希值进行签名。接收方通过用公钥解密签名,并重新计算数据的哈希值,以验证签名的真实性和数据的完整性。</p>
<p>与 SM2 一起使用,生成消息摘要,用于对数据进行数字签名。</p>
<h3><a id="33__78"></a>3.3 密码存储</h3>
<p>在用户注册或更改密码时,可以使用 SM3 哈希用户的密码并将哈希值存储在数据库中。当用户登录时,通过计算输入密码的哈希值并与存储的哈希值进行比较,从而验证用户身份。由于 SM3 是不可逆的,攻击者无法从存储的哈希值恢复原始密码。</p>
<h3><a id="34__82"></a>3.4 区块链和加密货币</h3>
<p>区块链中,每个区块都包含前一个区块的哈希值,从而形成一个链。SM3 可以用于计算区块的哈希,确保数据的不可篡改性和完整性。</p>
<p>在区块链技术中,SM3 用于计算区块哈希,确保区块链数据的完整性和安全性。</p>
<h3><a id="35__88"></a>3.5 文件指纹/文件和数据认证</h3>
<p>对于大文件,可以使用 SM3 生成文件的指纹(哈希值),以便在后续操作中快速比较文件是否相同,而不需要比较整个文件内容。</p>
<p>用于文件的哈希校验,确保文件在传输或存储过程中的安全性。</p>
<h2><a id="4_SM4__94"></a>4 SM4 是一种分组对称算法</h2>
<p>SM4是一种分组对称加密算法,类似于国际标准的 AES (Advanced Encryption Standard),它使用128位密钥进行数据加密。</p>
<p>场景:无线网络安全等。</p>
<h3><a id="41__100"></a>4.1 数据加密</h3>
<p>用于加密数据(如文件、消息等)以保护敏感信息,适用于存储和传输。</p>
<h3><a id="42__104"></a>4.2 网络安全</h3>
<p>在 VPN(虚拟专用网络)、SSL/TLS 等网络安全协议中,确保数据传输的安全性。</p>
<h3><a id="43__108"></a>4.3 信息存储</h3>
<p>用于数据库加密和文件系统加密,保护存储在磁盘上的敏感数据。</p>
<h3><a id="44__112"></a>4.4 移动设备和物联网</h3>
<p>适用于移动设备和 IoT 设备中的数据保护,确保数据在设备间传输时的安全性。</p>
<h3><a id="45__116"></a>4.5 电子支付和金融服务</h3>
<p>在金融行业中,确保交易数据的安全性和保密性。</p>
<h2><a id="5_Python__120"></a>5 Python 实战案例</h2>
<p>测试环境:Python3.10.9</p>
<pre><div class="hljs"><code class="lang-shell">pip install gmssl==3.2.2
</code></div></pre>
<h3><a id="51_SM2__128"></a>5.1 SM2 算法</h3>
<p><a href="https://www.couragesteak.com/article/484" target="_blank">深入理解 SM2、SM3 和 SM4 国密加密算法:Python 实现案例解析</a></p>
<p>SM2算法可逆。</p>
<p>场景:手机、身份证号等必要时间可以查询的。</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-keyword">from</span> gmssl <span class="hljs-keyword">import</span> sm2
<span class="hljs-comment"># 16 进制的公钥和私钥</span>
private_key = <span class="hljs-string">'00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'</span>
public_key = <span class="hljs-string">'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207'</span>
<span class="hljs-comment"># 待加密中文字符串</span>
text = <span class="hljs-string">"有勇氣的牛排 www.couragesteak.com"</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">"原始數據:"</span>, text)
<span class="hljs-comment"># 初始化 SM2 对象</span>
sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key, asn1=<span class="hljs-literal">False</span>)
<span class="hljs-comment"># 加密数据</span>
data = text.encode(<span class="hljs-string">'utf-8'</span>) <span class="hljs-comment"># 将字符串转换为字节</span>
enc_data = sm2_crypt.encrypt(data) <span class="hljs-comment"># 进行加密</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">"加密數據: "</span>, enc_data)
<span class="hljs-comment"># 解密数据</span>
decrypted_data = sm2_crypt.decrypt(enc_data) <span class="hljs-comment"># 直接使用加密数据进行解密</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">"解密后數據:"</span>, decrypted_data.decode(<span class="hljs-string">'utf-8'</span>)) <span class="hljs-comment"># 将解密后的数据解码为字符串</span>
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/b96af6673d99a557edc83523c02fd0bc.png" alt="Python SM2算法" /></p>
<h3><a id="52_SM3__162"></a>5.2 SM3 算法</h3>
<p>SM3 哈希算法是不可逆的。</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-keyword">from</span> gmssl <span class="hljs-keyword">import</span> sm3, func
<span class="hljs-keyword">def</span> <span class="hljs-title function_">compute_sm3_hash</span>(<span class="hljs-params">data: <span class="hljs-built_in">str</span></span>) -> <span class="hljs-built_in">str</span>:
<span class="hljs-string">"""
计算字符串的 SM3 哈希值
:param data: 输入字符串
:return: SM3 哈希值 (16 进制字符串)
"""</span>
<span class="hljs-comment"># 将字符串编码为字节</span>
data_bytes = data.encode(<span class="hljs-string">'utf-8'</span>)
<span class="hljs-comment"># 计算 SM3 哈希</span>
hash_value = sm3.sm3_hash(func.bytes_to_list(data_bytes))
<span class="hljs-keyword">return</span> hash_value
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
<span class="hljs-comment"># 示例输入</span>
input_data = <span class="hljs-string">"有勇氣的牛排 www.couragesteak.com"</span>
sm3_hash = compute_sm3_hash(input_data)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"输入数据:"</span>, input_data)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"SM3 哈希值:"</span>, sm3_hash)
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/8159967650df1e15ccf570d08ef773c5.png" alt="Python SM3算法" /></p>
<h3><a id="53_SM4__194"></a>5.3 SM4 算法</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding:utf-8 -*-</span>
<span class="hljs-comment"># @Author: 有勇气的牛排</span>
<span class="hljs-comment"># 博客地址: https://www.couragesteak.com</span>
<span class="hljs-comment"># @FileName : util_sm4.py</span>
<span class="hljs-comment"># @desc : SM4 加密算法</span>
<span class="hljs-comment"># 场景:数据加密、网络安全、信息存储、移动设备和物联网、电子支付和金融服务。</span>
<span class="hljs-keyword">from</span> gmssl <span class="hljs-keyword">import</span> sm4
<span class="hljs-keyword">class</span> <span class="hljs-title class_">SM4Crypt</span>:
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, key: <span class="hljs-built_in">bytes</span>, mode: <span class="hljs-built_in">str</span> = <span class="hljs-string">'ECB'</span></span>):
<span class="hljs-string">"""
初始化 SM4 加密/解密对象
:param key: 加密密钥(16 字节长度)
:param mode: 加密模式('ECB' 或 'CBC')
"""</span>
self.key = key
self.mode = mode
<span class="hljs-keyword">if</span> mode == <span class="hljs-string">'ECB'</span>:
self.sm4_crypt = sm4.CryptSM4(mode=sm4.SM4_ENCRYPT)
<span class="hljs-keyword">elif</span> mode == <span class="hljs-string">'CBC'</span>:
self.sm4_crypt = sm4.CryptSM4(mode=sm4.SM4_DECRYPT)
<span class="hljs-keyword">def</span> <span class="hljs-title function_">encrypt</span>(<span class="hljs-params">self, data: <span class="hljs-built_in">bytes</span></span>) -> <span class="hljs-built_in">bytes</span>:
<span class="hljs-string">"""
加密数据
:param data: 待加密的字节数据
:return: 加密后的字节数据
"""</span>
self.sm4_crypt.set_key(self.key, sm4.SM4_ENCRYPT)
encrypted_data = self.sm4_crypt.crypt_ecb(data) <span class="hljs-keyword">if</span> self.mode == <span class="hljs-string">'ECB'</span> <span class="hljs-keyword">else</span> self.sm4_crypt.crypt_cbc(data)
<span class="hljs-keyword">return</span> encrypted_data
<span class="hljs-keyword">def</span> <span class="hljs-title function_">decrypt</span>(<span class="hljs-params">self, enc_data: <span class="hljs-built_in">bytes</span></span>) -> <span class="hljs-built_in">bytes</span>:
<span class="hljs-string">"""
解密数据
:param enc_data: 加密后的字节数据
:return: 解密后的字节数据
"""</span>
self.sm4_crypt.set_key(self.key, sm4.SM4_DECRYPT)
decrypted_data = self.sm4_crypt.crypt_ecb(enc_data) <span class="hljs-keyword">if</span> self.mode == <span class="hljs-string">'ECB'</span> <span class="hljs-keyword">else</span> self.sm4_crypt.crypt_cbc(
enc_data)
<span class="hljs-keyword">return</span> decrypted_data
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
<span class="hljs-comment"># SM4 密钥,必须是 16 字节(128 位)</span>
key = <span class="hljs-string">b'0123456789abcdef'</span>
<span class="hljs-comment"># 待加密的数据</span>
user_data = <span class="hljs-string">"有勇氣的牛排 www.couragesteak.com"</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">"原始数据:"</span>, user_data)
<span class="hljs-comment"># 初始化 SM4 加密类</span>
sm4_util = SM4Crypt(key=key, mode=<span class="hljs-string">'ECB'</span>)
<span class="hljs-comment"># 加密数据</span>
encrypted_data = sm4_util.encrypt(user_data.encode(<span class="hljs-string">'utf-8'</span>))
<span class="hljs-built_in">print</span>(<span class="hljs-string">"加密后的数据:"</span>, encrypted_data)
<span class="hljs-comment"># 解密数据</span>
decrypted_data = sm4_util.decrypt(encrypted_data)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"解密后的数据:"</span>, decrypted_data.decode(<span class="hljs-string">'utf-8'</span>))
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/ad99e8f5305e50a799b1b475f8e72358.png" alt="Python SM4算法" /></p>
留言