RSA加密解密及数字签名

  • 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));
             
         }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
OpenSSL是一个开源的加密库,它提供了RSA加密、解密、签名和验签的功能。 对于RSA加密和解密,我们可以使用OpenSSL提供的命令行工具或者API来实现。 使用命令行工具,我们可以通过以下命令进行RSA加密: openssl rsautl -encrypt -in <input file> -out <output file> -inkey <public key file> -pubin 其中,<input file>是要加密的文件,<output file>是加密后的文件,<public key file>是存储公钥的文件,-pubin参数表示输入的是公钥。 使用命令行工具,我们可以通过以下命令进行RSA解密: openssl rsautl -decrypt -in <input file> -out <output file> -inkey <private key file> 其中,<input file>是要解密的文件,<output file>是解密后的文件,<private key file>是存储私钥的文件。 对于RSA签名和验签,我们可以使用以下命令进行签名: openssl rsautl -sign -in <input file> -out <output file> -inkey <private key file> 其中,<input file>是要签名的文件,<output file>是签名后的文件,<private key file>是存储私钥的文件。 使用以下命令进行验签: openssl rsautl -verify -in <input file> -out <output file> -inkey <public key file> -pubin 其中,<input file>是要验签的文件,<output file>是验签后的文件,<public key file>是存储公钥的文件,-pubin参数表示输入的是公钥。 使用OpenSSL的API进行RSA加密、解密、签名和验签的操作也是类似的,我们可以通过调用相应的函数来实现。需要注意的是,API的使用需要在代码中显式引入OpenSSL的头文件和链接OpenSSL的库文件。 总之,OpenSSL提供了便捷的工具和API来实现RSA加密、解密、签名和验签的功能,无论是命令行工具还是API,都可以选择合适的方式进行操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值