网上的demo一搜一大堆,但是,基本上都是一知半解(包括我)。为什么呢?我在尝试分别在两个平台加密的时候,竟然发现Android DES 加密和java DES加密的程序不能互通。就是加密的结果不一样,更不要说Android平台的加密输入作为java DES的解密输出了。这样的话,客户端和服务器端就不能进行通信了。 我网上之前也发帖子问了不少人,但是回答都不满意。
今天部门的另外一个同事跟我说了一下,才解决了这个不能互通的问题。
调用DES加密算法包最精要的就是下面两句话:
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
CBC是工作模式,DES一共有电子密码本模式( ECB )、加密分组链接模式( CBC )、加密反馈模式( CFB )和输出反馈模式( OFB )四种模式,
PKCS5Padding是填充模式,还有其它的填充模式:
然后,cipher.init()一共有三个参数:Cipher.ENCRYPT_MODE, key, zeroIv,zeroIv就是初始化向量,一个8为字符数组。
工作模式、填充模式、初始化向量这三种因素一个都不能少。否则,如果你不指定的话,那么就要程序就要调用默认实现。问题就来了,这就与平台有关了。难怪网上一搜"DES加密结果不一致“,出现n多网页结果。(之前我并没有指定IV,被折磨了2周)
源程序如下(从java平台到android平台,我根本没有更改一行代码):
另外,一般情况下,加密后的结果都会用base64编码进行传输。
java平台:
主程序
01
public
class
testDES {
07
public
static
void
main(String[] args)
throws
Exception {
09
String key =
"12345678"
;
10
String text =
"12345678"
;
11
String result1 = DES.encryptDES(text,key);
12
String result2 = DES.decryptDES(result1, key);
13
System.out.println(result1);
14
System.out.println(result2);
用到的DES加密类
01
import
javax.crypto.Cipher;
02
import
javax.crypto.spec.IvParameterSpec;
03
import
javax.crypto.spec.SecretKeySpec;
06
private
static
byte
[] iv = {
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
};
07
public
static
String encryptDES(String encryptString, String encryptKey)
throws
Exception {
09
IvParameterSpec zeroIv =
new
IvParameterSpec(iv);
10
SecretKeySpec key =
new
SecretKeySpec(encryptKey.getBytes(),
"DES"
);
11
Cipher cipher = Cipher.getInstance(
"DES/CBC/PKCS5Padding"
);
12
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
13
byte
[] encryptedData = cipher.doFinal(encryptString.getBytes());
15
return
Base64.encode(encryptedData);
17
public
static
String decryptDES(String decryptString, String decryptKey)
throws
Exception {
18
byte
[] byteMi =
new
Base64().decode(decryptString);
19
IvParameterSpec zeroIv =
new
IvParameterSpec(iv);
21
SecretKeySpec key =
new
SecretKeySpec(decryptKey.getBytes(),
"DES"
);
22
Cipher cipher = Cipher.getInstance(
"DES/CBC/PKCS5Padding"
);
23
cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
24
byte
decryptedData[] = cipher.doFinal(byteMi);
26
return
new
String(decryptedData);
用到的BASE64工具类:
001
import
java.io.ByteArrayOutputStream;
002
import
java.io.IOException;
003
import
java.io.OutputStream;
007
public
class
Base64 {
008
private
static
final
char
[] legalChars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
.toCharArray();
014
public
static
String encode(
byte
[] data) {
016
int
len = data.length;
017
StringBuffer buf =
new
StringBuffer(data.length *
3
/
2
);
024
int
d = ((((
int
) data[i]) &
0x0ff
) <<
16
)
025
| ((((
int
) data[i +
1
]) &
0x0ff
) <<
8
)
026
| (((
int
) data[i +
2
]) &
0x0ff
);
028
buf.append(legalChars[(d >>
18
) &
63
]);
029
buf.append(legalChars[(d >>
12
) &
63
]);
030
buf.append(legalChars[(d >>
6
) &
63
]);
031
buf.append(legalChars[d &
63
]);
041
if
(i == start + len -
2
) {
042
int
d = ((((
int
) data[i]) &
0x0ff
) <<
16
)
043
| ((((
int
) data[i +
1
]) &
255
) <<
8
);
045
buf.append(legalChars[(d >>
18
) &
63
]);
046
buf.append(legalChars[(d >>
12
) &
63
]);
047
buf.append(legalChars[(d >>
6
) &
63
]);
049
}
else
if
(i == start + len -
1
) {
050
int
d = (((
int
) data[i]) &
0x0ff
) <<
16
;
052
buf.append(legalChars[(d >>
18
) &
63
]);
053
buf.append(legalChars[(d >>
12
) &
63
]);
057
return
buf.toString();
060
private
static
int
decode(
char
c) {
061
if
(c >=
'A'
&& c <=
'Z'
)
062
return
((
int
) c) -
65
;
063
else
if
(c >=
'a'
&& c <=
'z'
)
064
return
((
int
) c) -
97
+
26
;
065
else
if
(c >=
'0'
&& c <=
'9'
)
066
return
((
int
) c) -
48
+
26
+
26
;
076
throw
new
RuntimeException(
"unexpected code: "
+ c);
081
* Decodes the given Base64 encoded String to a new byte array. The byte
082
* array holding the decoded data is returned.
085
public
static
byte
[] decode(String s) {
087
ByteArrayOutputStream bos =
new
ByteArrayOutputStream();
090
}
catch
(IOException e) {
091
throw
new
RuntimeException();
093
byte
[] decodedBytes = bos.toByteArray();
097
}
catch
(IOException ex) {
098
System.err.println(
"Error while decoding BASE64: "
+ ex.toString());
103
private
static
void
decode(String s, OutputStream os)
throws
IOException {
106
int
len = s.length();
109
while
(i < len && s.charAt(i) <=
' '
)
115
int
tri = (decode(s.charAt(i)) <<
18
)
116
+ (decode(s.charAt(i +
1
)) <<
12
)
117
+ (decode(s.charAt(i +
2
)) <<
6
)
118
+ (decode(s.charAt(i +
3
)));
120
os.write((tri >>
16
) &
255
);
121
if
(s.charAt(i +
2
) ==
'='
)
123
os.write((tri >>
8
) &
255
);
124
if
(s.charAt(i +
3
) ==
'='
)
adnroid平台的主函数:
01
public
class
main
extends
Activity {
02
/** Called when the activity is first created. */
04
public
void
onCreate(Bundle savedInstanceState) {
05
super
.onCreate(savedInstanceState);
06
setContentView(R.layout.main);
08
String key =
"12345678"
;
09
String text =
"12345678"
;
13
String result1 = DES.encryptDES(text,key);
14
String result2 = DES.decryptDES(result1, key);
15
Log.i(
"DES encode text is "
, result1);
16
Log.i(
"DES encode text is "
, result2);
17
}
catch
(Exception e) {
通过查看log日志就可以看到结果。
两个平台的结果是一样的,都是:
加密结果:X2p9Uo45Tzk6Ntu6W7Ev+Q== 解密结果:12345678