现实中的文件和书信我们可以通过印章来确定它的有效和可信性,那么在计算机网络中传送的报文如何保证呢?这就是数字签名要解决的问题。
数字签名必须能保证以下3点
1.接收者能够核实发送者对报文的签名。
2.发送者事后不能抵赖对报文的签名。
3.接收者不能伪造对报文的签名。
目前已经存在着各种各样数字签名方法。今天为大家介绍一种java中比较容易实现的公开密钥算法来做数字签名。首先介绍一下公开密钥算法实现数字签名的原理:
公开密钥算法有以下特点:
1.加密密钥PK对明文X加密后,用解密密钥SK解密即可恢复出原明文。另外加密和解密运算可以互换。
公式为:Dsk(Epk(X))=X 和Epk(Dsk(X))=X
2.加密密钥PK是公开的,但通过PK无法推导出SK
这2个特点正好满足了数字签名的3点要求。下图是用公开密钥算法实现数字签名的原理图
有了以上的知识用java来实现这个数字签名就很容易了,通过java.security里面有RSA和DSA公开密钥算法的实现。
下面是部分代码
generateKeypair方法生成PK和SK,你只需要把SK保存下来用
public static void generateKeypair() {
KeyPairGenerator keyGen;
FileOutputStream out = null;
try {
keyGen = KeyPairGenerator.getInstance("DSA");// 指定使用DSA算法
keyGen.initialize(1024, new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
pk = pair.getPublic();
sk = pair.getPrivate();
out = new FileOutputStream(System.getProperty("user.dir")
+ "\\sk.dat");
String tmpsk = StringUtil.encodeHex(sk.getEncoded());
out.write(tmpsk.getBytes());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
generateSignature方法通过sk对明文进行签名,返回值是对明文的签名
public String generateSignature(File inFile, PrivateKey privKey) {
Signature dsa;
FileInputStream fis = null;
try {
dsa = Signature.getInstance("DSA");
dsa.initSign(privKey);
fis = new FileInputStream(inFile);
SAXReader reader = new SAXReader();
Document doc = reader.read(fis);
dsa.update(doc.asXML().getBytes());
byte[] signature = dsa.sign();
return StringUtil.encodeHex(signature);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
validData方法对收到的数据进行签名验证
public boolean validData (byte[] data,String publicKey,String signature) {
try { // valid the file with public key and signature
byte[] encodedpubKey = StringUtil.decodeHex(publicKey);
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(
encodedpubKey);
KeyFactory keyFactory;
keyFactory = KeyFactory.getInstance("DSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
byte[] sign = StringUtil.decodeHex(signature);
Signature s = Signature.getInstance("DSA");
s.initVerify(pubKey);
s.update(data);
boolean flag = s.verify(sign);
return flag;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
}
return false;
}