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");
}
}