博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第十四章 数字签名算法--RSA
阅读量:6974 次
发布时间:2019-06-27

本文共 7449 字,大约阅读时间需要 24 分钟。

注意:本节内容主要参考自

  • 《Java加密与解密的艺术(第2版)》第9章“带密钥的消息摘要算法--数字签名算法”
  • 《大型分布式网站架构(设计与实践)》第3章“互联网安全架构”

14.1、数字签名算法

特点:

  • 非对称加密算法+消息摘要算法的结合体
  • 抗否认性、认证数据来源、防止数据被篡改(具体意思与做法查看下边的过程与类比部分)
  • 私钥加密(签名)、公钥解密(验证)

过程:

1)消息发送者产生一个密钥对(私钥+公钥),然后将公钥发送给消息接收者

2)消息发送者使用消息摘要算法对原文进行加密(加密后的密文称作摘要)

3)消息发送者将上述的摘要使用私钥加密得到密文--这个过程就被称作签名处理,得到的密文就被称作签名(注意,这个签名是名词)

4)消息发送者将原文与密文发给消息接收者

5)消息接收者使用公钥对密文(即签名)进行解密,得到摘要值content1

6)消息接收者使用与消息发送者相同的消息摘要算法对原文进行加密,得到摘要值content2

7)比较content1是不是与content2相等,若相等,则说明消息没有被篡改(消息完整性),也说明消息却是来源于上述的消息发送方(因为其他人是无法伪造签名的,这就完成了“抗否认性”和“认证消息来源”)

类比:

手写签名:

  • 张三在合同上签了自己的名字,这样张三在后来想否认自己的这个合同内容时,就不行了(抗否认性)
  • 在张三签过名之后,若合同内容又发生了变化,这个时候签名就可以看做无效了
  • 当然,我们通过合同上张三的签名,我们就可以知道签名的来源是张三(认证数据来源)

常见的数字签名算法:

  • RSA(数字签名算法的经典,也是最常用的数字签名算法)
  • DSA(是后续数字签名算法的基础)
  • ECDSA(ECC+DSA的结合体,相较于其他数字签名算法,速度快,强度高,签名短,但是使用还没有RSA广泛)

14.2、RSA

常见算法:

  • MD5WithRSA(JDK6)
  • SHA1WithRSA(JDK6)
  • SHA256WithRSA(>=JDK1.6.45,Bouncy Castle-->简称BC)

注意:在《Java加密与解密(第二版)》一书中,说JDK6不支持SHA256WithRSA,但是经过我自己测试1.6.45是支持的。

实现方式:(参考上边三行)

  • JDK
  • BC

14.2.1、基于JDK6实现的MD5WithRSA或SHA1WithRSA或SHA256WithRSA算法

1 package com.uti.rsa.digital;  2   3 import java.io.UnsupportedEncodingException;  4 import java.security.InvalidKeyException;  5 import java.security.KeyFactory;  6 import java.security.KeyPair;  7 import java.security.KeyPairGenerator;  8 import java.security.NoSuchAlgorithmException;  9 import java.security.PrivateKey; 10 import java.security.PublicKey; 11 import java.security.Signature; 12 import java.security.SignatureException; 13 import java.security.spec.InvalidKeySpecException; 14 import java.security.spec.PKCS8EncodedKeySpec; 15 import java.security.spec.X509EncodedKeySpec; 16  17 import org.apache.commons.codec.binary.Base64; 18  19 /** 20  * 基于BC的RSA数字签名算法 21  */ 22 public class RSACoderBC { 23     private static final String ENCODING = "UTF-8"; 24     private static final String KEY_ALGORITHM = "RSA";//非对称加密密钥算法 25     private static final String SIGNATURE_ALGORITHM = "MD5withRSA";//指定数字签名算法(可以换成SHA1withRSA或SHA256withRSA) 26     private static final int KEY_SIZE = 512;//非对称密钥长度(512~1024之间的64的整数倍) 27      28     /** 29      * 生成发送方密钥对 30      */ 31     public static KeyPair initKey() throws NoSuchAlgorithmException{ 32         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);//密钥对生成器 33         keyPairGenerator.initialize(KEY_SIZE);//指定密钥长度 34         KeyPair keyPair = keyPairGenerator.generateKeyPair();//生成密钥对 35         return keyPair; 36     } 37      38     /** 39      * 还原公钥 40      * @param pubKey 二进制公钥 41      */ 42     public static PublicKey toPublicKey(byte[] pubKey) throws NoSuchAlgorithmException,  43                                                               InvalidKeySpecException{ 44         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);//密钥工厂 45         return keyFactory.generatePublic(new X509EncodedKeySpec(pubKey));//还原公钥 46     } 47      48     /** 49      * 还原私钥 50      * @param priKey 二进制私钥 51      */ 52     public static PrivateKey toPrivateKey(byte[] priKey) throws NoSuchAlgorithmException,  53                                                                 InvalidKeySpecException{ 54         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);//密钥工厂 55         return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(priKey));//还原私钥 56     } 57      58     /** 59      * 私钥加密(签名) 60      * @param data     待加密数据 61      * @param keyByte  私钥 62      */ 63     public static byte[] encryptPriKey(String data, byte[] keyByte) throws NoSuchAlgorithmException,  64                                                                            InvalidKeySpecException,  65                                                                            InvalidKeyException,  66                                                                            SignatureException,  67                                                                            UnsupportedEncodingException { 68         PrivateKey priKey = toPrivateKey(keyByte);//还原私钥 69  70         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); 71         signature.initSign(priKey); 72         signature.update(data.getBytes(ENCODING)); 73          74         return signature.sign(); 75     } 76      77     /** 78      * 公钥解密(验证) 79      * @param data        原文(待加密数据,也成为“待校验数据”) 80      * @param keyByte    公钥 81      * @param sign        密文(也称作“签名”) 82      */ 83     public static boolean decryptPubKey(String data, byte[] keyByte, byte[] sign) throws NoSuchAlgorithmException,  84                                                                                          InvalidKeySpecException,  85                                                                                          InvalidKeyException,  86                                                                                          SignatureException,  87                                                                                          UnsupportedEncodingException { 88         PublicKey pubKey = toPublicKey(keyByte);//还原公钥 89          90         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); 91         signature.initVerify(pubKey); 92         signature.update(data.getBytes(ENCODING)); 93          94         return signature.verify(sign); 95     } 96      97     /** 98      * 获取公钥 99      */100     public static byte[] getPublicKey(KeyPair keyPair){101         return keyPair.getPublic().getEncoded();102     }103     104     /**105      * 获取私钥106      */107     public static byte[] getPrivateKey(KeyPair keyPair){108         return keyPair.getPrivate().getEncoded();109     }110     111     /**112      * 测试113      */114     public static void main(String[] args) throws NoSuchAlgorithmException, 115                                                   InvalidKeyException, 116                                                   InvalidKeySpecException, 117                                                   SignatureException, 118                                                   UnsupportedEncodingException {119         byte[] pubKey1;//甲方公钥120         byte[] priKey1;//甲方私钥121         122         /*********************测试是否可以正确生成以上2个key*********************/123         KeyPair keyPair1 = RSACoderBC.initKey();//生成甲方密钥对124         pubKey1 = RSACoderBC.getPublicKey(keyPair1);125         priKey1 = RSACoderBC.getPrivateKey(keyPair1);126         127         System.out.println("甲方公钥pubKey1-->"+Base64.encodeBase64String(pubKey1)+"@@pubKey1.length-->"+pubKey1.length);128         System.out.println("甲方私钥priKey1-->"+Base64.encodeBase64String(priKey1)+"@@priKey1.length-->"+priKey1.length);129         130         /*********************测试甲方使用私钥加密数据向乙方发送,乙方使用公钥解密数据*********************/131         System.out.println("甲方-->乙方");132         String data = "找一个好姑娘啊!你好吗,孩子";133         byte[] encodeStr = RSACoderBC.encryptPriKey(data, priKey1);//加密(签名)134         System.out.println("甲方加密后的数据-->"+Base64.encodeBase64String(encodeStr)+"@@encodeStr.length-->"+encodeStr.length);135         boolean decodeStr = RSACoderBC.decryptPubKey(data, pubKey1, encodeStr);136         System.out.println("乙方检验结果-->"+decodeStr);137     }138 }
View Code

注意点:

  • 代码与RSA非对称加密算法(查看第十二章)基本一样,只是将其中的私钥加密与公钥解密部分的加解密算法改为签名和验证算法,当然没有“公钥加密,私钥解密”

疑问:在《Java加密与解密的艺术(第二版)》一书中,作者说:“RSA数字签名算法的签名值与密钥长度相同”,但是在我的测试中,结果不一致:

1)在我配置非对称密钥为512的时候,测出来的公钥长度是96位,私钥长度是345位,与512差很远,那这里的512到底是怎么计算的?

2)消息摘要的结果长度是64(摘要值的二进制自己数组长度),不知道到底是怎么与密钥长度相同的?

以上两个问题,有知道的朋友请指点一下,谢谢!

 

转载地址:http://niesl.baihongyu.com/

你可能感兴趣的文章
ZOJ 3626(树形DP+背包+边cost)
查看>>
NanoHttpd
查看>>
使用FTPClient进行文件服务器内文件的上传和下载
查看>>
Spring IoC — 基于注解的配置
查看>>
我看项目管理第一回:认识利益相关方,提高思想意识
查看>>
使用git进行版本管理
查看>>
数据结构--树,二叉树
查看>>
MySQL优化—工欲善其事,必先利其器之EXPLAIN
查看>>
mysql性能优化学习笔记
查看>>
禁止 favicon.ico 请求
查看>>
CSS隐藏元素的N种实现方式。
查看>>
Hadoop概念学习系列之为什么hadoop/spark执行作业时,输出路径必须要不存在?(三十九)...
查看>>
UVa567_Risk(最短路)(小白书图论专题)
查看>>
Redis Sentinel实现的机制与原理详解
查看>>
nginx php-fpm安装手记
查看>>
spring注解工具类AnnotatedElementUtils和AnnotationUtils
查看>>
[转]简单介绍如何使用robotium进行自动化测试
查看>>
post和get的区别?
查看>>
android 滚动视图(ScrollView)
查看>>
无限级别菜单下拉
查看>>