非对称加密、公钥和私钥简要说明,Java实现RSA加密/解密/签章/验章

提示:

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私钥的人才能打开!

扫描二维码关注公众号,回复: 335505 查看本文章

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

猜你喜欢

转载自bnmnba.iteye.com/blog/2280837
今日推荐