网络加密解密原理(二) 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

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推