一、数字签名算法概述

   签名认证是对非对称加密技术与数字摘要技术的综合运用,指的是将通信内容的摘要信息使用发送者的私钥进行加密,然后将密文与原文一起传输给信息的接收者,接收者通过发送者的公钥信息来解密被加密的摘要作息,然后使用与发送者相同的摘要算法,对接收到的内容采用相同的方式方式产生摘要串,与解密的摘要串进行对比,如果相同,则说明接收到的内容是完整的,在传输过程中没有受到第三方的篡改,否则说明通信内容已被第三方修改。

   我们知道,每个人都有其特有的私钥,且都是对外界保密的,而通过私钥加密的信息,只能通过其对应的公钥来进行解密。因此,私钥可以代表私钥持有者的身份,可以通过私钥对应的公钥来对私钥拥有者的身份进行校验。通过数字签名,能够确认消息是消息发送方签名并发送过来的,因为其他人根本假冒不了消息发送方的签名,他们没有消息发送者的私钥。而不同的内容,摘要信息千差万别,通过数字摘要算法,可以确保传输内容的完整性,如果传输内容在中途被篡改了,对应的数字签名的值也将发生改变。

数字签名:带有密钥(公钥,私钥)的消息摘要算法。私钥用于签名,公钥用于验证。

数字签名的作用:

   验证数据的完整性,认证数据来源,抗否认。

数字签名实现的具体原理: 
   1、 将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证,只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。(详见参考资料的"公钥密码技术原理"章节)
   2、 将该报文摘要值用发送者的私人密钥加密,然后连同原报文和数字证书(包含公钥)一起发送给接收者而产生的报文即称数字签名。
   3、接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较,如相等则说明报文确实来自所称的发送者。
   4、同时通过证书颁发机构CA确认证书的有效性即可确认发送的真实身份。

数字签名的产生过程如图如示:

   

JAVA 数字签名验证 java实现数字签名_ooc

数字签名的校验过程:

   

JAVA 数字签名验证 java实现数字签名_java_02

  

常用的数字签名有:RSA、DSA、ECDSA


二、数字签名算法—RSA

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

   特性:安全性抗和否认性

   主要包括两类:MD、SHA

   具体算法如下图:

   

JAVA 数字签名验证 java实现数字签名_java_03

   例子:


[java]  view plain  copy


    1. package rmd_intl_app.Test;  
    2. import java.security.KeyFactory;  
    3. import java.security.KeyPair;  
    4. import java.security.KeyPairGenerator;  
    5. import java.security.PrivateKey;  
    6. import java.security.PublicKey;  
    7. import java.security.Signature;  
    8. import java.security.interfaces.RSAPrivateKey;  
    9. import java.security.interfaces.RSAPublicKey;  
    10. import java.security.spec.PKCS8EncodedKeySpec;  
    11. import java.security.spec.X509EncodedKeySpec;  
    12.   
    13. import org.apache.commons.codec.binary.Hex;  
    14.   
    15. public class ImoocRSA {  
    16.       
    17. private static String src = "imooc security rsa";  
    18.   
    19. public static void main(String[] args) {  
    20.         jdkRSA();  
    21.     }  
    22.       
    23. public static void jdkRSA() {  
    24. try {  
    25. //1.初始化密钥  
    26. "RSA");  
    27. 512);  
    28.             KeyPair keyPair = keyPairGenerator.generateKeyPair();  
    29.             RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();  
    30.             RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();  
    31.               
    32. //2.执行签名  
    33. new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());  
    34. "RSA");  
    35.             PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);  
    36. "MD5withRSA");  
    37.             signature.initSign(privateKey);  
    38.             signature.update(src.getBytes());  
    39. byte[] result = signature.sign();  
    40. "jdk rsa sign : " + Hex.encodeHexString(result));  
    41.               
    42. //3.验证签名  
    43. new X509EncodedKeySpec(rsaPublicKey.getEncoded());  
    44. "RSA");  
    45.             PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);  
    46. "MD5withRSA");  
    47.             signature.initVerify(publicKey);  
    48.             signature.update(src.getBytes());  
    49. boolean bool = signature.verify(result);  
    50. "jdk rsa verify : " + bool);  
    51. catch (Exception e) {  
    52.             e.printStackTrace();  
    53.         }  
    54.     }  
    55.   
    56. }



    三、数字签名算法—DSA

       DSA是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSfS(DigitalSignature Standard)。
       DSA是基于整数有限域离散对数难题的,其安全性与RSA相比差不多。DSA的一个重要特点是两个素数公开,这样,当使用别人的p和q时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。RSA却做不到。

        DSA仅包含数字签名

        具体算法如下图:

        

    JAVA 数字签名验证 java实现数字签名_ooc_04

        例子:


    [java]  view plain  copy


      1. package com.imooc.security.dsa;  
      2.   
      3. import java.security.KeyFactory;  
      4. import java.security.KeyPair;  
      5. import java.security.KeyPairGenerator;  
      6. import java.security.PrivateKey;  
      7. import java.security.PublicKey;  
      8. import java.security.Signature;  
      9. import java.security.interfaces.DSAPrivateKey;  
      10. import java.security.interfaces.DSAPublicKey;  
      11. import java.security.spec.PKCS8EncodedKeySpec;  
      12. import java.security.spec.X509EncodedKeySpec;  
      13.   
      14. import org.apache.commons.codec.binary.Hex;  
      15.   
      16. public class ImoocDSA {  
      17.       
      18. private static String src = "imooc security dsa";  
      19.   
      20. public static void main(String[] args) {  
      21.         jdkDSA();  
      22.     }  
      23.       
      24. public static void jdkDSA() {  
      25. try {  
      26. //1.初始化密钥  
      27. "DSA");  
      28. 512);  
      29.             KeyPair keyPair = keyPairGenerator.generateKeyPair();  
      30.             DSAPublicKey dsaPublicKey = (DSAPublicKey) keyPair.getPublic();  
      31.             DSAPrivateKey dsaPrivateKey = (DSAPrivateKey)keyPair.getPrivate();  
      32.               
      33. //2.执行签名  
      34. new PKCS8EncodedKeySpec(dsaPrivateKey.getEncoded());  
      35. "DSA");  
      36.             PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);  
      37. "SHA1withDSA");  
      38.             signature.initSign(privateKey);  
      39.             signature.update(src.getBytes());  
      40. byte[] result = signature.sign();  
      41. "jdk dsa sign : " + Hex.encodeHexString(result));  
      42.               
      43. //3.验证签名  
      44. new X509EncodedKeySpec(dsaPublicKey.getEncoded());  
      45. "DSA");  
      46.             PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);  
      47. "SHA1withDSA");  
      48.             signature.initVerify(publicKey);  
      49.             signature.update(src.getBytes());  
      50. boolean bool = signature.verify(result);  
      51. "jdk dsa verify : " + bool);  
      52. catch (Exception e) {  
      53.             e.printStackTrace();  
      54.         }  
      55.     }  
      56.   
      57. }


      四、数字签名算法—ECDSA

         ECDSA: 椭圆曲线数字签名算法(Elliptic Curve Digital Signatrue Algorithm)

         特点:速度快,强度高,签名短

         具体算法如下图:

         

      JAVA 数字签名验证 java实现数字签名_数字签名_05

         例子:


      [java]  view plain  copy


        1. package com.imooc.security.ecdsa;  
        2.   
        3. import java.security.KeyFactory;  
        4. import java.security.KeyPair;  
        5. import java.security.KeyPairGenerator;  
        6. import java.security.NoSuchAlgorithmException;  
        7. import java.security.PrivateKey;  
        8. import java.security.PublicKey;  
        9. import java.security.Signature;  
        10. import java.security.interfaces.ECPrivateKey;  
        11. import java.security.interfaces.ECPublicKey;  
        12. import java.security.spec.PKCS8EncodedKeySpec;  
        13. import java.security.spec.X509EncodedKeySpec;  
        14.   
        15. import org.apache.commons.codec.binary.Hex;  
        16.   
        17. public class ImoocECDSA {  
        18.       
        19. private static String src = "imooc security ecdsa";  
        20.   
        21. public static void main(String[] args) {  
        22.         jdkECDSA();  
        23.     }  
        24.       
        25. public static void jdkECDSA() {  
        26. try {  
        27. //1.初始化密钥  
        28. "EC");  
        29. 256);  
        30.             KeyPair keyPair = keyPairGenerator.generateKeyPair();  
        31.             ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic();  
        32.             ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate();  
        33.               
        34. //2.执行签名  
        35. new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded());  
        36. "EC");  
        37.             PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);  
        38. "SHA1withECDSA");  
        39.             signature.initSign(privateKey);  
        40.             signature.update(src.getBytes());  
        41. byte[] result = signature.sign();  
        42. "jdk ecdsa sign : " + Hex.encodeHexString(result));  
        43.               
        44. //3.验证签名  
        45. new X509EncodedKeySpec(ecPublicKey.getEncoded());  
        46. "EC");  
        47.             PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);  
        48. "SHA1withECDSA");  
        49.             signature.initVerify(publicKey);  
        50.             signature.update(src.getBytes());  
        51. boolean bool = signature.verify(result);  
        52. "jdk ecdsa verify : " + bool);  
        53. catch (Exception e) {  
        54.             e.printStackTrace();  
        55.         }  
        56.           
        57.     }  
        58.   
        59. }  
        60.