详解Android端与JavaWeb传输加密(DES+RSA)
一、加密介绍
本文采用对称式加密算法DES和非对称式加密算法RSA结合做数据传输加密的方式。
先说一下对称式加密DES:对称式加密即使用单钥密码加密的方法,信息的加密和解密使用同一个秘钥,这种方式也称为单秘钥加密。所谓对称就是指加密和解密使用的是同一个秘钥!
常用的对称加密有:DES、IDEA、RC2、RC4、SKIPJACK、RC5、AES算法等。
与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
RSA公钥加密算法是1977年由RonRivest、AdiShamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
二、RSA密钥生成
RSA密钥采用OpenSSL协议进行生成,本文仅简单生成公钥和私钥,如有其它需要可以通过CA证书进行密钥的生成
1、OpenSSL安装
http://slproweb.com/products/Win32OpenSSL.html
请自行选择32位64位进行下载安装
2、打开工作空间
打开OpenSSL安装目录下的bin,运行OpenSSL.exe进入OpenSSL工作空间
3、密钥生成
①、私钥生成(生成位置位于bin目录下)
genrsa-outrsa_private_key.pem1024
openssl随机生成了一份私钥,加密长度是1024位。加密长度是指理论上最大允许”被加密的信息“长度的限制,也就是明文的长度限制。随着这个参数的增大(比方说2048),允许的明文长度也会增加,但同时也会造成计算复杂度的极速增长。一般推荐的长度就是1024位(128字节)
JAVA需要使用的私钥需要经过PKCS#8编码,PHP程序不需要
当前私钥格式需要转换为pkcs#8的格式,命令为:
pkcs8-topk8-informPEM-inpkcs8_rsa_private_key.pem-outformPEM-nocrypt
②、公钥生成
rsa-inrsa_private_key.pem-outrsa_public_key.pem-pubout
至此,RSA+DES相关前期准备工作完成
三、Android端配置
本文主要针对数据传输过程进行加密,采取加密Json字符串完成整个加密过程,由此,需要统一传输参数为"data=********&sign="*******************"的格式,如有其它需求请自行更改。
由于本项目网络框架采用Retrofit+OkHttp的实现方式,所以对参数进行加密的过程由OkHttp拦截器来实现
publicclassEncryptionInterceptorimplementsInterceptor{
privateContextmContext;
publicEncryptionInterceptor(Contextcontext){
this.mContext=context;
}
@Override
publicResponseintercept(@NonNullChainchain)throwsIOException{
Requestrequest=chain.request();
RequestBodyoldBody=request.body();
Bufferbuffer=newBuffer();
if(oldBody!=null){
oldBody.writeTo(buffer);
}
StringstrOldBody=buffer.readUtf8();
Mapmap=newHashMap<>();
StringdataByte=URLDecoder.decode(strOldBody.substring(5),"utf-8");
try{
//获取DES的key
byte[]desKey=DESCoder.initKey();
//DES加密数据
byte[]encrypt=DESCoder.encrypt(dataByte.getBytes(),desKey);
map.put("data",parseByte2HexStr(encrypt));
//RSA加密
RSAEncryptrsaEncrypt=newRSAEncrypt();
InputStreaminputStream=mContext.getResources().getAssets().open("rsa_public_key.pem");
//rsa设置公钥
rsaEncrypt.loadPublicKey(inputStream);
//rsa加密DES的key
byte[]rsaData=rsaEncrypt.encrypt(rsaEncrypt.getPublicKey(),desKey);
map.put("sign",parseByte2HexStr(rsaData));
}catch(Exceptione){
e.printStackTrace();
}
FormBodybody=newFormBody.Builder().add("data",map.get("data")).add("sign",map.get("sign")).build();
request=request.newBuilder().header("Content-Type",body.contentType().type()).header("Content-Length",String.valueOf(body.contentLength())).method(request.method(),body).build();
returnchain.proceed(request);
}
/**
*将二进制转换成16进制
*
*@sincev1.0
*/
privatestaticStringparseByte2HexStr(bytebuf[]){
StringBuildersb=newStringBuilder();
for(byteaBuf:buf){
Stringhex=Integer.toHexString(aBuf&0xFF);
if(hex.length()==1){
hex='0'+hex;
}
sb.append(hex.toUpperCase());
}
returnsb.toString();
}
/**
*按照key排序得到参数列表字符串
*
*@paramparamValues参数map对象
*@return参数列表字符串
*/
publicstaticStringgetParamsOrderByKey(MapparamValues){
Stringparams="";
ListparamNames=newArrayList<>(paramValues.size());
paramNames.addAll(paramValues.keySet());
Collections.sort(paramNames);
for(StringparamName:paramNames){
if(params.equals("")){
params+=paramName+"="+paramValues.get(paramName);
}else{
params+="&"+paramName+"="+paramValues.get(paramName);
}
}
returnparams;
}
/**
*将16进制转换为二进制
*
*@sincev1.0
*/
publicbyte[]parseHexStr2Byte(StringhexStr){
if(hexStr.length()<1)
returnnull;
byte[]result=newbyte[hexStr.length()/2];
for(inti=0;i
添加OkHttp拦截器
newOkHttpClient.Builder()
.addInterceptor(newEncryptionInterceptor(this))
.build();
RSA工具类实现
publicclassRSAEncrypt{
publicstaticfinalStringDEFAULT_PUBLIC_KEY=
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1Qcf1zVOuhseFxvo6+FnVvEPs"+"\r"+"Uvczg6oX+HjMNksiiDWcNkbPHfznaPDtgoBY2xF0R8HGHbrT53LNvkj7UMcI48tq"+"\r"+"K+B4YdJHe9SgJVDCCiceLLGtf/ev206qJ/XgKgrLFD+vMmjIB8gQCkZvy/dxhEf1"+"\r"+"aAmoz5tdJhOVdxT7QwIDAQAB"+"\r";
publicstaticfinalStringDEFAULT_PRIVATE_KEY=
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALVBx/XNU66Gx4XG"+"\r"+
"+jr4WdW8Q+xS9zODqhf4eMw2SyKINZw2Rs8d/Odo8O2CgFjbEXRHwcYdutPncs2+"+"\r"+
"SPtQxwjjy2or4Hhh0kd71KAlUMIKJx4ssa1/96/bTqon9eAqCssUP68yaMgHyBAK"+"\r"+
"Rm/L93GER/VoCajPm10mE5V3FPtDAgMBAAECgYAf1hEAHHNhSS0MUzmqV+q3ftzT"+"\r"+
"SnM+6hZbJXpaLAMgapo3+NSRFmxQXP9MSEqw0LGNIfloCdrB03o3pv98nOCIZCh7"+"\r"+
"PHsU2GhxJ04Qro+wKhK358326KNXCjjqVIBG0xMbJxVhjM2/jjfocxFpe5iD7h53"+"\r"+
"c+GvDgUVduAYO4I1GQJBAO21n2aIzQV3mScS1O8BRV+9CmHaDbVHqBetRoB3kJ2U"+"\r"+
"piflKTNofwWmTA5A8sKt8WcOz7LsB2SWcp9jNvatxA8CQQDDNCmfo6eix9e5f11K"+"\r"+
"Rf8sRiN7XGDzlKkZlmQAN0UtXdTP4AN9cuZrwnntWKysXr/zLntYLGYn9rdrohbD"+"\r"+
"9RGNAkBOEsog7iuQcSCfQcMoIN29PSSs0OaRtNBTvniadyrLZuhP0CeBGAAoRd9T"+"\r"+
"CyfwoxrXg3jaRkWDVxqcmQSTbq0nAkB8flcRhilSqsuNdYpE5VFxpiXY9jirAKO8"+"\r"+
"Our6LEXFQjOIhCEVr+L+1OA4HDa8FA2thXaK7H4WfMXMMmr8fN69AkEAuR0YU9My"+"\r"+
"snzWLDWYR5sNp90PhyDSL/HTZHBnebD+JlAYwoYRFYt+tXw0/PEmV2B3thYGPeiZ"+"\r"+
"kHKd/TeLIVbxGg=="+"\r";
/**
*私钥
*/
privateRSAPrivateKeyprivateKey;
/**
*公钥
*/
privateRSAPublicKeypublicKey;
/**
*字节数据转字符串专用集合
*/
privatestaticfinalchar[]HEX_CHAR={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/**
*获取私钥
*
*@return当前的私钥对象
*/
publicRSAPrivateKeygetPrivateKey(){
returnprivateKey;
}
/**
*获取公钥
*
*@return当前的公钥对象
*/
publicRSAPublicKeygetPublicKey(){
returnpublicKey;
}
/**
*随机生成密钥对
*/
publicvoidgenKeyPair(){
KeyPairGeneratorkeyPairGen=null;
try{
keyPairGen=KeyPairGenerator.getInstance("RSA");
}catch(NoSuchAlgorithmExceptione){
e.printStackTrace();
}
keyPairGen.initialize(1024,newSecureRandom());
KeyPairkeyPair=keyPairGen.generateKeyPair();
this.privateKey=(RSAPrivateKey)keyPair.getPrivate();
this.publicKey=(RSAPublicKey)keyPair.getPublic();
}
/**
*从文件中输入流中加载公钥
*
*@paramin公钥输入流
*@throwsException加载公钥时产生的异常
*/
publicvoidloadPublicKey(InputStreamin)throwsException{
try{
BufferedReaderbr=newBufferedReader(newInputStreamReader(in));
StringreadLine=null;
StringBuildersb=newStringBuilder();
while((readLine=br.readLine())!=null){
if(readLine.charAt(0)=='-'){
continue;
}else{
sb.append(readLine);
sb.append('\r');
}
}
loadPublicKey(sb.toString());
}catch(IOExceptione){
thrownewException("公钥数据流读取错误");
}catch(NullPointerExceptione){
thrownewException("公钥输入流为空");
}
}
/**
*从字符串中加载公钥
*
*@parampublicKeyStr公钥数据字符串
*@throwsException加载公钥时产生的异常
*/
publicvoidloadPublicKey(StringpublicKeyStr)throwsException{
try{
//byte[]buffer=Base64.decode(publicKeyStr.getBytes(),Base64.DEFAULT);
BASE64Decoderbase64Decoder=newBASE64Decoder();
byte[]buffer=base64Decoder.decodeBuffer(publicKeyStr);
KeyFactorykeyFactory=KeyFactory.getInstance("RSA");
X509EncodedKeySpeckeySpec=newX509EncodedKeySpec(buffer);
this.publicKey=(RSAPublicKey)keyFactory.generatePublic(keySpec);
}catch(NoSuchAlgorithmExceptione){
thrownewException("无此算法");
}catch(InvalidKeySpecExceptione){
thrownewException("公钥非法");
}catch(NullPointerExceptione){
thrownewException("公钥数据为空");
}
}
/**
*从文件中加载私钥
*
*@return是否成功
*@throwsException
*/
publicvoidloadPrivateKey(InputStreamin)throwsException{
try{
BufferedReaderbr=newBufferedReader(newInputStreamReader(in));
StringreadLine=null;
StringBuildersb=newStringBuilder();
while((readLine=br.readLine())!=null){
if(readLine.charAt(0)=='-'){
continue;
}else{
sb.append(readLine);
sb.append('\r');
}
}
loadPrivateKey(sb.toString());
}catch(IOExceptione){
thrownewException("私钥数据读取错误");
}catch(NullPointerExceptione){
thrownewException("私钥输入流为空");
}
}
publicvoidloadPrivateKey(StringprivateKeyStr)throwsException{
try{
//byte[]buffer=Base64.encode(privateKeyStr.getBytes(),Base64.DEFAULT);
BASE64Decoderbase64Decoder=newBASE64Decoder();
byte[]buffer=base64Decoder.decodeBuffer(privateKeyStr);
PKCS8EncodedKeySpeckeySpec=newPKCS8EncodedKeySpec(buffer);
KeyFactorykeyFactory=KeyFactory.getInstance("RSA");
this.privateKey=(RSAPrivateKey)keyFactory.generatePrivate(keySpec);
}catch(NoSuchAlgorithmExceptione){
thrownewException("无此算法");
}catch(InvalidKeySpecExceptione){
thrownewException("私钥非法");
}catch(NullPointerExceptione){
thrownewException("私钥数据为空");
}
}
/**
*加密过程
*
*@parampublicKey公钥
*@paramplainTextData明文数据
*@return
*@throwsException加密过程中的异常信息
*/
publicbyte[]encrypt(RSAPublicKeypublicKey,byte[]plainTextData)throwsException{
if(publicKey==null){
thrownewException("加密公钥为空,请设置");
}
Ciphercipher=null;
try{
cipher=Cipher.getInstance("RSA");
//Android端无需添加此加密提供者,已默认实现
//cipher=Cipher.getInstance("RSA",newBouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE,publicKey);
returncipher.doFinal(plainTextData);
}catch(NoSuchAlgorithmExceptione){
thrownewException("无此加密算法");
}catch(NoSuchPaddingExceptione){
e.printStackTrace();
returnnull;
}catch(InvalidKeyExceptione){
thrownewException("加密公钥非法,请检查");
}catch(IllegalBlockSizeExceptione){
thrownewException("明文长度非法");
}catch(BadPaddingExceptione){
thrownewException("明文数据已损坏");
}
}
/**
*解密过程
*
*@paramprivateKey私钥
*@paramcipherData密文数据
*@return明文
*@throwsException解密过程中的异常信息
*/
publicbyte[]decrypt(RSAPrivateKeyprivateKey,byte[]cipherData)throwsException{
if(privateKey==null){
thrownewException("解密私钥为空,请设置");
}
Ciphercipher=null;
try{
cipher=Cipher.getInstance("RSA");
//Android端无需添加此加密提供者,已默认实现
//cipher=Cipher.getInstance("RSA",newBouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE,privateKey);
byte[]output=cipher.doFinal(cipherData);
returnoutput;
}catch(NoSuchAlgorithmExceptione){
thrownewException("无此解密算法");
}catch(NoSuchPaddingExceptione){
e.printStackTrace();
returnnull;
}catch(InvalidKeyExceptione){
thrownewException("解密私钥非法,请检查");
}catch(IllegalBlockSizeExceptione){
thrownewException("密文长度非法");
}catch(BadPaddingExceptione){
thrownewException("密文数据已损坏");
}
}
/**
*字节数据转十六进制字符串
*
*@paramdata输入数据
*@return十六进制内容
*/
publicstaticStringbyteArrayToString(byte[]data){
StringBuilderstringBuilder=newStringBuilder();
for(inti=0;i>>4]);
//取出字节的低四位作为索引得到相应的十六进制标识符
stringBuilder.append(HEX_CHAR[(data[i]&0x0f)]);
if(i
DES工具类实现
publicclassDESCoder{
/**
*密钥算法
*java7只支持56位密钥
*BouncyCastle支持64位密钥
*/
publicstaticfinalStringKEY_ALGORITHM="DES";
/**
*加密/解密算法/工作模式/填充方式
*/
publicstaticfinalStringCIPHER_ALGORITHM="DES/ECB/PKCS5Padding";
/**
*转换密钥
*@paramkey二进制密钥
*@returnkey密钥
*@throwsException
*/
privatestaticKeytoKey(byte[]key)throwsException{
//实例化DES密钥材料
DESKeySpecdks=newDESKeySpec(key);
//实例化密钥工厂
SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance(KEY_ALGORITHM);
//生产密钥
SecretKeysecretKey=keyFactory.generateSecret(dks);
returnsecretKey;
}
/**
*解密
*@paramdata待解密数据
*@paramkey密钥
*@returnbyte[]解密数据
*@throwsException
*/
publicstaticbyte[]decrypt(byte[]data,byte[]key)throwsException{
//还原密钥
Keyk=toKey(key);
//实例化
Ciphercipher=Cipher.getInstance(CIPHER_ALGORITHM);
//初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE,k);
//执行操作
returncipher.doFinal(data);
}
/**
*加密
*@paramdata待加密数据
*@paramkey密钥
*@returnbyte[]加密数据
*@throwsException
*/
publicstaticbyte[]encrypt(byte[]data,byte[]key)throwsException{
//还原密钥
Keyk=toKey(key);
//实例化
Ciphercipher=Cipher.getInstance(CIPHER_ALGORITHM,newBouncyCastleProvider());
//初始化,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE,k);
//执行操作
returncipher.doFinal(data);
}
/**
*生产密钥
*java7只支持56位密钥
*BouncyCastle支持64位密钥
*@returnbyte[]二进制密钥
*@throwsException
*/
publicstaticbyte[]initKey()throwsException{
/*
*实例化密钥生成器
*若要使用64位密钥注意替换
*讲下述代码中的
*KeyGenerator.getInstance(KEY_ALGORITHM);
*替换为
*KeyGenerator.getInstance(KEY_ALGORITHM,"BC");
*/
KeyGeneratorkg=KeyGenerator.getInstance(KEY_ALGORITHM,newBouncyCastleProvider());
kg.init(64);
//生成密钥
SecretKeysecretKey=kg.generateKey();
//获得密钥的二进制编码形式
returnsecretKey.getEncoded();
}
}
四、JavaWeb端配置
Web后端只需要在Controller中添加以下代码,接受服务端传递的data和sign,并完成接收的Json字符串转换为实体类即可
/**
*解密所需数据
*
*@paramdata接受客户端上传的Json格式的数据
*@paramsign接受客户端上传的解密数据的key值
*/
publicTconvertJson(Stringdata,Stringsign,Classclazz){
System.out.println(data);
System.out.println(sign);
TtClass=null;
try{
//rsa加密
RSAEncryptrsaEncrypt=newRSAEncrypt();
//加载rsa私钥
InputStreamin=newFileInputStream(newFile("C:\\OpenSSL-Win64\\bin\\pkcs8_rsa_private_key.pem"));
rsaEncrypt.loadPrivateKey(in);
//获取RSA加密的key的数据,并把该16进制的sign转成byte[],(客户端采用将byte[]转成16进制进行数据上传)
byte[]keyBytes=parseHexStr2Byte(sign);
//通过RSA解密DES的key值
byte[]rsaKey=rsaEncrypt.decrypt(rsaEncrypt.getPrivateKey(),keyBytes);
//通过DES的key值解密需要的json数据
byte[]desData=DESCoder.decrypt(parseHexStr2Byte(data),rsaKey);
System.out.println(Arrays.toString(desData));
System.out.println(newString(desData));
tClass=JSON.parseObject(newString(desData),clazz);
}catch(Exceptione){
e.printStackTrace();
}
returntClass;
}
五、备注
后续会上传相关Demo到Github
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。