最近项目需求需要用到TCP传输,为了保证安全传输使用AES,为了使 传输过程中减 数据量小,使用gzip压缩,特此分享一哈。
一、AES加密
关于AES的资料网上很多,个人觉得《加密与解密(第三版)》很不错,这本书中P155开始讲AES 下载地址:
这个过程中我们使用 bcprov 这个jar包,官网: http://www.bouncycastle.org/
1. 我们秘钥的定义:
publicfinalstaticCipherParameterskeyParams1=newParametersWithIV( newKeyParameter(newbyte[]{(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0xab,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0xfc,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0xed,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01}),newbyte[]{(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0xcf,(byte)0x01});
2.加密方法
/**
*AES加密
*@paramdata数据
*@return
*@throwsInvalidCipherTextException
*/
publicstaticbyte[]encrypt(byte[]data)throwsInvalidCipherTextException
{
BufferedBlockCiphercipher=newPaddedBufferedBlockCipher(newCBCBlockCipher(newAESEngine()));
cipher.init(true, keyParams);//秘钥
byte[]encrypt=newbyte[cipher.getOutputSize(data.length)];
intsize=cipher.processBytes(data,0,data.length,encrypt,0);
byte[]encrypted=newbyte[size+cipher.doFinal(encrypt,size)];
System.arraycopy(encrypt,0,encrypted,0,encrypted.length);
returnencrypted;
}
二、AES解密
/**
*AES解密
*@paramdata数据
*@return
*@throwsInvalidCipherTextException
*/
publicstaticbyte[]decrypt(byte[]data)throwsInvalidCipherTextException
{
BufferedBlockCiphercipher=newPaddedBufferedBlockCipher(newCBCBlockCipher(newAESEngine()));
cipher.init(false, keyParams);//
byte[]decrypt=newbyte[cipher.getOutputSize(data.length)];
intlength=cipher.processBytes(data,0,data.length,decrypt,0);
byte[]decrypted=newbyte[length+cipher.doFinal(decrypt,length)];
System.arraycopy(decrypt,0,decrypted,0,decrypted.length);
returndecrypted;
}
三、Gizp压缩和解压缩
这一个部分网上有很多,比如下面这个大神的。
1. 压缩
1. /**
2. *数据压缩
3. *
4. *@paramis
5. *@paramos
6. *@throwsException
7. */
8. publicstaticvoidcompress(InputStreamis,OutputStreamos)
9. throwsException{
10.
11. GZIPOutputStreamgos=newGZIPOutputStream(os);
12.
13. intcount;
14. bytedata[]=newbyte[BUFFER];
15. while((count=is.read(data,0,BUFFER))!=-1){
16. gos.write(data,0,count);
17. }
18.
19. gos.finish();
20.
21. gos.flush();
22. gos.close();
23. }
2.解压缩
1. /**
2. *数据解压缩
3. *
4. *@paramis
5. *@paramos
6. *@throwsException
7. */
8. publicstaticvoiddecompress(InputStreamis,OutputStreamos)
9. throwsException{
10.
11. GZIPInputStreamgis=newGZIPInputStream(is);
12.
13. intcount;
14. bytedata[]=newbyte[BUFFER];
15. while((count=gis.read(data,0,BUFFER))!=-1){
16. os.write(data,0,count);
17. }
18.
19. gis.close();
20. }
四、简单示例
我们创建一个java程序模拟后台,创建一个android程序当做客户端。
1.后台(java控制台程序模拟)
主程序部分
/**
*@authorxiaoming
*@time2015年5月30日下午5:01:01
*@说明AesDemo
*/
publicclassAesDemo{
publicstaticvoidmain(String[]args){
test();
}
publicstaticvoidtest(){
ServerSocketss=null;
Sockets=null;
DataInputStreamdis=null;
DataOutputStreamdos=null;
try{
ss=newServerSocket(10000);
s=ss.accept();
//========================获取请求部分==========================
dis=newDataInputStream(s.getInputStream());
//读取数据
byte[]recData=(newTcpUtil()).readData(dis);
System.out.println("长度:"+recData.length);
解压缩
byte[]uncompress=GZipUtils.decompress(recData);
//解密
byte[]decrypt=AESUtil.decrypt(uncompress);
System.out.println("解密前:"+newString(uncompress));
System.out.println("解密后:"+newString(decrypt));
//======================响应部分================================
dos=newDataOutputStream(s.getOutputStream());
byte[]respData="傻逼傻逼蹦擦擦".getBytes();
//加密
byte[]encrypt=AESUtil.encrypt(respData);
压缩
byte[]compress=GZipUtils.compress(encrypt);
dos.writeInt(compress.length);//把数据的长度写过去
dos.write(compress);
dos.flush();
s.shutdownOutput();
}catch(InvalidCipherTextExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}catch(Exceptione){
e.printStackTrace();
}finally{
try{
//关闭资源
if(dis!=null){
dis.close();
}
if(dos!=null){
dos.close();
}
if(s!=null){
s.close();
}
if(ss!=null){
ss.close();
}
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
byte
[]recData=(
new
TcpUtil()).readData(dis);进行了封装。TcpUtil类如下:
/**
*@authorqiwenming
*@time2015年5月30日下午4:16:45
*@说明Tcp请求的工具类简单的实现一哈
*/
publicclassTcpUtil{
/**
*读取数据
*@throwsIOException
*/
publicstaticbyte[]readData(DataInputStreamdis)throwsIOException{
//数据的长度
intlength=dis.readInt();
inttmpLength=1024;//每次读取最大缓冲区大小
byte[]ret=newbyte[length];//读取到流
intreaded=0,offset=0,left=length;
byte[]bs=newbyte[tmpLength];
while(left>0)
{
try
{
readed=dis.read(bs,0,Math.min(tmpLength,left));
if(readed==-1)
break;
System.arraycopy(bs,0,ret,offset,readed);
}
finally
{
offset+=readed;
left-=readed;
}
}
returnret;
}
}
2.android端
我们主要请求一个数据使一哈。
Activiy中的主要代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
*测试一哈
*@paramv
*/
public
void
toTest(Viewv){
StringresMsg=
"写代码真累"
;
reqCleEdt.setText(resMsg);
try
{
byte
[]reqData=resMsg.getBytes();
//加密
byte
[]encrypt=AESUtil.encrypt(reqData);
reqCipEdt.setText(
new
String(encrypt));
//压缩
final
byte
[]compress=GZipUtils.compress(encrypt);
new
Thread(){
public
void
run(){
try
{
byte
[]respData=
new
TcpUtil().requstData(compress);
//解压缩
final
byte
[]uncompress=GZipUtils.decompress(respData);
//解密
final
byte
[]decrypt=AESUtil.decrypt(uncompress);
runOnUiThread(
new
Runnable(){
public
void
run(){
respCleEdt.setText(
new
String(decrypt));
respCipEdt.setText(
new
String(uncompress));
}
});
}
catch
(InvalidCipherTextExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
catch
(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
};
}.start();
}
catch
(InvalidCipherTextExceptione){
e.printStackTrace();
}
catch
(Exceptione){
e.printStackTrace();
}
}
上面用到的获取响应数据的方法: byte[]respData=new TcpUtil().requstData(compress);我进行了封装,如下:
/**
*@authorqiwenming
*@time2015年5月30日下午4:16:45
*@说明Tcp请求的工具类简单的实现一哈
*/
publicclassTcpUtil{
privateOutputStreamoutputStream;
privateInputStreaminputStream;
privateSocketsocket;
/**
*请求数据
*@return
*/
publicbyte[]requstData(byte[]data)throwsException{
try{
if(socket==null){
socket=newSocket("192.168.1.106",10000);
}
outputStream=socket.getOutputStream();
DataOutputStreamdos=newDataOutputStream(outputStream);
dos.writeInt(data.length);
dos.write(data);//把数据的长度写过去
dos.flush();
socket.shutdownOutput();//数据发完
byte[]recData=responseData();
returnrecData;
}finally{
// disconnect();
}
}
/**
*响应的数据
*@throwsIOException
*/
publicbyte[]responseData()throwsIOException{
inputStream=socket.getInputStream();
DataInputStreamdis=newDataInputStream(inputStream);
//数据的长度
intlength=dis.readInt();
inttmpLength=1024;//每次读取最大缓冲区大小
byte[]ret=newbyte[length];//读取到流
intreaded=0,offset=0,left=length;
byte[]bs=newbyte[tmpLength];
while(left>0)
{
try
{
readed=dis.read(bs,0,Math.min(tmpLength,left));
if(readed==-1)
break;
System.arraycopy(bs,0,ret,offset,readed);
}
finally
{
offset+=readed;
left-=readed;
}
}
returnret;
}
/**
*关闭资源
*@throwsIOException
*/
publicvoiddisconnect()throwsIOException
{
if(outputStream!=null)
{
outputStream.close();
}
if(inputStream!=null)
{
inputStream.close();
}
if(socket!=null&&!socket.isClosed())
{
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
}
}
}
五、运行结果
如果你在使用的使用GZIP压缩错误的话,使用第三方的包(commons-compress),就ok了。