签名在生活中十分常见。当我们办理证件、签署协议时往往需要我们手动签名。签名的作用一是别人无法伪造,即唯一性;二是签上名之后我们也无法否认这种签名的行为与我们无关,即抗否认性。数字签名的作用与手动签名相差无几,即验证数据的完整、来源以及抗否认。
数字签名的应用在网上可以找到很多例子。这里可以参考某博主的文章。
数字签名是带密钥的消息摘要算法。密码学中有一个柯克霍夫原则——密码系统应该就算被所有人知道系统的运作步骤,仍然是安全的。这也是现代密码学设计的基本原则,即数据的安全基于密钥也不是算法,也就是说密钥是保密的,算法是公开的。
数字签名算法包括:RSA、DSA、ECDSA
RSA是数字签名的一个经典算法,也是非对称加密算法的一个应用十分广泛的经典算法。它结合消息摘要算法中的MD类和SHA类,包括了以下几种算法:
算法 | 密钥长度 | 默认长度 | 签名长度 | 实现方 |
---|---|---|---|---|
MD2withRSA | 512~65536 | 1024 | 512~65536 | JDK |
MD5withRSA | 512~65536 | 1024 | 512~65536 | JDK |
SHA1withRSA | 512~65536 | 1024 | 512~65536 | JDK |
SHA224withRSA | 512~65536 | 2048 | 512~65536 | BC |
SHA256withRSA | 512~65536 | 2048 | 512~65536 | BC |
SHA384withRSA | 512~65536 | 2048 | 512~65536 | BC |
SHA512withRSA | 512~65536 | 2048 | 512~65536 | BC |
这里的BC指的是Bouncy Castle,是一种用于Java平台的开源的轻量级密码术包,提供了许多JDK没有的算法包。
用JDK RSA实现签名小例:
package signature_rsa;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Hex;
public class RSA {
private static String src = "signature_rsa";
public static void main(String[] args) {
jdkRSA();
}
public static void jdkRSA() {
try {
// 1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
// 2.执行签名(私钥)
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();
System.out.println("jdk rsa sign: " + Hex.encodeHexString(result));
// 3.验证签名(公钥)
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("MD5withRSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk RSA verify: " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
}
DSA(Digital Signature Algorithm)是通过DSS数字签名标准形成的数字签名算法
算法 | 密钥长度 | 默认长度 | 实现方 |
---|---|---|---|
SHA1withDSA | 512~1024 | 1024 | JDK |
SHA224withDSA | 512~1024 | 1024 | BC |
SHA256withDSA | 512~1024 | 1024 | BC |
SHA384withDSA | 512~1024 | 1024 | BC |
SHA512withDSA | 512~1024 | 1024 | BC |
用JDK DSA实现签名小例:
package signature_dsa;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Hex;
public class DSA {
private static String src = "signature_dsa";
public static void main(String[] args) {
jdkDSA();
}
public static void jdkDSA() {
try {
// 1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
DSAPublicKey dsaPublicKey = (DSAPublicKey)keyPair.getPublic();
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey)keyPair.getPrivate();
// 2.执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(dsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result =signature.sign();
System.out.println("jdk DSA sign: " + Hex.encodeHexString(result));
// 3.验证签名
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(dsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("DSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withDSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk DSA verify: " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
}
ECDSA:Elliptic Curve Digital Signature Algorithm,椭圆曲线数字签名算法。它具有速度快、强度高、签名短的特性。微软的Office办公软件的序列号验证算法便是ECDSA。
算法 | 密钥长度 | 默认长度 | 签名长度 | 实现方 |
---|---|---|---|---|
NONEwithECDSA | 112~571 | 256 | 128 | JDK/BC |
RIPEMD160withECDSA | 112~571 | 256 | 160 | BC |
SHA1withECDSA | 112~571 | 256 | 160 | JDK/BC |
SHA224withECDSA | 112~571 | 256 | 224 | BC |
SHA256withECDSA | 112~571 | 256 | 256 | JDK/BC |
SHA384withECDSA | 112~571 | 256 | 384 | JDK/BC |
SHA512withECDSA | 112~571 | 256 | 512 | JDK/BC |
用JDK ECDSA实现签名小例:
package signature_ecdsa;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Hex;
public class ECDSA {
private static String src = "signature_ecdsa";
public static void main(String[] args) {
jdkECDSA();
}
public static void jdkECDSA() {
try {
// 1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(256);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic();
ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate();
// 2.执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withECDSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();
System.out.println("jdk ECDSA sign: " + Hex.encodeHexString(result));
// 3.验证签名
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(ecPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withECDSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk ECDSA verify: " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
}