运行结果:
非堆成加密算法有如下优点:
对称加密需要协商密钥,而非对称加密可以安全地公开各自的公钥
N个人之间通信
使用非对称加密只需要N个密钥对,每个人只管理自己的密钥对
使用对称加密需要N*(N-1)/2个密钥,每个人需要管理N-1个密钥
非对称加密的缺点:
运算速度慢
不能防止中间人攻击
数字签名算法 RSA签名算法 在非对称加密中,我们可以看到甲乙双方要进行通信,甲可以使用乙的publicKey对消息进行加密,然后乙使用自己的privateKey对消息进行解密,这个时候会出现一个问题,如果黑客使用乙的publicKey对消息进行加密,然后冒充甲发送给乙,那么乙怎么识别这个消息是甲发送的还是冒充的呢?所以我们就需要数字签名算法。甲在发送加密信息的时候,同时还要发送自己的签名,而这个签名是使用甲的privateKey计算的,而乙要验证这个签名是否是合法的,它会用甲的publicKey进行验证,如果验证成功,则说明这个消息确实是甲发送的。所以数字签名就是发送方用自己的私钥对消息进行签名(sig=signature(privateKey,'message')),接收方用发送方的公钥验证签名是否有效(boolen valid = verify(publicKey,sig,'message')),我们可以把数字签名理解为混入了私钥和公钥的摘要。
数字签名的目的:
确认信息是某个发送方发的(因为只有它用他自己的privateKey签名,其他人才可以用它的publickey来验证这个签名)
发送发不能抵赖它发送了消息(因为用谁的publicKey成功的验证了签名,则这个 签名也是用谁的privateKey进行的签名)
数据在传输过程中没有被修改
常用的数字签名算法:
MD5withRSA
SHA1withRSA
SHA256withRSA
import java.nio.charset.StandardCharsets; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class SecRSASignature { private PublicKey pk; private PrivateKey sk; public SecRSASignature() throws GeneralSecurityException { //生成 KeyPair KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(1024); KeyPair kp = keyGen.generateKeyPair(); this.sk = kp.getPrivate(); this.pk = kp.getPublic(); } //从已保存的字节中(例如读取文件)恢复公钥/密钥 public SecRSASignature(byte[] pk, byte[] sk) throws GeneralSecurityException { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pk); this.pk = keyFactory.generatePublic(keySpec); PKCS8EncodedKeySpec skSpec = new PKCS8EncodedKeySpec(sk); this.sk = keyFactory.generatePrivate(skSpec); } //把私钥到处为字节 public byte[] getPrivateKey(){ return this.sk.getEncoded(); } //把公钥导出为字节 public byte[] getPublicKey(){ return this.pk.getEncoded(); } //对消息进行签名 public byte[] sign(byte[] message) throws GeneralSecurityException { //sign by sk Signature signature = Signature.getInstance("SHA1withRSA"); signature.initSign(this.sk); signature.update(message); return signature.sign(); } //私用公钥验证签名 public boolean verify(byte[] message, byte[] sign) throws GeneralSecurityException { //verify by pk Signature sha1withRSA = Signature.getInstance("SHA1withRSA"); sha1withRSA.initVerify(this.pk); sha1withRSA.update(message); return sha1withRSA.verify(sign); } public static void main(String[] args) throws GeneralSecurityException { byte[] message = "Hello,使用SHA1withRSA算法进行数字签名!".getBytes(StandardCharsets.UTF_8); SecRSASignature rsas = new SecRSASignature(); byte[] sign = rsas.sign(message); System.out.println("sign: " + Base64.getEncoder().encodeToString(sign)); boolean verified = rsas.verify(message, sign); System.out.println("verified: " + verified); //用另一个公钥验证 boolean verified02 = new SecRSASignature().verify(message, sign); System.out.println("verify with another public key: " + verified02); //修改原始信息 message[0] = 100; boolean verified03 = rsas.verify(message, sign); System.out.println("verify changed message: " + verified03); } }运行结果如下: