提示:
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