数字签名(又称公钥数字签名)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证,但法条中的电子签章与数字签名,代表之意义并不相同,电子签章用以辨识及确认电子文件签署人身份、资格及电子文件真伪者。而数字签名则是以数学算法或其他方式运算对其加密,才形成电子签章,意即使用数字签名才创造出电子签章。 ——————— 摘自维基百科
签名的好处
签名可以保证数据完整性、不可抵赖性、鉴权
签名过程
发送方A将需要传送的数据通过自己的私钥(Private Key)进行签名产生摘要,然后将签名生成的摘要和需要传送的数据一起传输给接收方B,接收方B在接收到数据后通过A的公钥(Public Key)来对签名进行校验。
RSA签名算法
算法 | 密钥长度 | 默认长度 | 签名长度 | 实现方 |
MD2withRSA | 512~65536(64的整数倍) | 1024 | 与密钥长度相同 | JDK |
MD5withRSA | ||||
SHA1withRSA | ||||
SHA224withRSA | 2048 | BC | ||
SHA256withRSA | ||||
SHA384withRSA | ||||
SHA512withRSA | ||||
RIPEMD128withRSA | ||||
RIPEMD168withRSA |
代码实现:
public class SignatureWithRSA {
// 公/私钥生成算法
private final static String KEY_ALGORITHM = "RSA";
// 数据签名算法
/**
* JDK实现的RSA签名算法有 MD2withRSA、MD5withRSA、SHA1withRSA
* 密钥长度为512~65536(要求为64的整数倍),默认长度为1024,签名的长度和密钥长度相等
*
* 其他的RSA签名算法有SHA224withRSA、SHA256withRSA、SHA512withRSA等JDK并未实现,
* 但是bouncycastle都做了支持,默认密钥为2048,签名长度同样和密钥长度相等
* */
private static final String SIGN_ALGORITHM = "SHA1withRSA";
private static final String PUBLIC_KEY = "publicKey";
private static final String PRIVATE_KEY = "privateKey";
private static final int KEY_LENGTH = 512;
/**
* 初始化密钥
* @throws Exception
* */
public static Map<String, Key> initKey() throws Exception {
// 实例化密钥生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 初始化密钥长度,此处为512
keyPairGenerator.initialize(KEY_LENGTH);
// 获取密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 获取RSA公钥
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
// 获取RSA私钥
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Key> keyMap = new HashMap<String, Key>();
keyMap.put(PUBLIC_KEY, rsaPublicKey);
keyMap.put(PRIVATE_KEY, rsaPrivateKey);
return keyMap;
}
/**
* 获取公钥
* */
public static RSAPublicKey getPublicKey(Map<String, Key> keyMap) {
return (RSAPublicKey) keyMap.get(PUBLIC_KEY);
}
/**
* 获取私钥
* */
public static RSAPrivateKey getPrivateKey(Map<String, Key> keyMap) {
return (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
}
/**
* 使用私钥对数据进行签名
* @throws Exception
* @return byte[]
* */
public static byte[] signatureWithPrivateKey(String data, RSAPrivateKey rsaPrivateKey) throws Exception {
PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 获取私钥
PrivateKey privateKey = keyFactory.generatePrivate(encodedKeySpec);
// 使用签名算法实例化Signature
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
// 使用签名私钥进行初始化
signature.initSign(privateKey);
// 更新需要签名的数据
signature.update(data.getBytes());
// 执行签名
byte[] signed = signature.sign();
return signed;
}
/**
* 使用公钥对签名的数据进行校验
* @throws Exception
* */
public static boolean verifyWithPublicKey(String data, byte[] signed, RSAPublicKey rsaPublicKey) throws Exception {
X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
// 实例化KeyFactory
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 获取签名公钥
PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec);
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initVerify(publicKey);
signature.update(data.getBytes());
boolean verified = signature.verify(signed);
return verified;
}
public static void main(String[] args) throws Exception {
String msg = "Hello World";
Map<String, Key> keyMap = initKey();
RSAPrivateKey priK = getPrivateKey(keyMap);
RSAPublicKey pubK = getPublicKey(keyMap);
System.out.println("签名前的数据---->" + msg);
// 执行签名
byte[] signedMsg = signatureWithPrivateKey(msg, priK);
System.out.println("密钥长度---->" + KEY_LENGTH);
System.out.println("签名后数据长度---->" + signedMsg.length * 8);
System.out.println("签名后的数据---->" + Base64.encodeBase64String(signedMsg));
// 校验签名
boolean verified = verifyWithPublicKey(msg, signedMsg, pubK);
System.out.println("校验---->" + verified);
}
}
输出的结果:
以上,就是对RSA签名算法的简单介绍,如有错误请指出,谢谢!