提示:
1、公钥加密只能用私钥解密。
2、私钥加密只能用公钥解密。
3、文章中的密文是指加密后的内容类似:MIGfMA0GC=
4、代码中使用Base64是为了把二进制数组转换为字符串。加密解密内容是二进制,不限于字符串。
本文说明一下非对称加密如何实现安全通讯:
A和B两个人进行安全通讯需要:A的公钥和私钥、B的公钥和私钥。
1、A和B保存好自己的私钥不要泄漏。A公开自己的公钥,B保存A的公钥;B公开自己的公钥,A保存B的公钥。
2、A发消息到B。格式如下:
from:A(说明:A名字没有加密,所有人都能看到) to:B(说明:B名字没有加密,所有人都能看到) content:X我喜欢你,你知道吗?X(说明:[X我喜欢你,你知道吗?X]是用B的公钥加密后的密文, B的私钥才能打开) sign:EG6V/RGbxYFoX1Uz4r6MgUeqh2hAb9Duj8JlB8Y5iSRxMTO1PpAH.. (说明:用B的名字和加密后的内容,用A私钥签章得到的数字印章)
3、很多人都收到了这条消息,其中包括一些想要监控你通信内容的坏人。所有人都看到A向B发消息了,有A公钥的人能验证接收者是不是自己和加密内容没有被修改过,而加密内容却只有拥有B私钥的人才能打开!
4、B向A发消息也是类似。就这样,在不安全的链路上进行安全的通讯就完成了!
附上java实现的RSA的小例子:
MainTest:
package rsa; import java.util.HashMap; import java.util.Map; public class MainTest { /** * @param args * @throws Exception */ public static void main(String[] args) { KeyGenerater kgA = new KeyGenerater(); kgA.generater(); KeyGenerater kgB = new KeyGenerater(); kgB.generater(); System.out.println("pubKeyA = " + new String(kgA.getPubKey())); System.out.println("priKeyA = " + new String(kgA.getPriKey())); System.out.println("PubKeyB = " + new String(kgB.getPubKey())); System.out.println("PriKeyB = " + new String(kgB.getPriKey())); String text = "我喜欢你,你知道吗?"+((char) 134) + ""; byte[] content=text.getBytes(); print("content :",content); byte[] contentByteEntrpted=RASUtil.encryptByPubKey( content,kgB.getPubKey()/*B的公钥*/);//A加密内容,content的内容 print("contentByteEntrpted Bytes:",contentByteEntrpted); String beSigned=new StringBuilder()//被签章的内容:包括接收者和加密后的内容,保证这些内容,用A的私钥加密后没有人可以修改签章内容。 .append(new String("B"))//确保接收者不被修改 .append(new String(contentByteEntrpted))//确保加密内容不被修改 .toString(); System.out.println("beSigned ="+beSigned); byte[] signByte=RASUtil.sign(kgA.getPriKey()/*A的私钥*/, beSigned);//A签名,sign的内容 System.out.println("signByte:"+new String(signByte)); //组装成可以进行传输的数据对象,Base64是为了字符串化二进制,方便传输(二进制里的一些特殊控制字符不适合进行传输) Map<String,String> map=new HashMap<String, String>(); map.put("from", "A"); map.put("to", "B"); map.put("content", new String(contentByteEntrpted)); map.put("sign", new String(signByte)); String beSigned_B=new StringBuilder()//B要验章。 .append(new String("B")) .append(map.get("content")) .toString(); //B验章 System.out.println("B验证签名:"+RASUtil.verify(kgA.getPubKey()/*A的公钥*/, beSigned_B, map.get("sign").getBytes()));//B验证签名,如果为true,说明内容没有被修改,且接收者必定是自己。 print("contentByteEntrpted.getBytes:",map.get("content").getBytes()); //B如果发现接收者是自己,用私钥解开内容 byte[] content2=RASUtil.decryptByPriKey(map.get("content").getBytes(), kgB.getPriKey()/*B的私钥*/); content2=Base64.decode(content2); print("content2:",content2); System.out.println("加密解密无误:"+equals(content,content2));//只要保证,byte数组的每一个都是相等的即证明加密解密无误 //System.out.println(new String(content2).equals(new String(content)));//true //System.out.println(new String(content2).equals(text));//false,byte数组和字符串转换时,最后那个特殊char转换后发生变化导致。 } private static boolean equals(byte[] b, byte[] m2) { try{ for (int i = 0; i < m2.length; i++) { if(b[i]!=m2[i]){ return false; } } return true; }catch (Exception e) { return false; } } private static void print(String s,byte[] m) { System.out.print(s); for (int i = 0; i < m.length; i++) { System.out.print(Byte.valueOf(m[i]).intValue()); System.out.print(","); } System.out.println(); } }
KeyGenerater:
package rsa; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; public class KeyGenerater { private byte[] priKey; private byte[] pubKey; public byte[] getPriKey() { return priKey; } public void setPriKey(byte[] priKey) { this.priKey = priKey; } public byte[] getPubKey() { return pubKey; } public void setPubKey(byte[] pubKey) { this.pubKey = pubKey; } public void generater() { try { java.security.KeyPairGenerator keygen = java.security.KeyPairGenerator .getInstance("RSA"); SecureRandom secrand = new SecureRandom(); // secrand.setSeed(seed.getBytes()); // 初始化随机产生器,不要调用这个,不安全//seed相同的情况下,每次产生的密钥都一样 keygen.initialize(1024, secrand); KeyPair keys = keygen.genKeyPair(); PublicKey pubkey = keys.getPublic(); PrivateKey prikey = keys.getPrivate(); pubKey = Base64.encodeToByte(pubkey.getEncoded()); priKey = Base64.encodeToByte(prikey.getEncoded()); } catch (java.lang.Exception e) { System.out.println("生成密钥对失败"); e.printStackTrace(); } } }
RASUtil:
package rsa; public class RASUtil { /** * * Description:数字签名 * * @param priKeyByte * @param plainText * @return */ public static byte[] sign(byte[] priKeyByte, String plainText) { try { java.security.spec.PKCS8EncodedKeySpec priPKCS8 = new java.security.spec.PKCS8EncodedKeySpec( Base64.decode(priKeyByte)); java.security.KeyFactory keyf = java.security.KeyFactory.getInstance("RSA"); java.security.PrivateKey prikey = keyf.generatePrivate(priPKCS8); // 用私钥对信息生成数字签名 java.security.Signature signet = java.security.Signature .getInstance("MD5withRSA"); signet.initSign(prikey); signet.update(plainText.getBytes()); byte[] signed = Base64.encodeToByte(signet.sign()); return signed; } catch (java.lang.Exception e) { System.out.println("签名失败"); e.printStackTrace(); } return null; } /** * * Description:校验数字签名,此方法不会抛出任务异常,成功返回true,失败返回false,要求全部参数不能为空 * * @param pubKeyByte * 公钥,base64编码 * @param plainText * 明文 * @param signByte * 数字签名的密文,base64编码 * @return 校验成功返回true 失败返回false */ public static boolean verify(byte[] pubKeyByte, String plainText, byte[] signByte) { try { // 解密由base64编码的公钥,并构造X509EncodedKeySpec对象 java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec( Base64.decode(pubKeyByte)); // RSA对称加密算法 java.security.KeyFactory keyFactory = java.security.KeyFactory .getInstance("RSA"); // 取公钥匙对象 java.security.PublicKey pubKey = keyFactory .generatePublic(bobPubKeySpec); // 解密由base64编码的数字签名 byte[] signed = Base64.decode(signByte); java.security.Signature signatureChecker = java.security.Signature .getInstance("MD5withRSA"); signatureChecker.initVerify(pubKey); signatureChecker.update(plainText.getBytes()); // 验证签名是否正常 if (signatureChecker.verify(signed)) return true; else return false; } catch (Throwable e) { System.out.println("校验签名失败"); e.printStackTrace(); return false; } } /** * 公钥加密 * * @param data * @param publicKey * @return * @throws Exception */ public static byte[] encryptByPubKey(byte[] data, byte[] pubKeyByte) { try { // 解密由base64编码的公钥,并构造X509EncodedKeySpec对象 java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec( Base64.decode(pubKeyByte)); // RSA对称加密算法 java.security.KeyFactory keyFactory = java.security.KeyFactory .getInstance("RSA"); // 取公钥匙对象 java.security.PublicKey pubKey = keyFactory .generatePublic(bobPubKeySpec); javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA"); cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, pubKey); return Base64.encodeToByte(cipher.doFinal(data)); } catch (Exception e) { throw new RuntimeException(e); } } /** * 私钥加密 * * @param data * @param priKeyByte * @return * @throws Exception */ public static byte[] encryptByPriKey(byte[] data, byte[] priKeyByte) { try { java.security.spec.PKCS8EncodedKeySpec priPKCS8 = new java.security.spec.PKCS8EncodedKeySpec( Base64.decode(priKeyByte)); java.security.KeyFactory keyf = java.security.KeyFactory.getInstance("RSA"); java.security.PrivateKey prikey = keyf.generatePrivate(priPKCS8); javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA"); cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, prikey); return Base64.encodeToByte(cipher.doFinal(data)); } catch (Exception e) { throw new RuntimeException(e); } } /** * 公钥解密 * * @param data * @param pubKeyByte * @return * @throws Exception */ public static byte[] decryptByPubKey(byte[] data, byte[] pubKeyByte) { try { // 解密由base64编码的公钥,并构造X509EncodedKeySpec对象 java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec( Base64.decode(pubKeyByte)); // RSA对称加密算法 java.security.KeyFactory keyFactory = java.security.KeyFactory .getInstance("RSA"); // 取公钥匙对象 java.security.PublicKey pubKey = keyFactory .generatePublic(bobPubKeySpec); javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA"); cipher.init(javax.crypto.Cipher.DECRYPT_MODE, pubKey); return Base64.encodeToByte(cipher.doFinal(Base64.decode((data)))); } catch (Exception e) { throw new RuntimeException(e); } } /** * 私钥解密 * * @param data * @param priKeyByte * @return * @throws Exception */ public static byte[] decryptByPriKey(byte[] data, byte[] priKeyByte) { try { java.security.spec.PKCS8EncodedKeySpec priPKCS8 = new java.security.spec.PKCS8EncodedKeySpec( Base64.decode(priKeyByte)); java.security.KeyFactory keyf = java.security.KeyFactory.getInstance("RSA"); java.security.PrivateKey prikey = keyf.generatePrivate(priPKCS8); javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA"); cipher.init(javax.crypto.Cipher.DECRYPT_MODE, prikey); return Base64.encodeToByte(cipher.doFinal(Base64.decode(data))); } catch (Exception e) { throw new RuntimeException(e); } } }
Base64:转换一下用了Apache的commons-codec-1.10.jar
package rsa; public class Base64 { public static byte[] encodeToByte(byte[] encoded) { return org.apache.commons.codec.binary.Base64.encodeBase64(encoded); } public static byte[] decode(byte[] plainByte) { return org.apache.commons.codec.binary.Base64.decodeBase64(plainByte); } }
代码引用:http://blog.csdn.net/sunyujia/article/details/2008480
附件commons-codec-1.10.jar