Android 初学者之不对称加密工具类RSAHelper

package com.asiainfo.atmobile.security;

public interface SecurityInter {

	public String encrypt(String src);
	
	public String decrypt(String src);
	
	public int initialize(String path);
}

package com.asiainfo.atmobile.security;
/*
 * 系统安全采用工厂模式
 * 为以后扩展出新的加密解密方式做准备
 */
public class SecurityFactory {

	public static void main(String[] args){
		SecurityFactory.newInstance("com.example.atmobile.security.RSAHelper");
	}
	
	private SecurityFactory(){}
	
	@SuppressWarnings("finally")
	public static SecurityInter newInstance(String strClass){
		Object obj = null;
		try {
			Class clazz = Class.forName(strClass)  ;
			Class[] interfaces = clazz.getInterfaces();
			boolean implementsFlag = false ;
			for(int i=0;i

package com.asiainfo.atmobile.security;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Properties;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.ArrayUtils;


public class RSAHelper implements SecurityInter{
	
	public static void main(String[] args) throws UnsupportedEncodingException{
		/*
		 * 产生的公钥与私钥需要放到以下俩文件,实际应用中应将public.cfg发送给客户端;
		 * \\WEB-INF\\conf\\security_public.cfg
		 * \\WEB-INF\\conf\\security_public.cfg
		 * 
		 * #我的疑问:
		 * #如果public.cfg文件被他人截获系统还安全么?
		 * #应该把public.cfg文件加密,把加密后的文件再加密......
		 * #还需要把APK模糊化编译......
		 * #安全归根到底还是不安全!!!
		 *
			try {
				new RSAHelper().generateRSAKeys();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		*/
		
		/*
		 * 弄个还算长的字符串做测试用
		 */
		String srcmsg = "";
		srcmsg += "第八届全国“人民满意的公务员”和“人民满意的公务员集体”表彰大会17日上午在北京举行。中共中央政治局常委、国务院总理李克强接见了受表彰人员和与会代表。中共中央政治局常委、中央书记处书记刘云山参加接见。";
		srcmsg += "李克强代表党中央、国务院向受表彰的个人和集体表示祝贺。他说,人民满意是公务员的最高荣誉。受表彰的同志绝大多数来自基层普通岗位,有的长期在边远、艰苦地区工作,大家兢兢业业、勤勤恳恳为群众办事,在平凡岗位上创造了不平凡的业绩,这种精神值得弘扬光大。";
		srcmsg += "李克强指出,我国改革和发展已进入关键时期,机遇和挑战并存。能够亲身参与国家现代化建设的伟大进程,既是难得的人生际遇,也是我们共同肩负的重大责任和使命。李克强对广大公务员提出四点希望:";
		srcmsg += "一要促进改革创新。当前我国经济稳中向好,明年仍有条件保持平稳运行,全面深化改革将进一步解放和发展生产力,进一步增添发展的内生动力,激发市场活力。公务员不仅是改革的参与者,更应成为改革的推动者。继续推进简政放权等一系列改革,必然会触及利益,要从大局出发、从人民群众根本利益出发,以壮士断腕的精神,义无反顾,勇挑重担,走在全面深化改革的前列。";
		srcmsg += "二要始终勤政为民。公务员是人民的公仆,必须坚持人民至上,忠于职守,尽心竭力。要把让人民满意的标准高悬头上、牢记心上,把解决群众困难、为群众办实事、实现人民期盼体现在行动中,打造敢担当、有作为的政府。";
		srcmsg += "三要践行法治原则。法治是实现社会公正的基础和保障,改革也要在法治的大背景下来推进。公务员要增强法治意识,自觉遵纪守法,严格依法办事、规范履职行为,身体力行推进法治政府建设,营造公平公正的发展环境。";
		srcmsg += "四要严守清正廉洁。身为公务员,就是选择了一条为公众服务的道路。要得到群众信赖、让人民幸福,就必须清正廉洁。不廉者,政令难行。各级公务员要带头执行中央八项规定和国务院“约法三章”,建设廉洁政府,做俭朴清廉的表率。";
		srcmsg += "李克强强调,各级党委和政府要关心公务员特别是基层公务员的工作和生活,使他们更好地为国家和人民服务。";
		srcmsg += "李克强最后说,让我们紧密团结在以习近平同志为总书记的党中央周围,深入贯彻党的十八大和十八届二中、三中全会精神,奋发努力,做出更大贡献。";
		srcmsg += "马凯、刘奇葆、赵乐际、杨晶、郭声琨、王正伟参加接见。";
		
		/*
		 * 原始字符串转换为UTF-8
		 */
		srcmsg = new String(srcmsg.getBytes("UTF-8"),"UTF-8");
		System.out.println("原始字符串长度:"+srcmsg.getBytes("UTF-8").length);
		/*
		 * 公钥加密
		 * 如果想换成私钥加密
		 * 只需要更换配置文件“security_public.cfg”为“security_private.cfg”
		 * 其实就是修改了文件中的ispublic和exponent
		 */
		SecurityInter r1 = SecurityFactory.newInstance("com.asiainfo.atmobile.security.RSAHelper");
		r1.initialize("E:\\workspace_android\\ATmobile-Server\\ATmobileServer\\WEB-INF\\conf\\security_public.cfg");
		String enstr = r1.encrypt(srcmsg);
		System.out.println("---加密后---\n"+enstr);
		System.out.println("加密字符串长度:"+enstr.getBytes("UTF-8").length);
		/*
		 * 私钥解密
		 */
		SecurityInter r2 = SecurityFactory.newInstance("com.asiainfo.atmobile.security.RSAHelper");
		r2.initialize("E:\\workspace_android\\ATmobile-Server\\ATmobileServer\\WEB-INF\\conf\\security_private.cfg");
		String destr = r2.decrypt(enstr);
		System.out.println("---解密后---\n"+destr);
		System.out.println("解密字符串长度:"+destr.getBytes("UTF-8").length);
	}
	
	//private String padding = "RSA/ECB/PKCS1Padding";  /* SUN.JDK */
	private String padding = "RSA/ECB/NoPadding";  /* ANDROID.SDK 
													* 这里指的是谁加密的,padding是加密时插入到字符串中的。
	 												* 如果是Android设备加密的,那服务端即使是SUN.JDK也要按照'RSA/ECB/NoPadding'来进行设置。
	 												*/
	private String charset = "UTF-8";
	private PrivateKey privateK = null;
	private PublicKey publicK = null;
	private boolean ispublic = true ;
	private String modulus = null ;
	private String exponent = null ;
	
	public RSAHelper() {}
	
	/**
	 * 初始化加载参数,读取配置文件中的keys。
	 */
	@Override
	public int initialize(String path){		
		try {
			Properties prop = new Properties();
			InputStream is = new FileInputStream(path);
			prop.load(is);
			this.modulus = (String)prop.getProperty("modulus");
			this.exponent = (String)prop.getProperty("exponent");
			this.ispublic = new Boolean((String)prop.getProperty("ispublic")).booleanValue();
			this.charset = (String)prop.getProperty("charset") == null ? this.charset : (String)prop.getProperty("charset") ;
			this.padding = (String)prop.getProperty("padding") == null ? this.padding : (String)prop.getProperty("padding") ;
			if(this.modulus == null || this.exponent == null ){
				try {
					throw new Exception("modulus and exponent cannot be null !");
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			else{
				try {
					if(ispublic){
						publicK = getPublicKey(modulus,exponent);
					}
					else{
						privateK = getPrivateKey(modulus,exponent);
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}
	
	/**
	 * 加密方法
	 * 接口SecurityInter中提到的方法
	 * 输入原始字符串,返回加密字符串。
	 */
	@Override
	public String encrypt(String src) {
		byte[] bytes = null ;
		try {
			if(this.ispublic){
				bytes = encryptByPublicKey(src);
			}
			else{
				bytes = encryptByPrivateKey(src);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String result = new String(Hex.encodeHex(bytes));
		System.out.println("原始信息:"+src);
		System.out.println("加密信息:"+result);
		return result;
	}
	/**
	 * 解密方法
	 * 接口SecurityInter中提到的方法
	 * 输入加密字符串,返回原始字符串。
	 */
	@Override
	public String decrypt(String src) {
		String result = null ;
		try {
			if(this.ispublic){
				result = decryptByPublicKey(Hex.decodeHex( src.toCharArray() ));
			}
			else{
				result = decryptByPrivateKey(Hex.decodeHex( src.toCharArray() ));
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("加密信息:"+src);
		System.out.println("解密信息:"+result);
		return result;
	}
	/**
	 * 
	 * 使用公钥加密
	 */
	private byte[] encryptByPublicKey(String src) throws Exception {
		Cipher cipher = Cipher.getInstance(padding);
		cipher.init(Cipher.ENCRYPT_MODE, this.publicK );
		return encryptFinal(src,cipher);
	}
	/**
	 * 
	 * 使用私钥加密
	 */
	private byte[] encryptByPrivateKey(String src) throws Exception {
		Cipher cipher = Cipher.getInstance(padding);
		cipher.init(Cipher.ENCRYPT_MODE, this.privateK );
		return encryptFinal(src,cipher);
	}
	/**
	 *
	 * 使用公钥解密
	 */
	private String decryptByPublicKey(byte[] src) throws Exception {
		Cipher cipher = Cipher.getInstance(padding);
		cipher.init(Cipher.DECRYPT_MODE, this.publicK);
		return decryptFinal(src , cipher);
	}
	/**
	 * 
	 * 使用私钥解密
	 */
	private String decryptByPrivateKey(byte[] src) throws Exception {
		Cipher cipher = Cipher.getInstance(padding);
		cipher.init(Cipher.DECRYPT_MODE, this.privateK);
		return decryptFinal(src , cipher);
	}
	/**
	 * 加密的核心步骤
	 * @param src
	 * 如果src.getBytes("UTF-8").length > 117那么加密就会报错!需要做迭代处理。
	 * @param cipher
	 * @return
	 * @throws Exception
	 */
	private byte[] encryptFinal(String src , Cipher cipher) throws Exception  {
		byte[] enBytes = null;
		int len = src.getBytes(this.charset).length ;
		int limit = 117 ;
		if( len > limit ) {
			int remainder = len % limit ;
			int divisor = len / limit ;
			/*
			 * 整除数处理
			 * 处理以117为倍数的单元
			 */
			for(int i = 0 ; i < divisor ; i ++){
				byte[] subEnBytes = cipher.doFinal( src.getBytes(this.charset) , limit * i , limit) ;
				enBytes = ArrayUtils.addAll(enBytes, subEnBytes);
			}
			/*
			 * 余数处理
			 * 处理不足117的单元
			 */
			if( remainder > 0 ){
				byte[] subEnBytes = cipher.doFinal( src.getBytes(this.charset) , limit * divisor , remainder ) ;
				enBytes = ArrayUtils.addAll(enBytes,  subEnBytes);
			}
		}
		else{
			enBytes = cipher.doFinal(src.getBytes(this.charset));
		}
		return enBytes;
	}
	/**
	 * 解密的核心步骤
	 * @param src
	 * 如果src.length > 128那么就会报错!需要迭代处理。
	 * @param cipher
	 * @return
	 * @throws Exception
	 */
	private String decryptFinal(byte[] src ,Cipher cipher) throws Exception {
		byte[] deBytes = null;
		int len = src.length;
		int limit = 128 ;
		if( len > limit ){			
			int remainder = len % limit ;
			int divisor = len / limit ;
			/*
			 * 整除数处理
			 * 处理以128为倍数的单元
			 */
			for(int i = 0 ; i < divisor ; i ++){
				byte[] subDeBytes = ArrayUtils.subarray(src, limit * i , limit * i + limit);
				deBytes = ArrayUtils.addAll(deBytes, cipher.doFinal(subDeBytes) );
			}
			/*
			 * 余数处理
			 * 处理不足128的单元
			 * NOTE:在解密的时候都是以128为一个单元,尚为发现例外。所以这个步骤不会执行,留下它以防万一吧。
			 */
			if( remainder > 0 ) {
				byte[] subDeBytes = ArrayUtils.subarray(src, limit * divisor , limit * divisor + remainder );
				deBytes = ArrayUtils.addAll(deBytes, cipher.doFinal(subDeBytes) );
			}
		}
		else {
			deBytes = cipher.doFinal(src);
		}
		/*
		 * 如果是“RSA/ECB/NoPadding”模式,需要将(byte)0去掉
		 */
		if(this.padding.equals("RSA/ECB/NoPadding")){
			byte[] deBytesWithOutZero = null ;
			for(int i=0 ; i < deBytes.length ; i++){
				if( deBytes[i] == (byte)0 ){
					continue ;
				}
				else{
					deBytesWithOutZero = ArrayUtils.add(deBytesWithOutZero,deBytes[i]);
				}
			}
			return new String(deBytesWithOutZero,this.charset);
		}
		return new String(deBytes,this.charset);
	}
	/**
	 * 获得公钥
	 * @param modulus
	 * @param publicExponent
	 * @return
	 * @throws Exception
	 */
	public PublicKey getPublicKey(String modulus, String publicExponent) throws Exception {
		BigInteger m = new BigInteger(modulus);
		BigInteger e = new BigInteger(publicExponent);
		RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}
	/**
	 * 获得私钥
	 * @param modulus
	 * @param privateExponent
	 * @return
	 * @throws Exception
	 */
	public PrivateKey getPrivateKey(String modulus, String privateExponent) throws Exception {
		BigInteger m = new BigInteger(modulus);
		BigInteger e = new BigInteger(privateExponent);
		RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}
	/**
	 * 打印公钥与私钥
	 * @throws NoSuchAlgorithmException
	 */
	public void generateRSAKeys() throws NoSuchAlgorithmException{
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
		kpg.initialize(1024);
		KeyPair keyPair = kpg.generateKeyPair();
		RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
		System.out.println("#--- PUBLIC ---");
		System.out.println("modulus="+rsaPublicKey.getModulus());
		System.out.println("exponent="+rsaPublicKey.getPublicExponent());
		System.out.println("ispublic=true");
		System.out.println("#--- PRIVATE ---");
		System.out.println("modulus="+rsaPrivateKey.getModulus());
		System.out.println("exponent="+rsaPrivateKey.getPrivateExponent() );
		System.out.println("ispublic=false");
	}
}



你可能感兴趣的:(JAVA)