TCP传输中使用AES加密和gizp压缩
最近项目需求需要用到TCP传输,为了保证安全传输使用AES,为了使传输过程中减数据量小,使用gzip压缩,特此分享一哈。
二、AES解密
一、AES加密
关于AES的资料网上很多,个人觉得《加密与解密(第三版)》很不错,这本书中P155开始讲AES 下载地址:http://download.****.net/detail/qiwenmingshiwo/8755683
AES加解密算法的模式介绍 http://blog.****.NET/searchsun/article/details/2516191
这个过程中我们使用 bcprov 这个jar包,官网:http://www.bouncycastle.org/
1. 我们秘钥的定义:
1234567891011121314public
final
static
CipherParameters keyParams1 =
new
ParametersWithIV(
new
KeyParameter(
new
byte
[] { (
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
}),
new
byte
[] { (
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.加密方法
12345678910111213141516
/**
* AES加密
* @param data数据
* @return
* @throws InvalidCipherTextException
*/
public
static
byte
[] encrypt(
byte
[] data)
throws
InvalidCipherTextException
{
BufferedBlockCipher cipher =
new
PaddedBufferedBlockCipher(
new
CBCBlockCipher(
new
AESEngine()));
cipher.init(
true
, keyParams);
//秘钥
byte
[] encrypt =
new
byte
[cipher.getOutputSize(data.length)];
int
size = cipher.processBytes(data,
0
, data.length, encrypt,
0
);
byte
[] encrypted =
new
byte
[size + cipher.doFinal(encrypt, size)];
System.arraycopy(encrypt,
0
, encrypted,
0
, encrypted.length);
return
encrypted;
}
二、AES解密
12345678910111213141516
/**
* AES解密
* @param data数据
* @return
* @throws InvalidCipherTextException
*/
public
static
byte
[] decrypt(
byte
[] data)
throws
InvalidCipherTextException
{
BufferedBlockCipher cipher =
new
PaddedBufferedBlockCipher(
new
CBCBlockCipher(
new
AESEngine()));
cipher.init(
false
, keyParams);
//
byte
[] decrypt =
new
byte
[cipher.getOutputSize(data.length)];
int
length = cipher.processBytes(data,
0
, data.length, decrypt,
0
);
byte
[] decrypted =
new
byte
[length + cipher.doFinal(decrypt, length)];
System.arraycopy(decrypt,
0
, decrypted,
0
, decrypted.length);
return
decrypted;
}
三、Gizp压缩和解压缩
这一个部分网上有很多,比如下面这个大神的。Java压缩技术(四) GZIP——Java原生实现
1. 压缩
- /**
- * 数据压缩
- *
- * @param is
- * @param os
- * @throws Exception
- */
- public static void compress(InputStream is, OutputStream os)
- throws Exception {
- GZIPOutputStream gos = new GZIPOutputStream(os);
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = is.read(data, 0, BUFFER)) != -1) {
- gos.write(data, 0, count);
- }
- gos.finish();
- gos.flush();
- gos.close();
- }
2.解压缩
- /**
- * 数据解压缩
- *
- * @param is
- * @param os
- * @throws Exception
- */
- public static void decompress(InputStream is, OutputStream os)
- throws Exception {
- GZIPInputStream gis = new GZIPInputStream(is);
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = gis.read(data, 0, BUFFER)) != -1) {
- os.write(data, 0, count);
- }
- gis.close();
- }
四、简单示例
我们创建一个java程序模拟后台,创建一个android程序当做客户端。1.后台(java控制台程序模拟)主程序部分
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071/**
* @author xiaoming
* @time 2015年5月30日 下午5:01:01
* @说明 AesDemo
*/
public
class
AesDemo {
public
static
void
main(String[] args) {
test();
}
public
static
void
test() {
ServerSocket ss =
null
;
Socket s =
null
;
DataInputStream dis =
null
;
DataOutputStream dos =
null
;
try
{
ss =
new
ServerSocket(
10000
);
s = ss.accept();
//========================获取请求部分==========================
dis =
new
DataInputStream(s.getInputStream());
//读取数据
byte
[] recData = (
new
TcpUtil()).readData(dis);
System.out.println(
"长度:"
+ recData.length);
// //解压缩
byte
[] uncompress = GZipUtils.decompress(recData);
// 解密
byte
[] decrypt = AESUtil.decrypt(uncompress);
System.out.println(
"解密前:"
+
new
String(uncompress));
System.out.println(
"解密后:"
+
new
String(decrypt));
//======================响应部分================================
dos =
new
DataOutputStream(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
(InvalidCipherTextException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
catch
(Exception e) {
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
(IOException e) {
e.printStackTrace();
}
}
}
}
上面读取数据时候使用的:
byte
[] recData = (
new
TcpUtil()).readData(dis);进行了封装。TcpUtil类如下:
12345678910111213141516171819202122232425262728293031323334353637/**
* @author qiwenming
* @time 2015年5月30日 下午4:16:45
* @说明 Tcp请求的工具类 简单的实现一哈
*/
public
class
TcpUtil {
/**
* 读取数据
* @throws IOException
*/
public
static
byte
[] readData(DataInputStream dis)
throws
IOException{
//数据的长度
int
length = dis.readInt();
int
tmpLength =
1024
;
// 每次读取最大缓冲区大小
byte
[] ret =
new
byte
[length];
//读取到流
int
readed =
0
, offset =
0
, left = length;
byte
[] bs =
new
byte
[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;
}
}
return
ret;
}
}
2.android端
我们主要请求一个数据使一哈。
Activiy中的主要代码:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
/**
* 测试一哈
* @param v
*/
public
void
toTest(View v){
String resMsg =
"写代码真累"
;
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
(InvalidCipherTextException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
}.start();
}
catch
(InvalidCipherTextException e) {
e.printStackTrace();
}
catch
(Exception e) {
e.printStackTrace();
}
}
上面用到的获取响应数据的方法:
byte
[] respData =
new
TcpUtil().requstData(compress);我进行了封装,如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687/**
* @author qiwenming
* @time 2015年5月30日 下午4:16:45
* @说明 Tcp请求的工具类 简单的实现一哈
*/
public
class
TcpUtil {
private
OutputStream outputStream;
private
InputStream inputStream;
private
Socket socket;
/**
* 请求数据
* @return
*/
public
byte
[] requstData(
byte
[] data)
throws
Exception{
try
{
if
(socket==
null
){
socket =
new
Socket(
"192.168.1.106"
,
10000
);
}
outputStream = socket.getOutputStream();
DataOutputStream dos =
new
DataOutputStream(outputStream);
dos.writeInt(data.length);
dos.write(data);
//把数据的长度写过去
dos.flush();
socket.shutdownOutput();
//数据发完
byte
[] recData = responseData();
return
recData;
}
finally
{
// disconnect();
}
}
/**
* 响应的数据
* @throws IOException
*/
public
byte
[] responseData()
throws
IOException{
inputStream = socket.getInputStream();
DataInputStream dis =
new
DataInputStream(inputStream);
//数据的长度
int
length = dis.readInt();
int
tmpLength =
1024
;
// 每次读取最大缓冲区大小
byte
[] ret =
new
byte
[length];
//读取到流
int
readed =
0
, offset =
0
, left = length;
byte
[] bs =
new
byte
[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;
}
}
return
ret;
}
/**
* 关闭资源
* @throws IOException
*/
public
void
disconnect()
throws
IOException
{
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了。![]()