1、Alice(密码学中常用A到Z开头的人名代替甲乙丙丁等,字母越靠后出现频率越低)生成一对密钥,一个是sk(signing key),是非公开的;另一个是vk(verification key),是公开的。
这一对密钥同时生成,并且在数学上是相互关联的,同时,根据vk无法推测出关于sk的任何信息。
2、数字签名算法接收两个输出:信息M和sk,生成一个数字签名Sm。
3、验证函数接收信息M、Sm以及vk作为输入,返回结果是yes或者no。这一步的目的是为了验证你看到的针对信息M的数字签名确实是由Alice的sk来签发的,用于确认信息与签名是否相符。
与手写签名不同,手写签名基本都是相似的,但是数字签名却受输入影响很大。对输入轻微的改变都会产生一个完全不同的数字签名。一般不会对信息直接进行数字签名,而是对信息的哈希值进行签名。由加密哈希函数的无碰撞性可知,这样和对原信息进行签名一样安全。
数字签名实现的具体原理:1、将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。
在数学上保证,只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。(详见参考资料的"公钥密码技术原理"章节)
2、将该报文摘要值用发送者的私人密钥加密,然后连同原报文和数字证书(包含公钥)一起发送给接收者而产生的报文即称数字签名。
3、接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较,如相等则说明报文确实来自所称的发送者。
4、同时通过证书颁发机构CA确认证书的有效性即可确认发送的真实身份。
代码案例(包含签名和验签代码块):import java.security.PublicKey;
import java.security.cert.X509Certificate;
public class CertificateCoderDemo {
public static void main(String[] args) {
String keyStorePath = "c:/server.jks";
String alias = "server";
String pwd = "123456";
String cerPath = "c:/server.cer";
// 1、根据keyStore路径获取证书
try {
X509Certificate x509 = (X509Certificate) CertificateCoder.getCertificate(keyStorePath, alias, pwd);
System.out.println("证书内容:\r\n" x509);
} catch (Exception e) {
e.printStackTrace();
}
// 2、根据cert路径获取公钥
try {
PublicKey publicKey = CertificateCoder.getPublicKeyByCertificate(cerPath);
System.out.println("公钥内容:\r\n" publicKey);
} catch (Exception e) {
e.printStackTrace();
}
// 3、私钥加密公钥解密;
String data = "[私钥加密公钥解密]";
try {
byte[] decryptData = CertificateCoder.encryptByPrivateKey(data.getBytes(), keyStorePath, alias, pwd);
System.out.println("私钥加密内容:" decryptData);
byte[] encryptData = CertificateCoder.decryptByPublicKey(decryptData, cerPath);
System.out.println("公钥加密内容:" new String(decryptData));
} catch (Exception e) {
e.printStackTrace();
}
// 4、公钥加密公钥解密;
String text = "[公钥加密私钥解密]";
try {
byte[] decryptData = CertificateCoder.encryptByPublicKey(text.getBytes(), cerPath);
System.out.println("公钥加密内容:" decryptData);
byte[] encryptData = CertificateCoder.decryptByPrivateKey(decryptData, keyStorePath, alias, pwd);
System.out.println("私钥加密内容:" new String(encryptData));
} catch (Exception e) {
e.printStackTrace();
}
// 5、证书签名(私钥签名)
String signData = "证书签名(私钥签名)";
byte[] signedData = null;
try {
signedData = CertificateCoder.sign(signData.getBytes(), keyStorePath, pwd, alias);
System.out.println("证书签名结果:" signedData);
} catch (Exception e) {
e.printStackTrace();
}
// 6、验签(公钥验签)
try {
boolean verifyResult = CertificateCoder.verify(signData.getBytes(), signedData, cerPath);
System.out.println("证书验签结果:" verifyResult);
} catch (Exception e) {
e.printStackTrace();
}
}
}
import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class CertificateCoder {
public static final String CERT_TYPE = "X.509";
/**
* 获取私匙
*
* @param keyStorePath
* @param pwd
* @param alias
* @return PrivateKey 私匙
* @throws Exception
*/
private static PrivateKey getPrivateKey(String keyStorePath, String pwd, String alias) throws Exception {
KeyStore ks = getKeyStore(keyStorePath, pwd);
return (PrivateKey) ks.getKey(alias, pwd.toCharArray());
}
/**
* @param keyStorePath
* @param pwd
* @return keyStore 密匙库
* @throws Exception
*/
private static KeyStore getKeyStore(String keyStorePath, String pwd) throws Exception {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream in = new FileInputStream(keyStorePath);
ks.load(in, pwd.toCharArray());
in.close();
return ks;
}
/**
* @param certificatePath
* @return Certificate 证书
* @throws Exception
*/
private static Certificate getCertificate(String certificatePath) throws Exception {
CertificateFactory factory = CertificateFactory.getInstance(CERT_TYPE);
FileInputStream in = new FileInputStream(certificatePath);
Certificate certificate = factory.generateCertificate(in);
in.close();
return certificate;
}
/**
* 通过证书返回公匙
*
* @param certificatePath
* @return Publickey 返回公匙
* @throws Exception
*/
public static PublicKey getPublicKeyByCertificate(String certificatePath) throws Exception {
Certificate certificate = getCertificate(certificatePath);
return certificate.getPublicKey();
}
/**
* @param keyStorePath
* @param alias
* @param pwd
* @return Certificate 证书
* @throws Exception
*/
public static Certificate getCertificate(String keyStorePath, String alias, String pwd) throws Exception {
KeyStore ks = getKeyStore(keyStorePath, pwd);
//获取证书
return ks.getCertificate(alias);
}
/**
* 私匙加密
*
* @param data
* @param keyStorePath
* @param alias
* @param pwd
* @return byte[] 被私匙加密的数据
* @throws Exception
*/
public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath, String alias, String pwd) throws Exception {
PrivateKey privateKey = getPrivateKey(keyStorePath, pwd, alias);
//对数据进行加密
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 私匙解密
*
* @param data
* @param keyStorePath
* @param alias
* @param pwd
* @return byte[] 私匙解密的数据
* @throws Exception
*/
public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath, String alias, String pwd) throws Exception {
PrivateKey privateKey = getPrivateKey(keyStorePath, pwd, alias);
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 公匙加密
*
* @param data
* @param cerPath
* @return byte[] 被公匙加密的数据
* @throws Exception
*/
public static byte[] encryptByPublicKey(byte[] data, String cerPath) throws Exception {
//获取公匙
PublicKey publicKey = getPublicKeyByCertificate(cerPath);
System.out.println(publicKey.getAlgorithm());
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 公匙解密
*
* @param data
* @param cerPath
* @return
* @throws Exception
*/
public static byte[] decryptByPublicKey(byte[] data, String cerPath) throws Exception {
PublicKey publicKey = getPublicKeyByCertificate(cerPath);
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 签名
*
* @param sign
* @param keyStorePath
* @param pwd
* @param alias
* @return
* @throws Exception
*/
public static byte[] sign(byte[] sign, String keyStorePath, String pwd, String alias) throws Exception {
//获取证书
X509Certificate x509 = (X509Certificate) getCertificate(keyStorePath, alias, pwd);
//构建签名,由证书指定签名算法
Signature sa = Signature.getInstance(x509.getSigAlgName());
//获取私匙
PrivateKey privateKey = getPrivateKey(keyStorePath, pwd, alias);
sa.initSign(privateKey);
sa.update(sign);
return sa.sign();
}
/**
* 验证签名
*
* @param data
* @param sign
* @param cerPath
* @return
* @throws Exception
*/
public static boolean verify(byte[] data, byte[] sign, String cerPath) throws Exception {
X509Certificate x509 = (X509Certificate) getCertificate(cerPath);
Signature sa = Signature.getInstance(x509.getSigAlgName());
sa.initVerify(x509);
sa.update(data);
return sa.verify(sign);
}
}