链接:
国产密码算法介绍 SM2/SM3/SM4/SM9/祖冲之ZUC
目录
一、概述
非对称加密算法(Asymmetric Encryption Algorithm)是密码学领域的重要分支之一,也被称为公钥加密算法。与传统的对称加密不同,非对称加密使用两种不同的密钥:公钥和私钥。公钥可以公开传播,任何人都可以用它加密数据或验证签名;而私钥必须严格保密,只有持有者可以使用它解密数据或生成签名。
非对称加密的核心思想是利用数学上的单向函数特性,使得即使知道公钥,也无法通过计算推导出对应的私钥。这种设计不仅解决了对称加密中密钥分发的安全问题,还为数字签名、身份验证和不可否认性等提供了技术支持。非对称加密算法广泛应用于网络安全协议(如HTTPS)、区块链技术、电子支付系统以及电子邮件加密等领域。
二、基本概念
1.公钥与私钥:
- 公钥和私钥是一对密钥,它们在数学上密切相关,但无法相互推导。
- 公钥用于加密数据或验证签名,因此可以公开分享。
- 私钥用于解密数据或生成签名,必须严格保密,否则会导致整个加密系统的失效。
2.加密与解密:
- 加密过程:发送方使用接收方的公钥加密明文数据,生成密文。
- 解密过程:接收方使用自己的私钥解密密文,恢复原始明文。
- 这种机制确保了只有持有私钥的人才能读取消息,从而实现数据的机密性。
3.数字签名:
- 数字签名是一种基于非对称加密技术的身份验证机制。
- 签名过程:发送方使用自己的私钥对消息摘要进行加密,生成签名。
- 验证过程:接收方使用发送方的公钥验证签名的有效性,确保消息的完整性和来源的真实性。
- 数字签名的应用场景包括电子邮件认证、软件发布验证、区块链交易确认等。
4.密钥交换:
- 在对称加密中,密钥需要在通信双方之间安全传输,这本身是一个难题。
- 非对称加密可以通过公钥加密的方式安全地交换对称加密的会话密钥,从而结合两者的优点:对称加密的速度和非对称加密的安全性。
三、非对称加密的特点
1.安全性高:
- 非对称加密算法通常基于数学难题设计,例如大整数分解问题(RSA)、离散对数问题(DSA、ElGamal)和椭圆曲线离散对数问题(ECC)。这些数学问题在当前计算能力下几乎无法破解,因此保证了算法的安全性。
2.无需密钥分发:
- 对称加密需要提前共享密钥,而在非对称加密中,公钥可以公开分发,无需担心泄露风险。这种特性极大地简化了密钥管理流程。
3.支持身份验证和不可否认性:
- 非对称加密通过数字签名技术实现了身份验证和不可否认性。发送方用自己的私钥生成签名,接收方用发送方的公钥验证签名。这种方式不仅可以证明消息来源的真实性,还可以防止发送方否认自己发送过该消息。
4.计算复杂度高:
- 非对称加密算法的计算开销远高于对称加密。这是因为非对称加密涉及复杂的数学运算(如模幂运算、椭圆曲线点乘法等),导致其处理速度较慢。
- 因此,非对称加密通常不直接用于大数据加密,而是用于密钥交换或数字签名等场景。
5.灵活性强:
- 非对称加密不仅可以用于加密数据,还可以用于身份验证、数字签名、密钥交换等多种用途,具有很高的灵活性。
四、工作原理
非对称加密的核心思想是使用一对密钥:公钥和私钥。这两个密钥在数学上是相关的,但不能互相推导出来。公钥可以公开分享,任何人都可以用它加密信息;私钥必须保密,只有持有者才能用它解密信息。
1. 加解密过程
密钥生成
- 首先,系统会通过一些复杂的数学运算生成一对密钥:一个叫公钥,一个叫私钥。
- 公钥是用来加密数据的,可以随便给别人。
- 私钥是用来解密数据的,必须自己保管好,绝不能泄露。
- 公钥和私钥是一对“搭档”,它们之间有特殊的数学关系。
- 用公钥加密的数据,只能用对应的私钥解密;反过来,用私钥加密的数据,也只能用对应的公钥解密。
- 即使别人知道你的公钥,他们也无法通过公钥推算出你的私钥。这是因为背后的数学运算非常复杂,目前的计算机技术几乎无法破解。
加密过程
- 假设你想给朋友发送一条秘密消息,你需要先拿到他的公钥(比如他可以直接发给你,或者从某个安全的地方下载)。
- 你用朋友的公钥对消息进行加密。这个加密过程就像把消息放进了一个“锁住的箱子”,而公钥就是用来锁箱子的钥匙。
- 加密后的消息变成了乱码(密文),只有拥有对应私钥的人才能解开。
- 你把加密后的消息发送给朋友。即使有人截获了密文,他们也无法解开,因为他们没有朋友的私钥。
解密过程
- 你的朋友收到加密的消息后,会用自己的私钥来解密。
- 私钥就像是打开箱子的唯一钥匙,只有它能解开用公钥锁住的内容。
- 朋友用私钥解密后,就能看到你发送的原始消息。
2. 数字签名与验证过程
除了加密消息,非对称加密还可以用来证明消息的真实性,这就是所谓的数字签名。
签名过程
- 假设你想给朋友发送一条消息,并且想证明这条消息确实是你发的。
- 你可以用自己的私钥对消息进行“签名”。这个过程类似于用私钥给消息打上一个独特的标记。
发送消息
- 你把签名后的消息发送给朋友。
验证签名
- 朋友收到消息后,会用你的公钥来验证签名。
- 如果验证成功,说明这条消息确实是你发的,而且内容没有被篡改过。
3. 秘钥交换过程
非对称加密还有一个重要的用途,就是帮助双方安全地交换密钥。
为什么需要密钥交换?
- 对称加密(比如AES)速度很快,但它需要双方提前共享一个密钥。如果直接传输密钥,可能会被黑客截获。
- 非对称加密可以解决这个问题。
如何交换密钥?
- 假设你想和朋友建立一个安全的通信通道。
- 你可以用朋友的公钥加密一个对称密钥,然后发送给他。
- 朋友收到后,用自己的私钥解密,就能得到对称密钥。
- 之后,你们就可以用这个对称密钥进行快速加密和解密了。
五、应用场景
1.安全通信:
- 非对称加密广泛应用于网络通信协议中,例如HTTPS、SSH等。
- 在HTTPS协议中,服务器使用非对称加密完成客户端和服务器之间的密钥交换,之后使用对称加密进行高效的数据传输。
2.数字签名:
- 数字签名是非对称加密的一个重要应用,用于确保消息的完整性和来源的真实性。
- 应用场景包括电子邮件签名、软件发布认证、区块链交易验证等。
3.身份认证:
- 非对称加密可以用于身份认证。例如,在SSH登录中,用户使用自己的私钥生成签名,服务器使用用户的公钥验证签名,从而确认用户身份。
4.密钥交换:
- 在对称加密中,密钥需要在通信双方之间安全传输。非对称加密可以通过公钥加密的方式安全地交换对称加密的会话密钥。
5.电子支付:
- 非对称加密在电子支付系统中扮演着重要角色。例如,比特币等数字货币系统中使用非对称加密确保交易安全。
6.证书颁发机构(CA):
- CA机构使用非对称加密签发数字证书,用于验证网站、软件或个人的身份。例如,SSL/TLS证书就是基于非对称加密技术。
六、与对称加密算法的对比
非对称加密和对称加密是两种主要的加密方式,它们各有优缺点,并适用于不同的场景。以下是对这两种加密方式的详细对比,帮助你更好地理解它们的特点及应用场景。
对比维度 | 对称加密 | 非对称加密 |
密钥数量 | 使用单一密钥进行加密和解密。 | 使用一对密钥:公钥(公开)用于加密,私钥(保密)用于解密。 |
密钥分发 | 密钥需要安全地共享,通常通过物理传递或借助其他安全机制(如非对称加密)来完成密钥分发。 | 公钥可以公开分发,无需担心泄露;私钥必须严格保密,解决了密钥分发问题。 |
速度 | 加密和解密速度快,适合处理大量数据。 | 加密和解密速度慢,计算复杂度高,不适合直接加密大数据。 |
安全性 | 安全性依赖于密钥的保密性,一旦密钥泄露,整个系统将失效。 | 安全性基于复杂的数学难题(如大整数分解、离散对数问题),即使公钥被公开,也无法推导出私钥。 |
适用场景 | 适用于大数据加密、文件加密、数据库加密、实时通信中的数据加密等。 | 适用于密钥交换、数字签名、身份验证、证书颁发等场景。 |
典型算法 | AES(高级加密标准)、DES(数据加密标准)、Blowfish、3DES(三重数据加密标准)。 | RSA、DSA(数字签名算法)、ECDSA(椭圆曲线数字签名算法)、ECC(椭圆曲线密码学)。 |
优点 | - 加密解密速度快。 - 算法简单,易于实现。 - 适合加密大量数据。 | - 解决了密钥分发问题。 - 提供身份验证和不可否认性。 - 更适合用于安全通信和数字签名。 |
缺点 | - 密钥分发困难,容易成为攻击目标。 - 不支持身份验证和不可否认性。 | - 加密解密速度慢。 - 计算复杂度高,资源消耗大。 - 不适合直接加密大量数据。 |
常见应用 | 文件加密、数据库加密、视频流加密、磁盘加密等。 | HTTPS协议中的密钥交换、区块链交易验证、电子邮件签名、软件发布认证、电子支付等。 |
密钥长度 | 密钥长度较短,例如AES支持128位、192位、256位。 | 密钥长度较长,例如RSA通常使用2048位或4096位;ECC可以在更短的密钥长度下实现相同的安全性(如256位)。 |
可扩展性 | 不适合大规模用户环境下的密钥管理,因为每个用户都需要独立的密钥。 | 更适合大规模用户环境,只需分发公钥即可。 |
结合使用 | 常与非对称加密结合使用,先通过非对称加密安全地交换对称密钥,再用对称加密高效处理大量数据。 | 通常用于密钥交换或数字签名,之后切换到对称加密以提高效率。 |
七、常见的非对称加密算法
RSA:
- RSA是最著名的非对称加密算法之一,基于大整数分解问题。
- 安全性依赖于素数分解的难度,因此密钥长度通常较长(如2048位或4096位)。
- 广泛应用于密钥交换、数字签名和身份认证。
DSA(Digital Signature Algorithm):
- DSA专门用于数字签名,不能直接用于加密数据。
- 安全性基于离散对数问题,效率较高。
- 常用于美国联邦政府的标准签名算法。
ECDSA(Elliptic Curve Digital Signature Algorithm):
- ECDSA基于椭圆曲线密码学,提供更高的安全性和更短的密钥长度。
- 相较于RSA,可以在相同安全级别下使用更短的密钥,从而提高效率。
- 广泛应用于区块链技术(如比特币、以太坊)和移动设备。
ECC(Elliptic Curve Cryptography):
- ECC利用椭圆曲线上的点运算,提供比传统算法更高的安全性。
- 相较于RSA,ECC可以在更短的密钥长度下实现相同的安全性,适合资源受限的环境。
ElGamal:
- ElGamal基于离散对数问题,可用于加密和数字签名。
- 尽管不如RSA和ECC流行,但在某些场景下仍有应用。
SM2:
- SM2 是中国国家密码管理局发布的基于椭圆曲线公钥密码算法的标准。
- 它提供了数字签名、密钥交换和公钥加密等功能,广泛应用于中国的电子认证服务、电子商务等领域。
- 基于椭圆曲线密码学(ECC),在相同安全强度下可以使用比RSA更短的密钥长度。
- 标准化程度高,已被国际电信联盟ITU-T和国际标准化组织ISO认可为国际标准。
SM9:
- SM9 是一种标识加密算法,也是由中国国家密码管理局发布的一种新型密码技术。
- 不需要传统的数字证书来管理公钥,降低了证书管理和分发的成本。
- 安全性基于标识的密码体制,提供了一种新的密钥管理方式,适用于物联网(IoT)设备、移动互联网等多种场景。
- 特别适合那些对密钥管理有较高要求的应用环境,简化了密钥的生成、存储和分发过程。
八、RSA算法应用示例代码(C#)
加解密示例
using System;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main()
{
// 生成RSA密钥对
using (RSA rsa = RSA.Create())
{
// 获取公钥
string publicKey = rsa.ToXmlString(false);
// 获取私钥
string privateKey = rsa.ToXmlString(true);
Console.WriteLine("公钥: " + publicKey); //输出示例:<RSAKeyValue><Modulus>t35vPxmyudsWEgRVH+PkhtX+4V3R3GD2d/xYTj8Kk5S5/FdS04Sb4BNSW8yKItaM00TqADxQPmumLy1q+0gfIF3JrNnQOs2VJWfDI7aF6SLlZLXjiZufC9MiXCiJk92MetA9Xu4lFysDB+1uUEGfqoYkDajeNYIygAzz9fzYaqOBO9VOt2fiNQdnCDs6aSJDbNcSQbxIjWWjzNqWTSoC8R2zwi8dNFxM60Uk13ymU2r9YXjdMI/CxC+TmOGUpZ/Os7kGrePyOTNnqukGPHFs7m8WSw+pfFsKWQwAa+70ZtS+xITM1lkrS+RIEWZx86LICeFnnY1rsdQt6k6YEOQAgQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
Console.WriteLine("私钥: " + privateKey); //输出示例:<RSAKeyValue><Modulus>t35vPxmyudsWEgRVH+PkhtX+4V3R3GD2d/xYTj8Kk5S5/FdS04Sb4BNSW8yKItaM00TqADxQPmumLy1q+0gfIF3JrNnQOs2VJWfDI7aF6SLlZLXjiZufC9MiXCiJk92MetA9Xu4lFysDB+1uUEGfqoYkDajeNYIygAzz9fzYaqOBO9VOt2fiNQdnCDs6aSJDbNcSQbxIjWWjzNqWTSoC8R2zwi8dNFxM60Uk13ymU2r9YXjdMI/CxC+TmOGUpZ/Os7kGrePyOTNnqukGPHFs7m8WSw+pfFsKWQwAa+70ZtS+xITM1lkrS+RIEWZx86LICeFnnY1rsdQt6k6YEOQAgQ==</Modulus><Exponent>AQAB</Exponent><P>1sXiMA6I6/4fx7llfKd+OcWUKxUry3pGqc0A4MrUErSidVGHYcrvcKcKkQVdUTHTRxUNoQEv6bmuYxOpnFKMEupOfTxme6mZKyRdh/sP1FqAWLb5ZRRqLg+RHlL1L+pdfeN3k06Ix4h9x1RmHaMzVj9e7i+jJ2+/cyIRtx2KUWM=</P><Q>2rd4mXDZeoRghGyDqgGso7UN0fWCuLAmFJsvheey6n+wGLyfmo6QEz9dv6eC20ki+3tYLhrXR7e7ZCWgZ5Eke5c2tMt8ecZsCYpJlpbuz7vKu7qscWyMls3R+64d7lU9bNyMgyjaeY/WgqfdYA2j2OZnYZso1xeVceg5tDgx3cs=</Q><DP>IaPDBtXv+k7GeYj/bWPqsG/TAmCBiJBxav0yKwN57ige3hNUCiw4DsQLMqXNdP9B4XtZtCM0dv5fYyNcSKDhUcEjZBhG0Q3CcPB0Oe1IEHHQcpTOQVfOPcKwbzh9MPEbjbFINGlzoRUu5j7A89lxHAw2+UW6311wdj8a2TymQpM=</DP><DQ>epKHy7Yqqza0wIHv5764eaZl8FyevdI6BSJTJ8AJzNFyZuqOp5dtttu0NkwyUaJTMIyXhn8UVuTo598OXfxBbeH4jqnbQIOq2E3fn71GaLTdkQe0zHwA7iK6o0mZDJBItFGFjZu/lJC/rslUjxgV0uCM326NHL3iystSS2WSzLE=</DQ><InverseQ>jag28f9Y4L1hCYjNMrXGe8uuqXe8pcEEpL2EPBfyd+xF4AdSeKYk9ryQHsrNFyy9U5BVbHlzlPVOzJSGrqFe2MZm3Dc7aTyWRhIGiJkun9bVBIDLGFu2iJoUGM0O+RQUeRzXuPFbrQ7XYNQNN0fyN5rBSRVWhazahebRGrqi1h4=</InverseQ><D>PAgYWzuMFnQP32sdcmZ7gIWIcrDgFMqAODcNqOPFEQ1qX50uEtdiq8eGfVQIqWcqAYCdUeBpnFJZtzuTsYwh6tPkRDGqh2J09hzhYdC4NNLe27kKLR4FxbeYmTAF+qNT72YrfeBJsC+5OSG7onQlyYNDTli+AiGLZgtW0Vaccx5nOfkZln9svban2/1gSsCk0L3/J9jQNFUbr3hiRKQrH14TArhaD2CGP5oDq8Evt9pQuFAUnjEj4kGmIGwUxu4AQaxlWL4f9a2wrojdQw10mgoFtNyDUw22EcPrRnCPupuXurVldOHdcmschEvAQA4eAhq/C4uOrIWiEO/Y9Y4MVQ==</D></RSAKeyValue>
// 明文消息
string plainText = "Hello, RSA Encryption!";
Console.WriteLine("\n原始消息: " + plainText);
// 2. 使用公钥加密消息
byte[] encryptedData = EncryptData(plainText, publicKey);
Console.WriteLine("\n加密后的消息(Base64编码): " + Convert.ToBase64String(encryptedData));
// 3. 使用私钥解密消息
byte[] decryptedData = DecryptData(encryptedData, privateKey);
string decryptedText = Encoding.UTF8.GetString(decryptedData);
Console.WriteLine("\n解密后的消息: " + decryptedText);
}
Console.Read();
}
// 加密方法
static byte[] EncryptData(string plainText, string publicKey)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
// 导入公钥
rsa.FromXmlString(publicKey);
// 将明文转换为字节数组
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
// 使用公钥加密数据
return rsa.Encrypt(plainBytes, false); // 第二个参数表示是否使用OAEP填充(false 表示使用PKCS#1 v1.5)
}
}
// 解密方法
static byte[] DecryptData(byte[] encryptedData, string privateKey)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
// 导入私钥
rsa.FromXmlString(privateKey);
// 使用私钥解密数据
byte[] decryptedBytes = rsa.Decrypt(encryptedData, false); // 第二个参数与加密时一致
return decryptedBytes;
}
}
//输出:
/*
公钥: <RSAKeyValue><Modulus>t35vPxmyudsWEgRVH+PkhtX+4V3R3GD2d/xYTj8Kk5S5/FdS04Sb4BNSW8yKItaM00TqADxQPmumLy1q+0gfIF3JrNnQOs2VJWfDI7aF6SLlZLXjiZufC9MiXCiJk92MetA9Xu4lFysDB+1uUEGfqoYkDajeNYIygAzz9fzYaqOBO9VOt2fiNQdnCDs6aSJDbNcSQbxIjWWjzNqWTSoC8R2zwi8dNFxM60Uk13ymU2r9YXjdMI/CxC+TmOGUpZ/Os7kGrePyOTNnqukGPHFs7m8WSw+pfFsKWQwAa+70ZtS+xITM1lkrS+RIEWZx86LICeFnnY1rsdQt6k6YEOQAgQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
私钥: <RSAKeyValue><Modulus>t35vPxmyudsWEgRVH+PkhtX+4V3R3GD2d/xYTj8Kk5S5/FdS04Sb4BNSW8yKItaM00TqADxQPmumLy1q+0gfIF3JrNnQOs2VJWfDI7aF6SLlZLXjiZufC9MiXCiJk92MetA9Xu4lFysDB+1uUEGfqoYkDajeNYIygAzz9fzYaqOBO9VOt2fiNQdnCDs6aSJDbNcSQbxIjWWjzNqWTSoC8R2zwi8dNFxM60Uk13ymU2r9YXjdMI/CxC+TmOGUpZ/Os7kGrePyOTNnqukGPHFs7m8WSw+pfFsKWQwAa+70ZtS+xITM1lkrS+RIEWZx86LICeFnnY1rsdQt6k6YEOQAgQ==</Modulus><Exponent>AQAB</Exponent><P>1sXiMA6I6/4fx7llfKd+OcWUKxUry3pGqc0A4MrUErSidVGHYcrvcKcKkQVdUTHTRxUNoQEv6bmuYxOpnFKMEupOfTxme6mZKyRdh/sP1FqAWLb5ZRRqLg+RHlL1L+pdfeN3k06Ix4h9x1RmHaMzVj9e7i+jJ2+/cyIRtx2KUWM=</P><Q>2rd4mXDZeoRghGyDqgGso7UN0fWCuLAmFJsvheey6n+wGLyfmo6QEz9dv6eC20ki+3tYLhrXR7e7ZCWgZ5Eke5c2tMt8ecZsCYpJlpbuz7vKu7qscWyMls3R+64d7lU9bNyMgyjaeY/WgqfdYA2j2OZnYZso1xeVceg5tDgx3cs=</Q><DP>IaPDBtXv+k7GeYj/bWPqsG/TAmCBiJBxav0yKwN57ige3hNUCiw4DsQLMqXNdP9B4XtZtCM0dv5fYyNcSKDhUcEjZBhG0Q3CcPB0Oe1IEHHQcpTOQVfOPcKwbzh9MPEbjbFINGlzoRUu5j7A89lxHAw2+UW6311wdj8a2TymQpM=</DP><DQ>epKHy7Yqqza0wIHv5764eaZl8FyevdI6BSJTJ8AJzNFyZuqOp5dtttu0NkwyUaJTMIyXhn8UVuTo598OXfxBbeH4jqnbQIOq2E3fn71GaLTdkQe0zHwA7iK6o0mZDJBItFGFjZu/lJC/rslUjxgV0uCM326NHL3iystSS2WSzLE=</DQ><InverseQ>jag28f9Y4L1hCYjNMrXGe8uuqXe8pcEEpL2EPBfyd+xF4AdSeKYk9ryQHsrNFyy9U5BVbHlzlPVOzJSGrqFe2MZm3Dc7aTyWRhIGiJkun9bVBIDLGFu2iJoUGM0O+RQUeRzXuPFbrQ7XYNQNN0fyN5rBSRVWhazahebRGrqi1h4=</InverseQ><D>PAgYWzuMFnQP32sdcmZ7gIWIcrDgFMqAODcNqOPFEQ1qX50uEtdiq8eGfVQIqWcqAYCdUeBpnFJZtzuTsYwh6tPkRDGqh2J09hzhYdC4NNLe27kKLR4FxbeYmTAF+qNT72YrfeBJsC+5OSG7onQlyYNDTli+AiGLZgtW0Vaccx5nOfkZln9svban2/1gSsCk0L3/J9jQNFUbr3hiRKQrH14TArhaD2CGP5oDq8Evt9pQuFAUnjEj4kGmIGwUxu4AQaxlWL4f9a2wrojdQw10mgoFtNyDUw22EcPrRnCPupuXurVldOHdcmschEvAQA4eAhq/C4uOrIWiEO/Y9Y4MVQ==</D></RSAKeyValue>
原始消息: Hello, RSA Encryption!
加密后的消息(Base64编码): rn6rWhNSlwuJFTBrBRb9BI87TYo5dzvMQxLkvsQ4xtfXg5k89XPo1+T81ezeolFQZmQTpfptxQgut7gbztOV4xz2MUSLekr0qUGFU6tBeXQ6QkSB3Xl+HnEW1C+3GfOubLaV6iYtYH+OR3Mz42XmrpxJBRmyJTwv4biiO1AvT3BBPW30k42E0puJoOZoWftSDAJ3DpQpWhoUtVmUkZZKJpeGwc5LRi3h+n8bKmfEayrBAJWsTRt9CloxQ6R8X3q2l9o6JamNRDFsgIWO4WZe6eShq0ebRNWBevK/LXgB+FvpFqF/sjmSOO0LaXz3+pL1i7D+oVklNF1PaqtX8rTGqQ==
解密后的消息: Hello, RSA Encryption!
*/
}
数字签名示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
string message = "Sign this message.";
byte[] data = Encoding.UTF8.GetBytes(message);
string privateKey = "<RSAKeyValue><Modulus>t35vPxmyudsWEgRVH+PkhtX+4V3R3GD2d/xYTj8Kk5S5/FdS04Sb4BNSW8yKItaM00TqADxQPmumLy1q+0gfIF3JrNnQOs2VJWfDI7aF6SLlZLXjiZufC9MiXCiJk92MetA9Xu4lFysDB+1uUEGfqoYkDajeNYIygAzz9fzYaqOBO9VOt2fiNQdnCDs6aSJDbNcSQbxIjWWjzNqWTSoC8R2zwi8dNFxM60Uk13ymU2r9YXjdMI/CxC+TmOGUpZ/Os7kGrePyOTNnqukGPHFs7m8WSw+pfFsKWQwAa+70ZtS+xITM1lkrS+RIEWZx86LICeFnnY1rsdQt6k6YEOQAgQ==</Modulus><Exponent>AQAB</Exponent><P>1sXiMA6I6/4fx7llfKd+OcWUKxUry3pGqc0A4MrUErSidVGHYcrvcKcKkQVdUTHTRxUNoQEv6bmuYxOpnFKMEupOfTxme6mZKyRdh/sP1FqAWLb5ZRRqLg+RHlL1L+pdfeN3k06Ix4h9x1RmHaMzVj9e7i+jJ2+/cyIRtx2KUWM=</P><Q>2rd4mXDZeoRghGyDqgGso7UN0fWCuLAmFJsvheey6n+wGLyfmo6QEz9dv6eC20ki+3tYLhrXR7e7ZCWgZ5Eke5c2tMt8ecZsCYpJlpbuz7vKu7qscWyMls3R+64d7lU9bNyMgyjaeY/WgqfdYA2j2OZnYZso1xeVceg5tDgx3cs=</Q><DP>IaPDBtXv+k7GeYj/bWPqsG/TAmCBiJBxav0yKwN57ige3hNUCiw4DsQLMqXNdP9B4XtZtCM0dv5fYyNcSKDhUcEjZBhG0Q3CcPB0Oe1IEHHQcpTOQVfOPcKwbzh9MPEbjbFINGlzoRUu5j7A89lxHAw2+UW6311wdj8a2TymQpM=</DP><DQ>epKHy7Yqqza0wIHv5764eaZl8FyevdI6BSJTJ8AJzNFyZuqOp5dtttu0NkwyUaJTMIyXhn8UVuTo598OXfxBbeH4jqnbQIOq2E3fn71GaLTdkQe0zHwA7iK6o0mZDJBItFGFjZu/lJC/rslUjxgV0uCM326NHL3iystSS2WSzLE=</DQ><InverseQ>jag28f9Y4L1hCYjNMrXGe8uuqXe8pcEEpL2EPBfyd+xF4AdSeKYk9ryQHsrNFyy9U5BVbHlzlPVOzJSGrqFe2MZm3Dc7aTyWRhIGiJkun9bVBIDLGFu2iJoUGM0O+RQUeRzXuPFbrQ7XYNQNN0fyN5rBSRVWhazahebRGrqi1h4=</InverseQ><D>PAgYWzuMFnQP32sdcmZ7gIWIcrDgFMqAODcNqOPFEQ1qX50uEtdiq8eGfVQIqWcqAYCdUeBpnFJZtzuTsYwh6tPkRDGqh2J09hzhYdC4NNLe27kKLR4FxbeYmTAF+qNT72YrfeBJsC+5OSG7onQlyYNDTli+AiGLZgtW0Vaccx5nOfkZln9svban2/1gSsCk0L3/J9jQNFUbr3hiRKQrH14TArhaD2CGP5oDq8Evt9pQuFAUnjEj4kGmIGwUxu4AQaxlWL4f9a2wrojdQw10mgoFtNyDUw22EcPrRnCPupuXurVldOHdcmschEvAQA4eAhq/C4uOrIWiEO/Y9Y4MVQ==</D></RSAKeyValue>";
string publicKey = "<RSAKeyValue><Modulus>t35vPxmyudsWEgRVH+PkhtX+4V3R3GD2d/xYTj8Kk5S5/FdS04Sb4BNSW8yKItaM00TqADxQPmumLy1q+0gfIF3JrNnQOs2VJWfDI7aF6SLlZLXjiZufC9MiXCiJk92MetA9Xu4lFysDB+1uUEGfqoYkDajeNYIygAzz9fzYaqOBO9VOt2fiNQdnCDs6aSJDbNcSQbxIjWWjzNqWTSoC8R2zwi8dNFxM60Uk13ymU2r9YXjdMI/CxC+TmOGUpZ/Os7kGrePyOTNnqukGPHFs7m8WSw+pfFsKWQwAa+70ZtS+xITM1lkrS+RIEWZx86LICeFnnY1rsdQt6k6YEOQAgQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
// 签名
byte[] signature = SignData(message, privateKey);
Console.WriteLine("Signature: " + Convert.ToBase64String(signature));
// 验证签名
bool isValid = VerifySignature(message, signature, publicKey);
Console.WriteLine("Is valid signature? " + isValid);
}
Console.Read();
}
// 签名方法
static byte[] SignData(string message, string privateKey)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(privateKey);
byte[] data = Encoding.UTF8.GetBytes(message);
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
}
// 验证签名方法
static bool VerifySignature(string message, byte[] signature, string publicKey)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(publicKey);
byte[] data = Encoding.UTF8.GetBytes(message);
return rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
}
//输出:
/*
Signature: M11hF8bwacxW6arTXvz3AurzPWeBtqisCf6rRqqkFP8mvdaSWkpGhs9gWGeCXBsfT9sq2wEk9Pt6FFkoRkP3TIKU+kxEHH0gt58E7gm3AjPDYbsDxCJnepU/DIjp894Ixkc00PGYpchPGcnKLSbVagkHX/tycsMoCWibL2BveIiKek6edyDopWPDWTR7xq1OgigjozK6cBH4gk6McgJ3TffIfusC8xZb5JROgtzGoBuEjqT0i8YkiQA5ElPKqHQxrv82LFSiI3FtsSRXXYCGgXFcwkdT71ZUJ0E1fAkUJuWZ2aaIkWJnRpwJXKxuk2cIFte4YmObC7ZWCWZhK7+aEQ==
Is valid signature? True
*/
}
}
九、RSA算法应用示例代码(Java)
RSA加解密示例
import java.security.*;
import javax.crypto.Cipher;
import java.util.Base64;
public class RSAExample {
public static void main(String[] args) throws Exception {
// 生成密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String plainText = "Hello, RSA!";
Cipher cipher = Cipher.getInstance("RSA");
// 加密
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(plainText.getBytes());
System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encryptedData));
// 解密
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedData = cipher.doFinal(encryptedData);
System.out.println("Decrypted: " + new String(decryptedData));
}
}
数字签名示例
import java.security.*;
public class DigitalSignatureExample {
public static void main(String[] args) throws Exception {
// 生成密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
String message = "Sign this message.";
Signature signature = Signature.getInstance("SHA256withRSA");
// 签名
signature.initSign(privateKey);
signature.update(message.getBytes());
byte[] digitalSignature = signature.sign();
System.out.println("Signature: " + Base64.getEncoder().encodeToString(digitalSignature));
// 验证签名
signature.initVerify(publicKey);
signature.update(message.getBytes());
boolean isVerified = signature.verify(digitalSignature);
System.out.println("Is valid signature? " + isVerified);
}
}
十、数字签名与加密的区别
对比维度 | 加密(Encryption) | 数字签名(Digital Signature) |
主要目的 | 保护数据的机密性:确保只有特定的人(持有解密密钥的人)才能读取信息。 | 验证数据的完整性和来源的真实性:确保消息确实来自声称的发送者,并且在传输过程中没有被篡改。 |
操作过程 | - 发送方使用接收方的公钥对消息进行加密。 - 加密后的消息发送给接收方。 - 接收方使用其私钥解密消息,读取内容。 | - 发送方使用自己的私钥对消息摘要(通常是哈希值)进行加密,生成签名。 - 签名随消息一起发送。 - 接收方使用发送方的公钥来验证签名。 |
用途不同 | 用于保护通信内容的隐私,防止未经授权的第三方读取信息。 | 用于验证消息的真实性和完整性,确保消息未被篡改并且确实由某个特定实体发出。 |
使用的密钥不同 | 使用接收方的公钥加密消息,只有接收方的私钥能解密。 | 使用发送方的私钥生成签名,任何人都可以用发送方的公钥验证签名。 |
安全性目标不同 | 主要关注的是防止信息泄露给未经授权的人员。 | 主要关注的是防止信息被篡改以及伪造信息源。 |
操作顺序 | 1. 发送方获取接收方的公钥。 2. 发送方使用公钥加密消息。 3. 接收方收到加密的消息后,使用私钥解密。 | 1. 发送方计算消息的哈希值。 2. 发送方使用自己的私钥对哈希值进行签名。 3. 接收方使用发送方的公钥验证签名。 |