RSA加密解密及数字签名Java实现及部分原理

简介:

转载至:

https://my.oschina.net/jiangli0502/blog/171263

参考:

http://blog.csdn.net/he_qiao/article/details/44758711


如果大家对RSA算法原理很感兴趣,推荐下面这两篇文章:

http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html

http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html


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
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
        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
/**
      * 初始化密钥
      * @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
/**
      * 取得公钥,并转化为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
/**
      * 用私钥加密
      * @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
/**
      * 用私钥解密 * @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
/**
      * 用公钥加密
      * @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
/**
      * 用公钥解密
      * @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
/**
      * 用私钥对信息生成数字签名
      * @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
/**
      * 校验数字签名
      * @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));
         
     }

       对于RSA如何加密文件、图片等信息,加密的信息又如何保存,怎样保存解密后的信息,以及操作过程中遇到的错误将如何处理,将在后面的文章中介绍给大家。 






      本文转自建波李 51CTO博客,原文链接:http://blog.51cto.com/jianboli/1886907,如需转载请自行联系原作者



相关文章
|
存储 缓存 Java
我们来详细讲一讲 Java NIO 底层原理
我是小假 期待与你的下一次相遇 ~
434 2
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
352 0
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
398 0
|
存储 算法 安全
Java中的对称加密算法的原理与实现
本文详细解析了Java中三种常用对称加密算法(AES、DES、3DES)的实现原理及应用。对称加密使用相同密钥进行加解密,适合数据安全传输与存储。AES作为现代标准,支持128/192/256位密钥,安全性高;DES采用56位密钥,现已不够安全;3DES通过三重加密增强安全性,但性能较低。文章提供了各算法的具体Java代码示例,便于快速上手实现加密解密操作,帮助用户根据需求选择合适的加密方案保护数据安全。
901 58
|
人工智能 安全 Java
Go与Java泛型原理简介
本文介绍了Go与Java泛型的实现原理。Go通过单态化为不同类型生成函数副本,提升运行效率;而Java则采用类型擦除,将泛型转为Object类型处理,保持兼容性但牺牲部分类型安全。两种机制各有优劣,适用于不同场景。
656 24
|
XML JSON Java
Java 反射:从原理到实战的全面解析与应用指南
本文深度解析Java反射机制,从原理到实战应用全覆盖。首先讲解反射的概念与核心原理,包括类加载过程和`Class`对象的作用;接着详细分析反射的核心API用法,如`Class`、`Constructor`、`Method`和`Field`的操作方法;最后通过动态代理和注解驱动配置解析等实战场景,帮助读者掌握反射技术的实际应用。内容翔实,适合希望深入理解Java反射机制的开发者。
1029 13
|
算法 Java 索引
说一说 Java 并发队列原理剖析
我是小假 期待与你的下一次相遇 ~
139 1
|
安全 Java 编译器
JD-GUI,java反编译工具及原理: JavaDecompiler一个Java反编译器
Java Decompiler (JD-GUI) 是一款由 Pavel Kouznetsov 开发的图形化 Java 反编译工具,支持 Windows、Linux 和 Mac Os。它能将 `.class` 文件反编译为 Java 源代码,支持多文件标签浏览、高亮显示,并兼容 Java 5 及以上版本。JD-GUI 支持对整个 Jar 文件进行反编译,可跳转源码,适用于多种 JDK 和编译器。其原理基于将字节码转换为抽象语法树 (AST),再通过反编译生成代码。尽管程序可能带来安全风险,但可通过代码混淆降低可读性。最新版修复了多项识别错误并优化了内存管理。
10887 1
|
存储 Java 数据安全/隐私保护
Java技术栈揭秘:Base64加密和解密文件的实战案例
以上就是我们今天关于Java实现Base64编码和解码的实战案例介绍。希望能对你有所帮助。还有更多知识等待你去探索和学习,让我们一同努力,继续前行!
717 5