先前一直在做安卓,最近要开发iPhone客户端,这其中遇到的最让人纠结的要属Java、Android和iPhone三个平台加解密不一致的问题。因为手机端后台通常是用JAVA开发的Web Service,Android和iPhone客户端调用同样的Web Service接口,为了数据安全考虑,要对数据进行加密。头疼的问题就来了,很难编写出一套加密程序,在3个平台间加解密的结果一致,总不能为Android和iPhone两个客户端各写一套Web Service接口吧?我相信还会有很多朋友为此困惑,在此分享一套3DES加密程序,能够实现Java、Android和iPhone三个平台加解密一致。
首先是JAVA端的加密工具类,它同样适用于Android端,无需任何修改,即可保证Java与Android端的加解密一致,并且中文不会乱码。
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
package
org.liuyq.des3;
import
java.security.Key;
import
javax.crypto.Cipher;
import
javax.crypto.SecretKeyFactory;
import
javax.crypto.spec.DESedeKeySpec;
import
javax.crypto.spec.IvParameterSpec;
/**
* 3DES加密工具类
*
* @author liufeng
* @date 2012-10-11
*/
public
class
Des3 {
// 密钥
private
final
static
String secretKey =
"liuyunqiang@lx100$#365#$"
;
// 向量
private
final
static
String iv =
"01234567"
;
// 加解密统一使用的编码方式
private
final
static
String encoding =
"utf-8"
;
/**
* 3DES加密
*
* @param plainText 普通文本
* @return
* @throws Exception
*/
public
static
String encode(String plainText)
throws
Exception {
Key deskey =
null
;
DESedeKeySpec spec =
new
DESedeKeySpec(secretKey.getBytes());
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(
"desede"
);
deskey = keyfactory.generateSecret(spec);
Cipher cipher = Cipher.getInstance(
"desede/CBC/PKCS5Padding"
);
IvParameterSpec ips =
new
IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
byte
[] encryptData = cipher.doFinal(plainText.getBytes(encoding));
return
Base64.encode(encryptData);
}
/**
* 3DES解密
*
* @param encryptText 加密文本
* @return
* @throws Exception
*/
public
static
String decode(String encryptText)
throws
Exception {
Key deskey =
null
;
DESedeKeySpec spec =
new
DESedeKeySpec(secretKey.getBytes());
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(
"desede"
);
deskey = keyfactory.generateSecret(spec);
Cipher cipher = Cipher.getInstance(
"desede/CBC/PKCS5Padding"
);
IvParameterSpec ips =
new
IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
byte
[] decryptData = cipher.doFinal(Base64.decode(encryptText));
return
new
String(decryptData, encoding);
}
}
|
上面的加密工具类会使用到Base64这个类,该类的源代码如下:
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
package
org.liuyq.des3;
import
java.io.ByteArrayOutputStream;
import
java.io.IOException;
import
java.io.OutputStream;
/**
* Base64编码工具类
*
* @author liufeng
* @date 2012-10-11
*/
public
class
Base64 {
private
static
final
char
[] legalChars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
.toCharArray();
public
static
String encode(
byte
[] data) {
int
start =
0
;
int
len = data.length;
StringBuffer buf =
new
StringBuffer(data.length *
3
/
2
);
int
end = len -
3
;
int
i = start;
int
n =
0
;
while
(i <= end) {
int
d = ((((
int
) data[i]) &
0x0ff
) <<
16
) | ((((
int
) data[i +
1
]) &
0x0ff
) <<
8
) | (((
int
) data[i +
2
]) &
0x0ff
);
buf.append(legalChars[(d >>
18
) &
63
]);
buf.append(legalChars[(d >>
12
) &
63
]);
buf.append(legalChars[(d >>
6
) &
63
]);
buf.append(legalChars[d &
63
]);
i +=
3
;
if
(n++ >=
14
) {
n =
0
;
buf.append(
" "
);
}
}
if
(i == start + len -
2
) {
int
d = ((((
int
) data[i]) &
0x0ff
) <<
16
) | ((((
int
) data[i +
1
]) &
255
) <<
8
);
buf.append(legalChars[(d >>
18
) &
63
]);
buf.append(legalChars[(d >>
12
) &
63
]);
buf.append(legalChars[(d >>
6
) &
63
]);
buf.append(
"="
);
}
else
if
(i == start + len -
1
) {
int
d = (((
int
) data[i]) &
0x0ff
) <<
16
;
buf.append(legalChars[(d >>
18
) &
63
]);
buf.append(legalChars[(d >>
12
) &
63
]);
buf.append(
"=="
);
}
return
buf.toString();
}
private
static
int
decode(
char
c) {
if
(c >=
'A'
&& c <=
'Z'
)
return
((
int
) c) -
65
;
else
if
(c >=
'a'
&& c <=
'z'
)
return
((
int
) c) -
97
+
26
;
else
if
(c >=
'0'
&& c <=
'9'
)
return
((
int
) c) -
48
+
26
+
26
;
else
switch
(c) {
case
'+'
:
return
62
;
case
'/'
:
return
63
;
case
'='
:
return
0
;
default
:
throw
new
RuntimeException(
"unexpected code: "
+ c);
}
}
/**
* Decodes the given Base64 encoded String to a new byte array. The byte array holding the decoded data is returned.
*/
public
static
byte
[] decode(String s) {
ByteArrayOutputStream bos =
new
ByteArrayOutputStream();
try
{
decode(s, bos);
}
catch
(IOException e) {
throw
new
RuntimeException();
}
byte
[] decodedBytes = bos.toByteArray();
try
{
bos.close();
bos =
null
;
}
catch
(IOException ex) {
System.err.println(
"Error while decoding BASE64: "
+ ex.toString());
}
return
decodedBytes;
}
private
static
void
decode(String s, OutputStream os)
throws
IOException {
int
i =
0
;
int
len = s.length();
while
(
true
) {
while
(i < len && s.charAt(i) <=
' '
)
i++;
if
(i == len)
break
;
int
tri = (decode(s.charAt(i)) <<
18
) + (decode(s.charAt(i +
1
)) <<
12
) + (decode(s.charAt(i +
2
)) <<
6
) + (decode(s.charAt(i +
3
)));
os.write((tri >>
16
) &
255
);
if
(s.charAt(i +
2
) ==
'='
)
break
;
os.write((tri >>
8
) &
255
);
if
(s.charAt(i +
3
) ==
'='
)
break
;
os.write(tri &
255
);
i +=
4
;
}
}
}
|
接下来是iPhone端的加密程序,当然是用Ojbective-C写的3DES加密程序,源代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//
// DES3Util.h
// lx100-gz
//
// Created by 柳峰 on 12-10-10.
// Copyright 2012 http://blog.csdn.net/lyq8479. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface DES3Util : NSObject {
}
// 加密方法
+ (NSString*)encrypt:(NSString*)plainText;
// 解密方法
+ (NSString*)decrypt:(NSString*)encryptText;
@end
|
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
//
// DES3Util.m
// lx100-gz
//
// Created by 柳峰 on 12-9-17.
// Copyright 2012 http://blog.csdn.net/lyq8479. All rights reserved.
//
#import "DES3Util.h"
#import <CommonCrypto/CommonCryptor.h>
#import "GTMBase64.h"
#define gkey @"liuyunqiang@lx100$#365#$"
#define gIv @"01234567"
@implementation DES3Util
// 加密方法
+ (NSString*)encrypt:(NSString*)plainText {
NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
size_t plainTextBufferSize = [data length];
const void *vplainText = (const void *)[data bytes];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
const void *vkey = (const void *) [gkey UTF8String];
const void *vinitVec = (const void *) [gIv UTF8String];
ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithm3DES,
kCCOptionPKCS7Padding,
vkey,
kCCKeySize3DES,
vinitVec,
vplainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
NSString *result = [GTMBase64 stringByEncodingData:myData];
return result;
}
// 解密方法
+ (NSString*)decrypt:(NSString*)encryptText {
NSData *encryptData = [GTMBase64 decodeData:[encryptText dataUsingEncoding:NSUTF8StringEncoding]];
size_t plainTextBufferSize = [encryptData length];
const void *vplainText = [encryptData bytes];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
const void *vkey = (const void *) [gkey UTF8String];
const void *vinitVec = (const void *) [gIv UTF8String];
ccStatus = CCCrypt(kCCDecrypt,
kCCAlgorithm3DES,
kCCOptionPKCS7Padding,
vkey,
kCCKeySize3DES,
vinitVec,
vplainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
NSString *result = [[[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)bufferPtr
length:(NSUInteger)movedBytes] encoding:NSUTF8StringEncoding] autorelease];
return result;
}
@end
|
iPhone端的加密工具类中引入了“GTMBase64.h”,这是iOS平台的Base64编码工具类,见附件
好了,赶紧试一下吧,JAVA,Android和iPhone三个平台的加密不一致问题是不是解决了呢?以上为3DES加密,也可将其改为AES加密。其实,对此问题,还有一种更好的实现方式,那就是用C语言写一套加密程序,这样在iOS平台是可以直接使用C程序的,而在Java和Android端通过JNI去调用C语言编写的加密方法,这是不是就实现了3个平台调用同一套加密程序呢?