

接收方要确保收到的消息是正确的发送者,即确保消息的发送者是其声称的身份,防止假冒。数字签名可以保证一旦消息在传输过程中被篡改,接受方通过验证签名即可发现。
数字签名作用类似现实生活中的手写签名,但它是基于复杂的密码学算法,安全性更高。生活中的手写签名容易被模仿或伪造,而破解数字签名需要极高的计算能力和技术手段。
需要注意的是,和通常公钥、私钥的角色刚好相反:消息发送方即负责数字签名一方使用私钥签名,消息接受方负责使用公约验证签名。
1. 数字签名
消息发送方对要发送的消息(明文)进行哈希运算,生成消息的哈希值(也称此哈希值是消息的摘要)。哈希函数会将任意长度的消息转换为固定长度的哈希值,并且不同的消息生成相同哈希值的概率极低。发送方使用自己的私钥对生成的哈希值进行加密,得到数字签名。由于私钥只有发送方拥有,所以这个签名可以证明消息是由发送方发出的。
java.security包中的Signature类的实例负责实施数字签名,
(1)使用Signature类的静态方法
static Signature getInstance(String algorithm)
返回一个Signature类的实例,例如:
Signature signature = Signature.getInstance("SHA256withRSA");
其中参数algorithm取值"SHA256withRSA"表示使用SHA256哈希算法和RSA提供的私钥实施数字签名。
(2)Signature类的实例调用
final void initSign(PrivateKey privateKey)
方法确定所使用的私钥,例如使用RSA生成的私钥privateKey:
signature.initSign(privateKey);(3)Signature类的实例调用下列update()方法把数据data或data的一部分添加到 Signature类的实例内部的缓冲区中(不会消除此方法已经添加到缓冲区的已有内容):
final void update(byte[] data)final void update(byte[] data, int off, int len)
(4)最后Signature类的实例调用sign()方法对其缓冲区的内容实施签名,并返回签名。例如:
byte[] signBytes = signature.sign();2.验证签名
接收方收的角色是客户,客户收到被签名消息后,使用发送方给的公钥验证此消息的数字签名,如果消息在传输过程中没有被篡改,就会验证成功。
(1)使用Signature类的静态方法
static Signature getInstance(String algorithm)
返回一个Signature类的实例,例如:
Signature signature = Signature.getInstance("SHA256withRSA");其中参数 algorithm取值"SHA256withRSA"表示使用 SHA256 哈希算法验和RSA提供的公钥实施验证。
(2)Signature类的实例调用
final void initVerify(PublicKey publicKey)
方法确定所使用的公钥,例如使用RSA生成的公钥publicKey:
signature.initVerify(publicKey);(3)Signature类的实例调用下列update()方法要将要验证的原始数据添加到signature的缓冲区:
final void update(byte[] data)final void update(byte[] data, int off, int len)
(4)最后Signature类的实例调用
final boolean verify(byte[] signature)
方法验证收到的消息的数字签名,并返回一个boolean值,如果boolean值是true表示验证成功,否则验证失败。例如:boolean isSuccess = signature.verify();例子3.5给文件实施数字签名并验证文件的数字签名。

import java.security.*;import java.io.*;public class Ex3_5 {// 生成密钥对public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048);return keyPairGenerator.generateKeyPair();}// 数字签名public static byte[] signData(File file, PrivateKey privateKey) throws Exception {Signature signature = Signature.getInstance("SHA256withRSA");signature.initSign(privateKey);FileInputStream in = new FileInputStream(file);byte []data = new byte[256];int n = -1;while((n = in.read(data))!=-1){signature.update(data,0,n);//向缓冲区怎加新内容}//signature对其缓冲区的内容实施数字签名byte[] signBytes = signature.sign();return signBytes;}// 验证数字签名public static boolean verifyData(File file, byte[] signatureBytes, PublicKey publicKey) throws Exception {Signature signature = Signature.getInstance("SHA256withRSA");signature.initVerify(publicKey);// 将要验证的原始数据添加到signature的缓冲区FileInputStream in = new FileInputStream(file);byte []data = new byte[256];int n = -1;while((n = in.read(data))!=-1){signature.update(data,0,n);}// 验证签名return signature.verify(signatureBytes);}public static void main(String[] args) {try {// 生成密钥对KeyPair keyPair = generateKeyPair();PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey = keyPair.getPublic();File file = new File("Ex3_5.java");System.out.println("发送方对\'"+file.getName()+"\'进行数字签名");// 进行签名byte[] signature = signData(file, privateKey);System.out.println("我的数字签名:\n " + java.util.Arrays.toString(signature));System.out.println("接受方收到\'"+file.getName()+"\'进行验证");// 验证文件签名boolean isValid = verifyData(file, signature, publicKey);System.out.println("签名验证结果: " + isValid);file = new File("Ex3_4.java");System.out.println("接受方收到\'"+file.getName()+"\'进行验证:");// 验证文件签名isValid = verifyData(file, signature, publicKey);System.out.println("签名验证结果: " + isValid);} catch (Exception e) {e.printStackTrace();}}}