公钥加密&私钥签名的通俗说明
================================
一、公钥加密
假设一下,我找了两个数字,一个是1,一个是2。我喜欢2这个数字,就保留起来,不告诉你们(私钥),然后我告诉大家,1是我的公钥。
我有一个文件,不能让别人看,我就用1加密了。别人找到了这个文件,但是他不知道2就是解密的私钥啊,所以他解不开,只有我可以用
数字2,就是我的私钥,来解密。这样我就可以保护数据了。
我的好朋友x用我的公钥1加密了字符a,加密后成了b,放在网上。别人偷到了这个文件,但是别人解不开,因为别人不知道2就是我的私钥,
只有我才能解密,解密后就得到a。这样,我们就可以传送加密的数据了。
二、私钥签名
如果我用私钥加密一段数据(当然只有我可以用私钥加密,因为只有我知道2是我的私钥),结果所有的人都看到我的内容了,因为他们都知
道我的公钥是1,那么这种加密有什么用处呢?
但是我的好朋友x说有人冒充我给他发信。怎么办呢?我把我要发的信,内容是c,用我的私钥2,加密,加密后的内容是d,发给x,再告诉他
解密看是不是c。他用我的公钥1解密,发现果然是c。
这个时候,他会想到,能够用我的公钥解密的数据,必然是用我的私钥加的密。只有我知道我得私钥,因此他就可以确认确实是我发的东西。
这样我们就能确认发送方身份了。这个过程叫做数字签名。当然具体的过程要稍微复杂一些。用私钥来加密数据,用途就是数字签名。
总结:公钥和私钥是成对的,它们互相解密。
公钥加密,私钥解密。
私钥数字签名,公钥验证。
相对不那么通俗的说明
============================
RSA加密算法是最常用的非对称加密算法。
RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。目前该加密方式广泛用于网上银行、数字签名等场合。
密钥的长度越长,安全性就越好,但是加密解密所用的时间就会越多。
所以非对称加密一般都用于加密对称加密算法的密钥,而不是直接加密内容。
数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。
测试代码
package com.inspur.cloud.am.util; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Scanner; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class RSAUtil { private static RSAPublicKey publicKey = null; private static RSAPrivateKey privateKey = null; static{ publicKey = (RSAPublicKey)loadKeyByFile("publicKey.keystore","publicKey"); privateKey = (RSAPrivateKey)loadKeyByFile("privateKey.keystore","privateKey"); } public static void main(String[] args) { //------------------------ //generateKeyPair(); //------------------------ //使用公钥加密 //String cipherData = encrypt(publicKey, "你好".getBytes()); //System.out.println(cipherData); //使用私钥解密 //System.out.println(decrypt(privateKey, cipherData)); //------------------------ //使用私钥加密 //String cipherData2 = encrypt(privateKey, "中国".getBytes()); //System.out.println(cipherData2); //使用公钥解密 //System.out.println(decrypt(publicKey, cipherData2)); //------------------------ //生成签名数据 String originalData = "你好"; String signData = sign(originalData); System.out.println(signData); //验证签名 boolean check = doCheck(originalData, signData); System.out.println(check); } /** * 生成公钥、私钥对 */ private static void generateKeyPair() { try { // 返回生成指定算法的 public/private 密钥对的 KeyPairGenerator 对象。 参数RSA算法 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); // 初始化RSA长度,RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024 keyPairGenerator.initialize(1024); // 生成一个密钥对 KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 获得公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 获得私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到公钥字符串 String publicKeyString = Base64.encodeBytes(publicKey.getEncoded()); // 得到私钥字符串 String privateKeyString = Base64.encodeBytes(privateKey.getEncoded()); // 将密钥对写入到文件 FileWriter fw1 = new FileWriter("publicKey.keystore"); FileWriter fw2 = new FileWriter("privateKey.keystore"); fw1.write(publicKeyString); fw2.write(privateKeyString); fw1.flush(); fw1.close(); fw2.flush(); fw2.close(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 加载公钥/私钥 * @param path * @return */ public static Object loadKeyByFile(String path,String type){ StringBuilder key = new StringBuilder(); Scanner s = null; try { s = new Scanner(new File(path)); //设置分隔符,不设置,则默认使用空格进行分割 s.useDelimiter(System.getProperty("line.separator")); while(s.hasNext()){ key.append(s.next()); } //关闭扫描器s.close; } catch (FileNotFoundException e) { e.printStackTrace(); }finally{ s.close(); } try { byte[] buffer = Base64.decode(key.toString()); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); if(type.equals("privateKey")){ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer); return keyFactory.generatePrivate(keySpec); }else{ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer); return keyFactory.generatePublic(keySpec); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); } return null; } /** * 使用公钥/私钥加密 * @param key 加密密钥 * @param plainTextData 原文 * @return 密文 * @throws Exception */ public static String encrypt(Key key,byte[] plainTextData){ Cipher cipher = null; try { cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] output = cipher.doFinal(plainTextData); return Base64.encodeBytes(output); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } return null; } /** * 使用公钥/私钥解密 * @param key 解密密钥 * @param cipherData 密文 * @return */ public static String decrypt(Key key,String cipherData){ Cipher cipher = null; try { cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, key); byte[] output = cipher.doFinal(Base64.decode(cipherData)); return new String(output); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } return null; } /** * 私钥签名 * @param content 待签名数据 * @return 签名值 */ public static String sign(String content) { try { java.security.Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(privateKey); signature.update(content.getBytes()); byte[] signed = signature.sign(); return Base64.encodeBytes(signed); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 使用公钥验证签名 * @param content * @param sign * @return */ public static boolean doCheck(String content, String sign) { try { Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initVerify(publicKey); signature.update(content.getBytes()); boolean bverify = signature.verify(Base64.decode(sign)); return bverify; } catch (Exception e) { e.printStackTrace(); } return false; } }