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

相关文章

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.