目录
简述
数字签名算法可以看做是一种带有密钥的消息摘要算法,并且这种密钥包含了公钥、私钥。也就说,数字签名算法是非对称加密算法和消息摘要算法的结合体。
作用
- 验证数据完整性
- 认证数据来源
- 抗否认
签名流程
- 发送者通过hash算法计算原始消息(m)的消息摘要,记为h(m);
- 发送者使用非对称私钥对h(m)进行加密,生成数字签名s;
- 发送者将原始消息和数字签名(m,s)发送给接收者。
验签流程
- 接收者通过hash算法计算原始消息的消息摘要,记为h(m);
- 接收者使用发送者提供的非对称公钥对数字签名s进行解密,得到解密后报文H(m);
- 接收者比较H(m)与h(m),如果一致则验签通过。
常用数字签名算法
- RSA:基于整数因子分解问题
- DSA:基于离散对数问题
- ECDSA:基于离散对数问题
经典数字签名算法-RSA
RSA数字签名算法是Diffie和Hellman提出数字签名思想后的第一个数字签名算法,是由Rivest、Shamir和Adleman三个人共同完成的,该签名算法源于RSA公钥密码算法的思想,将RSA公钥密码算法按照数字签名的方式运用。RSA数字签名算法是迄今为止应用最为广泛的数字签名算法。具体算法如下表:
算法 | 密钥长度 | 默认长度 | 签名长度 | 备注 |
---|---|---|---|---|
MD2withRSA | 512 ~ 65536 (64的整数倍) | 1024 | 与密钥长度相同 | jdk7实现 |
MD5withRSA | ||||
SHA1withRSA | ||||
SHA224withRSA | 2048 | Bouncy Castle实现 | ||
SHA256withRSA | ||||
SHA384withRSA | ||||
SHA512withRSA | ||||
RIPEMD128withRSA | ||||
RIPEMD160withRSA |
java实例:
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.StopWatch;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
* RSA算法签名实现
*
* @author chen.ww
* @date 2021/10/19 11:02
*/
public class RsaAlgorithm {
/**
* 密钥算法
*/
private static final String KEY_ALGORITHM = "RSA";
/**
* 签名算法
*/
private static final String SIGN_ALGORITHM = "SHA256WithRSA";
/**
* 创建签名公、私钥
*
* @author chen.ww
* @date 2021/10/19 11:40
* @param
* @return java.util.Map<java.lang.String,java.lang.String>
*/
public static Map<String, String> createSecretKey() {
try {
StopWatch sw = new StopWatch();
sw.start();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
sw.stop();
System.out.println(sw.getTotalTimeSeconds());
Map<String, String> keyMap = new HashMap<String, String>(2);
keyMap.put("pubKey", Base64.encodeBase64String(rsaPublicKey.getEncoded()));
keyMap.put("priKey", Base64.encodeBase64String(rsaPrivateKey.getEncoded()));
return keyMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 创建签名
*
* @author chen.ww
* @date 2021/10/19 11:40
* @param data
* @param signPriKey
* @return java.lang.String
*/
public static String createSign(String data, String signPriKey) {
try {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(signPriKey));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initSign(priKey);
signature.update(data.getBytes());
return Base64.encodeBase64String(signature.sign());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 验证签名
*
* @author chen.ww
* @date 2021/10/19 11:53
* @param data
* @param signData
* @param signPubKey
* @return boolean
*/
public static boolean verifySign(String data, String signData, String signPubKey) {
try {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(signPubKey));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initVerify(publicKey);
signature.update(data.getBytes());
return signature.verify(Base64.decodeBase64(signData));
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
数字签名标准算法-DSA
1991年,美国国家标准技术协会公布了数字签名标准(Digital Signature Standard,DSS),于1994年正式生效,并作为美国联邦信息处理标准。DSS本质上是EIGamal数字签名算法,DSS使用的算法称为数字签名算法(Digital Signature Algorithm,DSA)。
DSA算法与RSA算法都是数字证书中不可或缺的两种算法。两者不同的是,DSA算法仅包含数字签名算法,使用DSA算法的数字证书无法进行加密通信,而RSA算法既包含加密/解密算法,同时兼有数字签名算法。具体算法如下表:
算法 | 密钥长度 | 密钥长度默认值 | 签名长度 | 备注 |
---|---|---|---|---|
SHA1withDSA | 512 ~ 1024位 (密钥长度必须是64的倍数) | 1024bit | - | Java7实现 |
SHA224withDSA | ||||
SHA256withDSA | ||||
SHA384withDSA | ||||
SHA512withDSA |
java实例
import org.apache.commons.codec.binary.Base64;
import java.security.*;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
* DSA算法签名实现
*
* @author chen.ww
* @date 2021/10/19 14:30
*/
public class DsaAlgorithm {
/**
* 密钥算法
*/
private static final String KEY_ALGORITHM = "DSA";
/**
* 签名算法
*/
private static final String SIGN_ALGORITHM = "SHA256WithDSA";
/**
* 创建签名公、私钥
*
* @author chen.ww
* @date 2021/10/19 11:40
* @param
*/
public static Map<String, String> initSecretKey() throws Exception {
// 获取密钥对生成器实例
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 初始化密钥长度,默认为1024位
keyPairGenerator.initialize(1024);
// 生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 生成DSA公钥、私钥
DSAPublicKey dsaPublicKey = (DSAPublicKey) keyPair.getPublic();
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) keyPair.getPrivate();
// 将DSA公钥、私钥放入Map
Map<String, String> keyMap = new HashMap<String, String>(2);
keyMap.put("pubKey", Base64.encodeBase64String(dsaPublicKey.getEncoded()));
keyMap.put("priKey", Base64.encodeBase64String(dsaPrivateKey.getEncoded()));
return keyMap;
}
/**
* 创建签名
*
* @author chen.ww
* @date 2021/10/19 11:40
* @param data
* @param signPriKey
* @return java.lang.String
*/
public static String sign(String data, String signPriKey) throws Exception {
// 获取签名密钥规范实例
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(signPriKey));
// 获取密钥工厂实例
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 根据密钥规范生成私钥
PrivateKey priKey = keyFactory.generatePrivate(keySpec);
// 获取签名实例
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
// 签名初始化
signature.initSign(priKey);
// 签名参数初始化
signature.update(data.getBytes());
// 签名并进行Base64编码
return Base64.encodeBase64String(signature.sign());
}
/**
* 验证签名
*
* @author chen.ww
* @date 2021/10/19 11:53
* @param data
* @param signData
* @param signPubKey
* @return boolean
*/
public static boolean verifySign(String data, String signData, String signPubKey) throws Exception {
// 获取签名密钥规范实例
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(signPubKey));
// 获取密钥工厂实例
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 根据密钥规范生成公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// 获取签名实例
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
// 验签初始化
signature.initVerify(publicKey);
// 验签参数初始化
signature.update(data.getBytes());
// 验签
return signature.verify(Base64.decodeBase64(signData));
}
}