-
2021-12-23 09:19:57
RSA签名算法概述及使用
一、加密算法种类
1、密钥
密钥,一般就是一个字符串或数字,在加密或者解密时传递给加密或解密算法,以使算法能够正确对明文加密或者对密文解密。
2、加密算法分类
大体上分为单向加密和双向加密。
2.1、单向加密
单向加密就是非可逆加密,就是不可解密的加密方法,由于其在加密后会生成唯一的加密串,故而经常用于检测数据传输过程中是否被修改。常见的单向加密有MD5、SHA、HMAC。我们只是把他们作为加密的基础,单纯的以上三种加密并不可靠。
2.2、双向加密
双向加密又可分为对称加密和非对称加密。你想进行加解密操作的时候需要具备两样东西:秘钥和加解密算法。
2.3、对称加密
对称加密算法的特点是加密使用的密钥和解密使用的密钥是相同的。也就是说,加密和解密都是使用的同一个密钥。因此对称加密算法要保证安全性的话,密钥自然要做好保密,只能让使用的人知道,不能对外公开。
2.4、非对称加密
在非对称加密算法中,有公钥和私钥两种密钥,其中,公钥是公开的,不需要保密,私钥由个人持有,必须妥善保管和注意保密。加密和解密使用两种不同的密钥,是它得名的原因。估计大家都听说过RSA,这就是一种常见的,应用很广的非对称加密算法。
二、RSA
1、那RSA 是什么呢?
RSA加密算法是一种非对称加密算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。这样就可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的(可能同时多人持有)。
2、原理
3、RSA加密、签名区别
加密和签名都是为了安全性考虑,但略有不同。常有人问加密和签名是用私钥还是公钥?其实都是对加密和签名的作用有所混淆。简单的说,加密是为了防止信息被泄露,而签名是为了防止信息被篡改。这里举2个例子说明。
第一个场景:战场上,B要给A传递一条消息,内容为某一指令。
RSA的加密过程如下:
(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
(2)A传递自己的公钥给B,B用A的公钥对消息进行加密。
(3)A接收到B加密的消息,利用A自己的私钥对消息进行解密。
在这个过程中,只有2次传递过程,第一次是A传递公钥给B,第二次是B传递加密消息给A,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行解密,防止了消息内容的泄露。
第二个场景:A收到B发的消息后,需要进行回复“收到”。
RSA签名的过程如下:
(1)A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
(2)A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。
(3)B收到消息后,在获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。
在这个过程中,只有2次传递过程,第一次是A传递加签的消息和消息本身给B,第二次是B获取A的公钥,即使都被敌方截获,也没有危险性,因为只有A的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给B,防止了消息内容的篡改。
但是,综合两个场景你会发现,第一个场景虽然被截获的消息没有泄露,但是可以利用截获的公钥,将假指令进行加密,然后传递给A。第二个场景虽然截获的消息不能被篡改,但是消息的内容可以利用公钥验签来获得,并不能防止泄露。所以在实际应用中,要根据情况使用,也可以同时使用加密和签名,比如A和B都有一套自己的公钥和私钥,当A要给B发送消息时,先用B的公钥对消息加密,再对加密的消息使用A的私钥加签名,达到既不泄露也不被篡改,更能保证消息的安全性。
总结:公钥加密、私钥解密、私钥签名、公钥验签。
三、测试代码
RSAUtil 工具类
public class RsaUtil {/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
public static final String privateKeyA = "privateKeyA";
public static final String publicKeyA = "publicKeyA";
public static final String publicKeyB = "publicKeyB";
public static final String privateKeyB = "privateKeyB";
/**
* 获取私钥
* @param privateKey 私钥字符串
* @return PrivateKey
*/
public static PrivateKey getPrivateKey(String privateKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
return keyFactory.generatePrivate(keySpec);
}
/**
* 获取公钥
* @param publicKey 公钥字符串
* @return PublicKey
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
return keyFactory.generatePublic(keySpec);
}
/**
* 随机生成密钥对
* @throws NoSuchAlgorithmException
*/
public static Map<Integer,String> genKeyPair() throws NoSuchAlgorithmException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024,new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
// 将公钥和私钥保存到Map
Map<Integer, String> keyMap = new HashMap();
keyMap.put(0,publicKeyString); //0表示公钥
keyMap.put(1,privateKeyString); //1表示私钥
return keyMap;
}
/**
* RSA公钥加密
* @param str 加密字符串
* @param publicKey 公钥
* @return 密文
* @throws Exception 加密过程中的异常信息
*/
public static String encrypt( String str, String publicKey ) throws Exception{
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] data = str.getBytes("UTF-8");
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
String outStr = Base64.encodeBase64String(encryptedData);
return outStr;
}
/**
* RSA私钥解密
* @param str 加密字符串
* @param privateKey 私钥
* @return 铭文
* @throws Exception 解密过程中的异常信息
*/
public static String decrypt(String str, String privateKey) throws Exception{
//64位解码加密后的字符串
byte[] data = Base64.decodeBase64(str.getBytes("UTF-8"));
//base64编码的私钥
byte[] decoded = Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
String outStr = new String(decryptedData);
return outStr;
}
/**
* 签名
* @param data 待签名数据
* @param privateKey 私钥
* @return 签名
*/
public static String sign(String data, PrivateKey privateKey) throws Exception {
byte[] keyBytes = privateKey.getEncoded();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey key = keyFactory.generatePrivate(keySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(key);
signature.update(data.getBytes());
return new String(Base64.encodeBase64(signature.sign()));
}
/**
* 验签
* @param srcData 原始字符串
* @param publicKey 公钥
* @param sign 签名
* @return 是否验签通过
*/
public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
byte[] keyBytes = publicKey.getEncoded();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey key = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initVerify(key);
signature.update(srcData.getBytes());
return signature.verify(Base64.decodeBase64(sign.getBytes()));
}
}
测试类client
假设 生成两对公钥、私钥,如上的工具类中,以便下面使用
public class TestClient {
public static void main(String[] args) {
// client 是 A server 是 B
// testSign();
// testPassword();
testSignAndPassword();
}
public static void testPassword(){
TestServer testServer = new TestServer();
try {
PasswordOrder passwordOrder = new PasswordOrder("1",new BigDecimal(100),"描述信息","weixin");
System.out.println("加密前的数据:" + JSONObject.toJSONString(passwordOrder));
String encrypt = RsaUtil.encrypt(JSONObject.toJSONString(passwordOrder), RsaUtil.publicKeyA);
System.out.println("加密后的数据:" + encrypt);
testServer.testPassword(encrypt);
} catch (Exception e){
e.printStackTrace();
}
}
public static void testSign(){
try {
TestServer testServer = new TestServer();
ClientOrder order = new ClientOrder("1",new BigDecimal(100),"描述信息","weixin");
String data = MapUtil.mapToString(MapUtil.beanToMap(order));
String sign = RsaUtil.sign(data, RsaUtil.getPrivateKey(RsaUtil.privateKeyA));
order.setSign(sign);
System.out.println("客户端请求数据为原数据和sign:" + JSONObject.toJSONString(order));
testServer.testSign(order);
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 先签名后加密,最后把密文传到服务端
*/
public static void testSignAndPassword(){
try {
TestServer testServer = new TestServer();
ClientOrder order = new ClientOrder("1",new BigDecimal(100),"描述信息","weixin");
String data = MapUtil.mapToString(MapUtil.beanToMap(order));
String sign = RsaUtil.sign(data, RsaUtil.getPrivateKey(RsaUtil.privateKeyA));
order.setSign(sign);
System.out.println("签名:" + sign);
System.out.println("加密前的数据:" + JSONObject.toJSONString(order));
String encrypt = RsaUtil.encrypt(JSONObject.toJSONString(order), RsaUtil.publicKeyB);
System.out.println("加密后的数据:" + encrypt);
testServer.testSignAndPassword(encrypt);
} catch (Exception e){
e.printStackTrace();
}
}
}
测试类server
public class TestServer {
public void testSign(ClientOrder order){
try {
System.out.println("服务端收到的数据:" + JSONObject.toJSONString(order));
String sign = order.getSign();
order.setSign(null);
String data = MapUtil.mapToString(MapUtil.beanToMap(order));
boolean verify = RsaUtil.verify(data, RsaUtil.getPublicKey(RsaUtil.publicKeyA), sign);
System.out.println("验签结果:" + verify);
} catch (Exception e){
e.printStackTrace();
}
}
public void testPassword(String encrypt) {
try {
String decrypt = RsaUtil.decrypt(encrypt, RsaUtil.privateKeyA);
PasswordOrder passwordOrder = JSONObject.parseObject(decrypt, PasswordOrder.class);
System.out.println("解密后的数据:" + JSONObject.toJSONString(passwordOrder));
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 先解密,再验签
* @param encrypt
*/
public void testSignAndPassword(String encrypt) {
try {
System.out.println("收到的数据:" + encrypt);
String decrypt = RsaUtil.decrypt(encrypt, RsaUtil.privateKeyB);
System.out.println("解密后的数据:" + decrypt);
ClientOrder clientOrder = JSONObject.parseObject(decrypt, ClientOrder.class);
String sign = clientOrder.getSign();
clientOrder.setSign(null);
String data = MapUtil.mapToString(MapUtil.beanToMap(clientOrder));
boolean verify = RsaUtil.verify(data, RsaUtil.getPublicKey(RsaUtil.publicKeyA), sign);
System.out.println("验签结果:" + verify);
} catch (Exception e){
e.printStackTrace();
}
}
}
注意:
1、因为rsa在加解密的时候,有长度限制,所以在加解密的时候应该采用分段式加解密。
2、当需要同时使用加解密的时候,必须是先签名后加密,假设是 A 请求 B ,A用A的私钥生成签名,再用B的公钥加密,最后把密文传B,B 收到密文的时候,先用B的私钥进行解密,再用A的公钥验签。
使用场景:
1、只对数据加密 , 此时只需要server端生成一对公私钥,把公钥交给client,这种情况主要用在web与服务器的交互,比如传密码之类的。(防泄漏)
2、只对数据签名,此时只需要client端生成一对公私钥,把公钥交给server,这种情况主要用在公司内部与第三方对接,比如,公司有个项目A需要接入微信,支付宝,京东等,即,A 是client,第三方则是server,这样每次调用第三方都需要把数据签名后,发给第三方,然后进行验签。(防篡改)
3、对数据进行签名和加密,此时client和server两方各自生成一对公私钥,相互交换公钥,这种情况主要用在企业之间的数据传输,比如 甲 乙 两个企业要通信。(防篡改和防泄漏)
更多相关内容 -
RSA签名算法
2021-11-16 20:59:09文章目录RSA签名算法简介RSA签名的过程全部代码运行结果 RSA签名算法简介 签名就是在这份资料后面增加一段强而有力的证明,以此证明这段信息的发布者和这段信息的有效性完整性。 RSA签名常用的就是将这份信息进行...RSA签名算法简介
- 签名就是在这份资料后面增加一段强而有力的证明,以此证明这段信息的发布者和这段信息的有效性完整性。
- RSA签名常用的就是将这份信息进行hash,得到一个hash值,再将hash值加密作为签名,后缀在信息的末尾。
- 哈希的好处:更安全,签名更快,解除了签名长度的限制。
RSA签名的过程
- A生成一对密钥(公钥和私钥),私钥不公开,A自己保留。公钥为公开的,任何人可以获取。
- A用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给B。
- B收到消息后,在获取A的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是A回复的。
- 哈希函数的实现请参考本人其它文章:SHA256,SHA1
- 这里直接调用库函数实现哈希SHA512
全部代码
# -*-coding:utf-8-*- """ File Name: RSA签名.py Program IDE: PyCharm Create Time: 2021-10-31 14:20 Create By Author: 陆依依 """ import hashlib # 实现哈希 import random # 产生大素数(w位) def generate_prime(w): while True: # 产生一个奇数() num = random.randint(2 ** (w - 1), 2 ** w - 1) | 1 # 对素数进行50次素性检验, 错误概率为:7.888609052210118e-31, 可以忽略 for i in range(50): if not Miller_Rabin(num): break if i == 49: return num # Miller-Rabin素性检测 def Miller_Rabin(num): m = num - 1 k = 0 while m % 2 == 0: m = m // 2 k = k + 1 a = random.randint(2, num) b = Mod_P(a, m, num) if b == 1: return True for i in range(k): if b == num - 1: return True else: b = b * b % num return False # 非递归求a^n mod p, 快速幂思想 def Mod_P(a, n, p): c = 1 binstr = bin(n)[2:][::-1] # 通过切片去掉开头的0b,截取后面,然后反转 for item in binstr: if item == '1': c = (c * a) % p a = (a ** 2) % p elif item == '0': a = (a ** 2) % p return c # 求最大公因子.欧几里得算法 def gcd(a, b): if a % b == 0: return b else: return gcd(b, a % b) # 求逆元,扩展欧几里得算法 def Ex_Euclid(x, n): r0 = n r1 = x % n if r1 == 1: y = 1 else: s0 = 1 s1 = 0 t0 = 0 t1 = 1 while r0 % r1 != 0: q = r0 // r1 r = r0 % r1 r0 = r1 r1 = r s = s0 - q * s1 s0 = s1 s1 = s t = t0 - q * t1 t0 = t1 t1 = t if r == 1: y = (t + n) % n return y # 产生公私钥 def Build_key(): p = generate_prime(512) q = generate_prime(512) n = p * q # n的长度近似为1024位,即秘钥长度1024 _n = (p - 1) * (q - 1) # n的欧拉函数 while True: e = random.randint(2, _n-1) # 随机选择一个与_n互质的整数,一般选择65537。 if gcd(e, _n) == 1: # 模拟计算 break d = Ex_Euclid(e, _n) # 计算e对_n的模反元素 return n, e, d # 返回公私钥,公钥(n,e),私钥(n,d) def sign(m, n, d): s = [Mod_P(ord(i), d, n) for i in m] return m, s def verify(m, s, n, e): return m == ''.join([chr(Mod_P(i, e, n)) for i in s]) # demo if __name__ == '__main__': choose = int(input('请选择加密对象:1)文件 2)非文件\t')) if choose == 2: message = input('请输入待加密内容:').encode('utf-8') else: path = input('请输入完整文件路径:') with open(path, 'rb') as f: message = f.read() m = hashlib.sha512(message).hexdigest() print('散列后的消息:', m) n, e, d = Build_key() m, s = sign(m, n, d) print('签名列表长度:', len(s)) # 将签名写入新文件 with open('sign.txt', 'w') as f: f.write(str(s).replace('[', '').replace(']', '').replace(',', '\n').replace(' ', '')) print('签名写入成功!!!') print('签名验证结果?', verify(m, s, n, e))
运行结果
- 文本文件进行签名
- 签名结果:大概就是128个1024bit的大整数,后续不再展示
- 对非文本文件进行签名
- 对字符串进行签名
-
RSA签名算法,PKCS7格式
2018-10-24 11:16:21本资源包含:RSA签名算法,格式为PKCS7。RSA签名算法,格式为PKCS7。RSA签名算法,格式为PKCS7。RSA签名算法,格式为PKCS7。 RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977... -
基于RSA的数字签名算法的实现
2021-10-25 23:58:38基于RSA的数字签名算法的实现,能够用在VC6.0 平台运行。RSA加密算法中,消息发送方是用公钥对数据进行加密,消息接收方用...在RSA签名算法中,消息发布者用私钥对消息进行签名,消息接收者用签名者的公钥进行验证。 -
PHP实现的MD5结合RSA签名算法实例
2021-01-20 01:35:10本文实例讲述了PHP实现的MD5结合RSA签名算法。分享给大家供大家参考,具体如下: <?php class Md5RSA{ /** * 利用约定数据和私钥生成数字签名 * @param $data 待签数据 * @return String 返回签名 */ ... -
RSA签名算法实例
2014-04-09 17:23:33RSA签名算法实例,使用RSA的SignHash和VerifyHash可以同样做到SignData和VerifyData,事实上还有一种方法进行公钥加密的签名 认证。就是.NET中的AsymmetricSignatureFormatter和AsymmetricSignatureDeformatter。直 ... -
JAVA RSA 加密算法 RSA.java
2020-08-29 17:22:17JAVA RSA 加密算法 RSA.java RSA公钥加解密,RSA私钥加解密,MD5withRSA 签名 MD5withRSA签名较验 -
数字签名系列一:签名简介与RSA签名算法
2021-09-15 15:18:15导师建议我从点到面,可以写一篇综述之类的,看了看大佬写的综述,数字签名真的种类繁多,而且自己能力有限,写综述实在不知道从哪里下手,因此就想在自己博客上写写签名那些事,争取一周更一个数字签名算法,希望...写在前面
学了一年的数字签名方案,一直都在一个点进行专研,虽然还是有所收获,总感觉还差点感觉,上了一年研究生,还没有对数字签名有整体了解。导师建议我从点到面,本来想写一篇综述之类的,看了看大佬写的综述,数字签名真的种类繁多,而且自己能力有限,写综述实在不知道从哪里下手,因此就想在自己博客上写写签名那些事,争取一周更一个数字签名算法,希望通过这样子方式,可以对数字签名有较深了解,也希望可以结交志趣相投的朋友一起探讨(本人菜鸟,求抱大腿)。
数字签名作用
数字签名,本质上就是一种签名方式。古代人以手写或者印章,指模等方式进行签名,表示自己对签名的内容了解且负有责任,当出现矛盾纷争的时候可以作为证据起到法律责任(不知为啥想到了卖身契),随着计算机发展,要求我们对数字文档进行签名认证,如何让我们的签名如同手写印章那样合法有效?数字签名技术便应运而生。
数字签名技术大多使用公钥密码机制,最简单的构造即签名者用自己私钥进行签名,任意验证者使用签名者的公钥进行验证。根据公钥密码体制可知,已知公钥求私钥是困难的,因此只要验证通过,就可以认为签名有效,因此数字签名具有保证签名者身份的真实性,签名内容完整性以及一旦验证通过,签名不可抵赖性(概括为数字签名的三个特性:真实性,完整性与不可抵赖性)。数字签名发展史
1976年,Whitfield与Martin Hellman发表历史性文章[1],提出数字签名的概念。
1978年,发表RSA数字签名方案。RSA是一种很经典的数字签名方案,在现实生活中仍有很大的应用。迄今为止,对RSA的攻击已经很多,但都没有对它构成真正的威胁。
1978年,Rabin发表了一次性签名方案(OTS)[2]一次性签名方案实现简单,甚至可以直接用部分密钥(与身份有关)作为签名。每个密钥对仅加密1bit,安全性高。缺点是成本高,效率慢。为了提高效率,提出Merkle数字签名方案。
1984年,Elgamal发表基于离散对数问题的Elgamal数字签名算法[3]
1984年,Adi Shamir提出基于身份的密码技术(IBC),且给出了第一个基于身份的数字签名方案.基于身份的密码也称为基于标识的密码。
1986年Amos Fiat和Adi Shamir提出Fiat-Shamir变换[4],该变换可以将一大类身份认证转化为数字签名算法。(主要应用之一,可以把交互式零知识证明转化为非交互式,化简算法,提高效率,在数字签名算法中应用广泛)
1991年NIST发表数字签名算法DSA,是对Elgamal数字签名算法的变形
2002年ChoonCha,JungHee Cheon等利用双线性对构造短签名算法。
2017年NIST征集后量子公钥算法标准化工作,后量子数字签名方案不断得到重视
2008年Gentry,Peikert等人提出了第一个高效安全的格签名方案[5]
2001年,曾贵华教授提出了第一个仲裁量子签名协议(AQS)[6]带属性的数字签名
简单功能的数字签名方案已经不能满足一些特殊需求,比如电子现金,电子选取,交通等领域应用,使得数字签名功能不断得到完善,现介绍几个带属性的数字签名技术。
(1)盲签名:1982年David Chaum提出盲签名概念。盲签名是相对于一般的数字签名而言的概念,是指签名人员虽然对某个消息签了名,但他并不知道所签消息的具体内容,也就是说对签名人而言,消息被盲化处理过。签名的有效性是指可以在消息去盲以后公开验证。
(2)多重签名:多重数字签名即为多人同时对一份数字分档进行签名。多重数字签名技术有很多应用场景,比如,夫妻共同财产的支配问题,只有两者均同意才可以进行财产支配。多重机制可用于对于签名有需求且对长度有敏感的应用。与多重签名类似的签名机制为聚合签名。聚合签名分为通用聚合签名与顺序聚合签名两种。
(3)门限签名:提到门限签名,不得不提秘密共享技术。很多门限签名都是有秘密共享机制转化而成。门限签名是普通数字签名的一个重要分支,是门限秘密共享技术和数字签名的一种结合。1991年,Desmedt-Frankel首次提出了(t,n)门限签名方案。(t,n)门限签名方案是指由n个成员组成一个签名群体,该群体有一对公钥和私钥,群体内大于等于t个合法、诚实的成员组合可以代表群体用群私钥进行签名,任何人可利用该群体的公钥进行签名验证。这里t是门限值,只有大于等于t个合法成员才能代表群体进行签名,群体中任何个或更少的成员不能代表该群体进行签名,同时任何成员不能假冒其他成员进行签名。采用门限签名方式可以实现权力分配,避免滥用职权。
…未完待续RSA数字签名方案
第一个数字签名方案,我选择了比较经典的RSA数字签名。在介绍这个签名之前,首先想先介绍一下RSA加解密算法:
RSA公钥算法(基于大整数分解难题)
(1)选取两个不同大素数p,q
(2)计算n=pq, φ ( n ) = ( p − 1 ) ( q − 1 ) \varphi (n)=\left ( p-1 \right )\left ( q-1 \right ) φ(n)=(p−1)(q−1),其中 φ ( n ) \varphi (n) φ(n)是欧拉函数。
(3)随机选取整数e作为公钥,要求满足 ( e , φ ( n ) ) = 1 \left ( e,\varphi \left ( n \right ) \right )=1 (e,φ(n))=1
(4)采用欧几里得算法计算私钥d,使得ed=1mod φ ( n ) \varphi (n) φ(n)。
e,n是公钥,d是私钥。p,q, φ ( n ) \varphi (n) φ(n)可销毁不可公开
RSA签名算法
最简单的RSA签名算法即私钥签名,公钥验证,具体流程如下:
(1)密钥对的产生(e,d),把e传输给验证者。
(2)对消息M进行处理,求其摘要,公开摘要算法。
(3)用户用自己私钥对摘要进行加密处理后,把摘要以及原文发送给验证者
(4)验证者用对方公钥进行解密,得到摘要,计算M的摘要,看看两个摘要是否一致,一致签名成功,否则失败。
这次就先介绍到这里,如有错误望指正!参考文献
[1] Diffie W., Hellman M. (1976) New Directions in
Cryptography. IEEE Transactions on Information Theory.
22 (6): 644.
[2]Rivest R., Shamir A., Adleman L. (1978) A Method
for Obtaining Digital Signatures and Public-Key
Cryptosystems. Communications of the ACM. 21 (2):
120–126
[3]ElGamal T. (1985) A Public Key Cryptosystem and
a Signature Scheme Based on Discrete Logarithms.
Advances in Cryptology. CRYPTO 1984. Lecture Notes in Computer Science, vol 196. Springer, Berlin,
Heidelberg.
[4]Fiat A., Shamir A. (1987) How To Prove Yourself:
Practical Solutions to Identification and Signature
Problems. Advances in Cryptology — CRYPTO’ 86.
CRYPTO 1986. Lecture Notes in Computer Science, vol
263. Springer, Berlin, Heidelberg.
[5] Craig Gentry, Chris Peikert, Vinod Vaikuntanathan. Trapdoors for hard lattices and new cryptographic constructions. In the 40th Annual ACM Symposium on Theory of Computing. ACM, 2008, 197-206.
[6]Zeng G, Keitel C H. Arbitrated quantum-signature scheme[J]. Physical Review A, 2002, 65(4): 042312. -
非对称加密算法 --- RSA签名算法
2020-05-13 00:07:23RSA原理 通过一定的规则,生成公钥和私钥,公钥和私钥...非对称加密算法之RSA算法实现 RSA应用场景 RSA加密场景 A给B传一条消息,要保证哪怕消息被截取了,也不能让别人知道消息的真正含义。 1、B生成公钥和私钥,私RSA原理
通过一定的规则,生成公钥和私钥,公钥和私钥总是成对出现。
公钥可以公开出去,任何人都可以知道。
私钥只有自己知道。
RSA算法能保证,公钥加密后的密文,只有对应的私钥才能解密。或者,私钥加密后的密文,只有对应的公钥才能解密。
而且不能通过公钥得到私钥,也不能通过私钥算出公钥。关于为什么公私钥直接不能互相转换,请看我之前的一篇文章:
非对称加密算法之RSA算法实现RSA应用场景
RSA加密场景
A给B传一条消息,要保证哪怕消息被截取了,也不能让别人知道消息的真正含义。
1、B生成公钥和私钥,私钥自己保留,把公钥传给A
2、A用公钥加密要传的消息,然后把密文传给B
3、B用私钥解密密文,得到真正的消息。
这样做的好处是,就算有人把中间的密文和公钥都拿到了,他也获取不到明文。
因为RSA的特点就是公钥加密,必须用对应的私钥才能解密。而私钥一直是B保管。RSA签名场景
同样的,A给B传一条消息,可以明文传输,但要保证,B收到的,就是A发出的,不能被别人恶意修改。
1、B生成公钥和私钥,私钥自己保留,把公钥传给A
2、A用公钥对要传的信息进行签名,形成签名信息。A将签名信息和明文一起传给B
3、B收到明文和签名后,用私钥对签名进行验证,如果验证通过,则证明B收到的明文就是A发出的明文。
这样做的好处是,哪怕中间有人截取到明文和签名,只要修改任意一个,B那里最终都不会验证通过。RSA加解密和签名算法的java实现
import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; public class TestRsa { // 私钥对象 private PrivateKey sk; // 公钥对象 private PublicKey pk; // 私钥字符串 private String privateKeyStr; // 公钥字符串 private String publicKeyStr; // 初始化公钥私钥 public TestRsa() throws NoSuchAlgorithmException { KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA"); rsa.initialize(1024); KeyPair keyPair = rsa.generateKeyPair(); sk = keyPair.getPrivate(); pk = keyPair.getPublic(); privateKeyStr = new String(Base64.encodeBase64(sk.getEncoded())); publicKeyStr = new String(Base64.encodeBase64(pk.getEncoded())); } // 公钥加密 public String encrypt(String str, String publicKey) throws Exception { //base64编码的公钥 byte[] decoded = Base64.decodeBase64(publicKey); RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded)); //RSA加密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8"))); return outStr; } // 私钥解密 public String decrypt(String str, String privateKey) throws Exception { //64位解码加密后的字符串 byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8")); //base64编码的私钥 byte[] decoded = Base64.decodeBase64(privateKey); RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); //RSA解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, priKey); String outStr = new String(cipher.doFinal(inputByte)); return outStr; } // 私钥签名 public String sign(String str) throws Exception { Signature signature = Signature.getInstance("SHA1withRSA"); signature.initSign(this.sk); signature.update(str.getBytes()); byte[] sign = signature.sign(); return new String(Base64.encodeBase64(sign)); } // 公钥验证 public boolean verify(String str, String sign) throws Exception { Signature signature = Signature.getInstance("SHA1withRSA"); signature.initVerify(this.pk); signature.update(str.getBytes()); return signature.verify(Base64.decodeBase64(sign.getBytes("UTF-8"))); } public static void main(String[] args) throws Exception { String str = "这是加密前的明文"; TestRsa testRsa = new TestRsa(); String encrypt = testRsa.encrypt(str, testRsa.publicKeyStr); System.out.println("加密后的密文:" + encrypt); String decrypt = testRsa.decrypt(encrypt, testRsa.privateKeyStr); System.out.println("解密后的明文:" + decrypt); // 签名 String sign = testRsa.sign(str); System.out.println("签名结果:" + sign); // 验证 boolean verify = testRsa.verify(str, sign); System.out.println("验证结果:" + verify);// true // 验证反例 String str2 = "这是被恶意修改过的伪原文"; boolean verify2 = testRsa.verify(str2, sign); System.out.println("验证结果2:" + verify2);// false } }
最终结果:
加密后的密文:Pc/lj5beiojR1BIiEG1O9fooVOmwDgQixN9qX19ofU3Myq5iOViMqEM2lUZ+tmihms3BrLahZze2FeZVR1wrTSk24ZTK5rjKtL1GZLsQI6m/wNXmk9bA5gYbcR6ivZSTEw5a9+77mcAFuAgpeSmSM825NOTAt7epZeUt7i9FPNY= 解密后的明文:这是加密前的明文 签名结果:Oe2XuGCb5mBwE4JTRPcemipOSuXEsw+hxido6r3/FSyDhx371sdg6/iRYQk6C2FuOqOpltWBJ4gA7x+VfJSJoA94+EIu5WxOaupaPumzNrsfhC/ZtYRUw0PfUvR5j232LH5bfA+Dh6pGbo1gu6qMVf8EtS63BoGHi9SYP068uss= 验证结果:true 验证结果2:false
-
RSA签名算法-C++实现
2019-07-05 16:04:03密码设计课写过的RSA算法 代码写的丑,有学这门课需要的道友可以看一下 main函数 #include<iostream> #include<math.h> #include"ProRPN.h" #include<... -
RSA数字签名算法的具体实现.zip
2021-07-09 22:11:37RSA数字签名算法的具体实现 -
Java实现的数字签名算法RSA完整示例
2020-08-25 16:08:49主要介绍了Java实现的数字签名算法RSA,结合完整实例形式详细分析了RSA算法的相关概念、原理、实现方法及操作技巧,需要的朋友可以参考下 -
数字签名算法rsa
2021-05-25 01:51:44数字签名算法消息传递模型由消息发送方构建密钥对,这里由甲方完成。由消息发送方公布公钥至消息接收方,这里由甲方将公钥公布给乙方。...RSA数字签名算法是迄今为止应用最为广泛的数字签名算法。 RS... -
RSA加密算法和签名算法
2019-05-14 14:16:25RSA加密算法和签名算法 一、理论_来源于网上。 RSA加密算法 RSA公钥加密体制包含如下3个算法:KeyGen(密钥生成算法),Encrypt(加密算法)以及Decrypt(解密算法)。 。密钥生成算法以安全常数作为输入,输出... -
数字签名算法RSA
2021-05-26 02:42:27//使用私钥进行签名 System.out.println("jdk RSA签名" + Hex.encodeHexString(result)); //验证签名 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); keyFactory = ... -
DELPHI版RSA算法
2018-07-29 17:57:23可设置任意秘钥长度,生成秘钥可按各种格式保存,可配合MD5, SHA1哈希算法做签名和验签,提供实用函数和类库,方便你在DELPHI程序中直接调用 -
数字签名算法,c++实现,RSA的算法
2010-12-23 10:10:56包涵三个RSA算法,c++是实现,数字签名的合集,三个独自的程序,可以独自编译运行,VC6.0下编译 -
数字签名算法_RSA
2021-05-25 01:51:46public static void jdkRsa(String data) {try {// 初始化密钥KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(512);// 获取密钥KeyPair keyPair = ... -
数字签名算法之RSA
2020-10-21 14:33:38数字签名算法之RSA1.数字签名简述2. 模型分析3. 代码实现3.1 签名算法实现3.2 测试代码3.3 运行结果 1.数字签名简述 数字签名算法可以看做是一种带有密钥的消息摘要算法,并且这种密钥包含了公钥和私钥。也就是说... -
实现数字签名算法(DSA),Hash算法的实现C语言
2020-04-15 12:30:411)利用C\C++语言实现DSA算法。 2)DSA中的Hash函数采用SHA算法。 (1)消息填充:因为我们存储的时候是以字节为单位存储的,所以消息的长度(单位:位)一定是 8 的倍数。而我们填充的时候也一定是 8 位、8 位... -
RSA-PSS数字签名算法
2022-01-29 19:04:21RSA-PSS数字签名算法 -
扩展RSA签名算法__实现双人签名、验证.pdf
2010-03-27 21:47:39扩展RSA签名算法__实现双人签名、验证.pdf 扩展RSA签名算法__实现双人签名、验证.pdf -
实现了RSA的加密以及数字签名
2018-10-26 20:20:59用python实现RSA算法,包括加密与解密,数字签名。操作的对象是二维码,只是对二维码的信息进行加密解密 -
【密码学】Python实现RSA数字签名算法
2021-11-21 20:00:48程序要求清单: 基本流程: 运行结果: INPUT: ... -
RSA算法和RSA数字签名算法
2018-03-07 15:47:49一、引言 随着网络技术的飞速发展,信息安全性已成为亟待解决的问题。...另外,随着电子商务的发展,网络上资金的电子交换日益频繁,如何防止信息的伪造和欺骗也成为非常...目前关于数字签名的研究主要集中基于公钥...