网络加密解密原理(二) RSA加密解密及数字签名Java实现

2024-05-08 02:18

本文主要是介绍网络加密解密原理(二) RSA加密解密及数字签名Java实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

RSA公钥加密算法 是1977年由 罗纳德·李维斯特 (Ron Rivest)、阿迪·萨莫尔 (Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院 工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

    RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密算法

    RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。

    关于RSA算法的原理,这里就不再详加介绍,网上各种资源一大堆。下面就开始介绍RSA加密解密JAVA类的具体实现。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import  java.security.MessageDigest;
import  sun.misc.BASE64Decoder;
import  sun.misc.BASE64Encoder;
public  class  Coder {
     
     public  static  final  String KEY_SHA= "SHA" ;
     public  static  final  String KEY_MD5= "MD5" ;
     
     /**
      * BASE64解密
      * @param key
      * @return
      * @throws Exception
      */
     public  static  byte [] decryptBASE64(String key)  throws  Exception{
         return  ( new  BASE64Decoder()).decodeBuffer(key);
     }
     
     /**
      * BASE64加密
      * @param key
      * @return
      * @throws Exception
      */
     public  static  String encryptBASE64( byte [] key) throws  Exception{
         return  ( new  BASE64Encoder()).encodeBuffer(key);
     }
     
     /**
      * MD5加密
      * @param data
      * @return
      * @throws Exception
      */
     public  static  byte [] encryptMD5( byte [] data) throws  Exception{
         MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
         md5.update(data);
         return  md5.digest();
     }
     
     /**
      * SHA加密
      * @param data
      * @return
      * @throws Exception
      */
     public  static  byte [] encryptSHA( byte [] data) throws  Exception{
         MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
         sha.update(data);
         return  sha.digest();
     }
}

     先提供Coder编码类,该类封装了基本的Base64、md5和SHA加密解密算法。Java对这些算法的实现提供了很好的API封装,开发人员只需调用这些API就可很简单方便的实现数据的加密与解密。

    下面提供RSA加密解密类,该类为Coder类子类,因为其中对RSA公私密钥的保存进行了一层Base64加密处理。

    RSA加密解密类静态常量

?
1
2
3
4
5
        public  static  final  String KEY_ALGORTHM= "RSA" ; //
     public  static  final  String SIGNATURE_ALGORITHM= "MD5withRSA" ;
     
     public  static  final  String PUBLIC_KEY =  "RSAPublicKey" ; //公钥
     public  static  final  String PRIVATE_KEY =  "RSAPrivateKey" ; //私钥



    RSA加密解密的实现,需要有一对公私密钥,公私密钥的初始化如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
      * 初始化密钥
      * @return
      * @throws Exception
      */
     public  static  Map<String,Object> initKey() throws  Exception{
         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORTHM);
         keyPairGenerator.initialize( 1024 );
         KeyPair keyPair = keyPairGenerator.generateKeyPair();
         
         //公钥
         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
         //私钥
         RSAPrivateKey privateKey =  (RSAPrivateKey) keyPair.getPrivate();
         
         Map<String,Object> keyMap =  new  HashMap<String, Object>( 2 );
         keyMap.put(PUBLIC_KEY, publicKey);
         keyMap.put(PRIVATE_KEY, privateKey);
         
         return  keyMap;
     }

      从代码中可以看出密钥的初始化长度为1024位,密钥的长度越长,安全性就越好,但是加密解密所用的时间就会越多。而一次能加密的密文长度也与密钥的长度成正比。一次能加密的密文长度为:密钥的长度/8-11。所以1024bit长度的密钥一次可以加密的密文为1024/8-11=117bit。所以非对称加密一般都用于加密对称加密算法的密钥,而不是直接加密内容。对于小文件可以使用RSA加密,但加密过程仍可能会使用分段加密。

    从map中获取公钥、私钥

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
      * 取得公钥,并转化为String类型
      * @param keyMap
      * @return
      * @throws Exception
      */
     public  static  String getPublicKey(Map<String, Object> keyMap) throws  Exception{
         Key key = (Key) keyMap.get(PUBLIC_KEY);  
         return  encryptBASE64(key.getEncoded());     
     }
     /**
      * 取得私钥,并转化为String类型
      * @param keyMap
      * @return
      * @throws Exception
      */
     public  static  String getPrivateKey(Map<String, Object> keyMap)  throws  Exception{
         Key key = (Key) keyMap.get(PRIVATE_KEY);  
         return  encryptBASE64(key.getEncoded());     
     }


    对于RSA产生的公钥、私钥,我们可以有两种方式可以对信息进行加密解密。私钥加密-公钥解密 和 公钥加密-私钥解密。
 

    私钥加密

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
      * 用私钥加密
      * @param data   加密数据
      * @param key    密钥
      * @return
      * @throws Exception
      */
     public  static  byte [] encryptByPrivateKey( byte [] data,String key) throws  Exception{
         //解密密钥
         byte [] keyBytes = decryptBASE64(key);
         //取私钥
         PKCS8EncodedKeySpec pkcs8EncodedKeySpec =  new  PKCS8EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
         Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
         
         //对数据加密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, privateKey);
         
         return  cipher.doFinal(data);
     }

   私钥解密

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
      * 用私钥解密 * @param data    加密数据
      * @param key    密钥
      * @return
      * @throws Exception
      */
     public  static  byte [] decryptByPrivateKey( byte [] data,String key) throws  Exception{
         //对私钥解密
         byte [] keyBytes = decryptBASE64(key);
         
         PKCS8EncodedKeySpec pkcs8EncodedKeySpec =  new  PKCS8EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
         Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
         //对数据解密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, privateKey);
         
         return  cipher.doFinal(data);
     }

    公钥加密

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
      * 用公钥加密
      * @param data   加密数据
      * @param key    密钥
      * @return
      * @throws Exception
      */
     public  static  byte [] encryptByPublicKey( byte [] data,String key) throws  Exception{
         //对公钥解密
         byte [] keyBytes = decryptBASE64(key);
         //取公钥
         X509EncodedKeySpec x509EncodedKeySpec =  new  X509EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
         Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
         
         //对数据解密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
         
         return  cipher.doFinal(data);
     }

    私钥加密

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
      * 用公钥解密
      * @param data   加密数据
      * @param key    密钥
      * @return
      * @throws Exception
      */
     public  static  byte [] decryptByPublicKey( byte [] data,String key) throws  Exception{
         //对私钥解密
         byte [] keyBytes = decryptBASE64(key);
         X509EncodedKeySpec x509EncodedKeySpec =  new  X509EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
         Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
         
         //对数据解密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, publicKey);
         
         return  cipher.doFinal(data);
     }

    关于数字签名,先了解下何为数字签名。数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。数字签名是非对称密钥加密技术与数字摘要技术的应用。简单地说,所谓数字签名就是附加在数据单元上的一些数据,或是对数据单元所作的密码变换。这种数据或变换允许数据单元的接收者用以确认数据单元的来源和数据单元的完整性并保护数据,防止被人(例如接收者)进行伪造。

    数字签名的主要功能如下:
 

    保证信息传输的完整性、发送者的身份认证、防止交易中的抵赖发生。

    数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。

    数字签名是个加密的过程,数字签名验证是个解密的过程。

     数字签名算法依靠公钥加密技术来实现的。在公钥加密技术里,每一个使用者有一对密钥:一把公钥和一把私钥。公钥可以自由发布,但私钥则秘密保存;还有一个要求就是要让通过公钥推算出私钥的做法不可能实现。

    普通的数字签名算法包括三种算法:

    1.密码生成算法;

    2.标记算法;

   3.验证算法

    通过RSA加密解密算法,我们可以实现数字签名的功能。我们可以用私钥对信息生成数字签名,再用公钥来校验数字签名,当然也可以反过来公钥签名,私钥校验。

    私钥签名
 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
      * 用私钥对信息生成数字签名
      * @param data   //加密数据
      * @param privateKey //私钥
      * @return
      * @throws Exception
      */
     public  static  String sign( byte [] data,String privateKey) throws  Exception{
         //解密私钥
         byte [] keyBytes = decryptBASE64(privateKey);
         //构造PKCS8EncodedKeySpec对象
         PKCS8EncodedKeySpec pkcs8EncodedKeySpec =  new  PKCS8EncodedKeySpec(keyBytes);
         //指定加密算法
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
         //取私钥匙对象
         PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
         //用私钥对信息生成数字签名
         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
         signature.initSign(privateKey2);
         signature.update(data);
         
         return  encryptBASE64(signature.sign());
     }

    公钥校验


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
      * 校验数字签名
      * @param data   加密数据
      * @param publicKey  公钥
      * @param sign   数字签名
      * @return
      * @throws Exception
      */
     public  static  boolean  verify( byte [] data,String publicKey,String sign) throws  Exception{
         //解密公钥
         byte [] keyBytes = decryptBASE64(publicKey);
         //构造X509EncodedKeySpec对象
         X509EncodedKeySpec x509EncodedKeySpec =  new  X509EncodedKeySpec(keyBytes);
         //指定加密算法
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
         //取公钥匙对象
         PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec);
         
         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
         signature.initVerify(publicKey2);
         signature.update(data);
         //验证签名是否正常
         return  signature.verify(decryptBASE64(sign));
         
     }

      


转:http://my.oschina.net/jiangli0502/blog/171263

这篇关于网络加密解密原理(二) RSA加密解密及数字签名Java实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/969018

相关文章

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

AJAX请求上传下载进度监控实现方式

《AJAX请求上传下载进度监控实现方式》在日常Web开发中,AJAX(AsynchronousJavaScriptandXML)被广泛用于异步请求数据,而无需刷新整个页面,:本文主要介绍AJAX请... 目录1. 前言2. 基于XMLHttpRequest的进度监控2.1 基础版文件上传监控2.2 增强版多

Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

《SpringSecurity方法级安全控制@PreAuthorize注解的灵活运用小结》本文将带着大家讲解@PreAuthorize注解的核心原理、SpEL表达式机制,并通过的示例代码演示如... 目录1. 前言2. @PreAuthorize 注解简介3. @PreAuthorize 核心原理解析拦截与

一文详解JavaScript中的fetch方法

《一文详解JavaScript中的fetch方法》fetch函数是一个用于在JavaScript中执行HTTP请求的现代API,它提供了一种更简洁、更强大的方式来处理网络请求,:本文主要介绍Jav... 目录前言什么是 fetch 方法基本语法简单的 GET 请求示例代码解释发送 POST 请求示例代码解释

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Redis分片集群的实现

《Redis分片集群的实现》Redis分片集群是一种将Redis数据库分散到多个节点上的方式,以提供更高的性能和可伸缩性,本文主要介绍了Redis分片集群的实现,具有一定的参考价值,感兴趣的可以了解一... 目录1. Redis Cluster的核心概念哈希槽(Hash Slots)主从复制与故障转移2.

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

使用Python实现一键隐藏屏幕并锁定输入

《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

Mybatis 传参与排序模糊查询功能实现

《Mybatis传参与排序模糊查询功能实现》:本文主要介绍Mybatis传参与排序模糊查询功能实现,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、#{ }和${ }传参的区别二、排序三、like查询四、数据库连接池五、mysql 开发企业规范一、#{ }和${ }传参的