现象描述:' C+ `. _# p7 ~9 H! }& W
! `5 j0 h3 X# Twindows上加解密正常,linux上加密正常,解密时发生如下异常: ^) E- X( Y+ e* G9 H7 x
8 k4 ]6 k* j; l6 s- l% R Yjavax.crypto.BadPaddingException: Given final block not properly padded; V+ R: F% d( P" p z
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
7 k8 K& h2 S; `6 f# l. ` at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
; Q# g% y. F, x# J0 Y at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
6 j' L! `* x b6 l at javax.crypto.Cipher.doFinal(DashoA13*..)# _7 K' y6 g. Z' V6 k% i
at chb.test.crypto.AESUtils.crypt(AESUtils.java:386)
$ c1 X/ P6 h- s8 }; H+ `" M at chb.test.crypto.AESUtils.AesDecrypt(AESUtils.java:254)
% e' g, R: g, A: L) F4 V8 b at chb.test.crypto.AESUtils.main(AESUtils.java:40) 解决方法:3 X% E' j! J; V' s3 ?( z7 L2 h
1 k* p- `3 R4 Y {0 T经过检查之后,定位在生成KEY的方法上,如下:8 N# K! m s% z% ^9 i9 a
- public static SecretKey getKey (String strKey) {
: j3 I# N- l W - try {
) ?7 @" t. Y1 Q! ~ - KeyGenerator _generator = KeyGenerator.getInstance( "AES" );8 K* N( G( y7 Z2 u
- _generator.init(128, new SecureRandom(strKey.getBytes()));
0 D7 n& l& V3 @ - return _generator.generateKey();# b- a" p" I4 f: s4 v" ^
- } catch (Exception e) {' v+ N( h% E! E5 q* k/ C, D
- throw new RuntimeException( " 初始化密钥出现异常 " );
} a- G- q0 T4 X1 N( w1 Y - }
6 Z+ V' s6 ?" @4 e' v2 U - }
复制代码 修改到如下方式,问题解决:5 J# z7 o& L) @" f3 W: D
- public static SecretKey getKey(String strKey) {) ]$ z. b, z! J% |2 @
- try {
0 N" Q7 b+ d6 H% c - KeyGenerator _generator = KeyGenerator.getInstance( "AES" );
e5 A- t( J% [ - SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );" q: w- N2 S: J' m$ U% {* d
- secureRandom.setSeed(strKey.getBytes());
) T* j6 l$ l: u# G - _generator.init(128,secureRandom);
- ^+ o) X9 _9 r* G$ u; m* Q: u - return _generator.generateKey();
% k: j" B2 }$ i/ T( `- v - } catch (Exception e) {
! R) A# T1 n+ [, q6 S4 [ - throw new RuntimeException( " 初始化密钥出现异常 " );) s' _ [6 X$ q
- }0 X. X! J `' B. W1 M4 E
- }
复制代码 原因分析4 s; P1 V: H5 w9 g: O" `! N( J
SecureRandom 实现完全隨操作系统本身的內部狀態,除非調用方在調用 getInstance 方法之後又調用了 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。
" Y6 g* v/ k! C+ l
. q, s0 {5 m' z* x( r原因二:) k3 I d |1 ]7 b! j
' p1 n7 V* H2 v; w; B) v9 X
1、加密完byte[] 后,需要将加密了的byte[] 转换成base64保存,如:
( }0 C7 d4 B3 b- ?! e0 |BASE64Encoder base64encoder = new BASE64Encoder(); ) A) b* L, _" B
String encode=base64encoder.encode(bytes);
! V$ L; w$ t5 t$ w t- E; J
" V- a! L# s1 ?2 }* o4 H2、解密前,需要将加密后的字符串从base64转回来再解密,如: ; e2 c2 Y+ n5 ` S
BASE64Decoder base64decoder = new BASE64Decoder(); ; E0 A% e& q; J$ |
byte[] encodeByte = base64decoder.decodeBuffer(str);
7 C: k, R! M; U! C8 {1 C# w8 ~8 x# y" y( q
! ]# S# M, j, v完整例子:7 C4 k4 W7 M7 s W& s: Z2 n
- package com.travelsky.tdp.pkgStock.util;
0 C6 F6 M* U6 U v0 c. Q - 5 c7 `2 p4 ^; B9 i
- import java.io.IOException;
& N: X5 e ?5 ` - import java.io.UnsupportedEncodingException;7 W; ]# G9 f+ D& A# D8 N
- import java.security.InvalidKeyException;
8 Y+ J& x {- e7 e/ @4 U- g - import java.security.NoSuchAlgorithmException;
! g1 N( K* `0 K, i1 r) @* e) A- M - import java.security.SecureRandom;
3 o! e+ Z- e5 L4 V
% P8 M% O+ q( Y( [ S- import javax.crypto.BadPaddingException;
% M I& x. s6 h4 s( n+ D - import javax.crypto.Cipher;$ k/ S5 y3 c2 v- l4 b/ M
- import javax.crypto.IllegalBlockSizeException;
; r1 a7 g& @) i; h - import javax.crypto.KeyGenerator;3 o0 P) P& P9 B! ?$ H
- import javax.crypto.NoSuchPaddingException;- E. s( O4 L' y/ \' i5 |
- import javax.crypto.SecretKey;, W* S6 ^% ?; D$ X. _. F
- import javax.crypto.spec.SecretKeySpec;
. T* c; I, B5 o q2 H& M - $ w- |* c! h% o8 z4 a
- import sun.misc.BASE64Decoder;( ?7 H+ L/ a) j- z
- import sun.misc.BASE64Encoder;
% a/ p& [# U/ }+ n! c9 L - % J U+ V% c5 m* v3 |
- public class SecurityAES {
+ T7 ~& R, n; \ - private final static String encoding = "UTF-8"; # e( h7 z; M6 l$ y9 e
- /**2 F6 k! ?! m: q/ ?) n
- * AES加密' O3 I; b- I: U' L5 ~7 c
- * 0 W% y- w9 Z% V
- * @param content I& y+ x( i1 e$ [# K& E" D
- * @param password9 |) e: T0 f+ a8 W
- * @return8 c' t2 Y H2 y6 Y; I) h8 s
- */
1 c9 k5 G: g1 d& C8 { - public static String encryptAES(String content, String password) {
% G; ^) b5 }5 @( G- @ - byte[] encryptResult = encrypt(content, password);
% k2 B& l3 t' H# v2 ]0 i - String encryptResultStr = parseByte2HexStr(encryptResult);
) c0 A9 @7 W9 A! M1 I - // BASE64位加密( h! `& V+ ^! O- C9 p
- encryptResultStr = ebotongEncrypto(encryptResultStr);
: Y3 j% {3 c: |! G' } - return encryptResultStr;! x8 c6 R. Z7 b* x
- }
4 Y5 h% i; A) a- }9 m. e' a& c - @$ Q5 Z; [ J+ l+ u% d
- /**% U+ }: n! p P0 j- Z
- * AES解密
7 u! }6 [ C. ?* z; C2 Q# E& \: f - *
9 e( C6 k- O& _ N - * @param encryptResultStr
3 s" p% [8 ^% O0 ^0 y$ X* w- \ - * @param password
$ {( N/ N% E) [+ |5 H8 n) R# S+ |" _1 \: | - * @return T& O( n* f' C% k
- */" q2 R# M4 j7 [7 b4 n9 j
- public static String decrypt(String encryptResultStr, String password) {7 x5 F& H6 a" _) N y6 o
- // BASE64位解密
5 C3 n+ B" v h! p* C, q W - String decrpt = ebotongDecrypto(encryptResultStr);: k$ }2 f- z' V f: `) m/ W5 U
- byte[] decryptFrom = parseHexStr2Byte(decrpt);: k) E) @9 ~- q( k. I) s$ ?+ t' d2 ^
- byte[] decryptResult = decrypt(decryptFrom, password);% k' ?" C& Z1 V# I% V$ _% s! z6 P
- return new String(decryptResult);
1 ~) G3 @! `, J g - }/ x/ h# A+ }% d; c( c7 |2 q
- ) \! ?9 h& W) b! b* `6 o, ?
- /**
7 C0 Y, P6 f2 w# X0 w ?/ ~ - * 加密字符串+ S1 D8 m4 {7 B
- */
, ^: v3 g4 U1 V4 q( V" ^6 L - public static String ebotongEncrypto(String str) {. L0 |& ~$ Z# f6 _& K
- BASE64Encoder base64encoder = new BASE64Encoder();# e6 p! u/ Y/ y& G m; s* P
- String result = str;5 y! c% p7 K2 z4 [) |* L" z
- if (str != null && str.length() > 0) {
R1 y: @9 F5 w6 B* n - try {
, L- J2 Z2 u/ \6 v5 [6 T& [ - byte[] encodeByte = str.getBytes(encoding);: \( d9 A/ ?+ d$ `7 N- [
- result = base64encoder.encode(encodeByte);
/ D& G2 V4 R0 L5 D - } catch (Exception e) {
7 d, b$ M i5 O+ X6 U0 } }2 A* [" s - e.printStackTrace();
; D/ X3 b1 u; C - }
; h4 D- N/ k& l* g# y! [- {% b. C - }3 J0 Z) r0 j p; t2 x& k
- //base64加密超过一定长度会自动换行 需要去除换行符
. k+ f6 `" K- ^1 x - return result.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");6 c: _( e2 i, \0 m: Z9 n
- }. t* M }4 W/ a, x( p& G8 O
- 8 r/ N" W3 y9 r; I8 c* ?9 _
- /**+ {1 H! l0 ^: [) L# r# p0 @: `
- * 解密字符串
4 G: [$ n8 W7 A3 l- k. Y0 [$ l- G5 \ - */+ m5 l: _8 x# I2 ]4 y4 ~
- public static String ebotongDecrypto(String str) {
9 W/ K* W+ S4 Z' F: K) Q - BASE64Decoder base64decoder = new BASE64Decoder();' U& J) }) ~" d# {' d* b
- try {
3 ]6 H; E. X4 l - byte[] encodeByte = base64decoder.decodeBuffer(str);) b5 |3 `$ p3 o' U, n- a
- return new String(encodeByte);
, T1 f* h: D' q& ] - } catch (IOException e) { s5 M& B1 h6 l9 d& _* s
- e.printStackTrace();
, U3 x1 z7 v4 \' {$ H: ]5 @3 D& I - return str;, z9 {8 y& C$ e- a( I1 w
- }
1 V# x; E; d+ [2 r - }
1 V; F8 o, _5 z! J; _ - /**
- e' m* ~, W$ m; v& T$ _; ? - * 加密 2 E w; f+ Y+ [) ?/ F
- *
* e, Y" b$ j# \3 i3 r - * @param content 需要加密的内容 ! p4 Z3 u( g* S/ r) v" K/ m
- * @param password 加密密码
& h, \8 i- i+ z$ U | - * @return ( v+ M+ F% K( A% N0 m) v6 r
- */ " q- ]' t K' @" S+ k
- private static byte[] encrypt(String content, String password) {
" L% J5 u$ S4 a$ a! s' E - try { 5 I6 Z' R+ Q* z
- KeyGenerator kgen = KeyGenerator.getInstance("AES"); ( y- |0 v+ D5 f& V; O
- //防止linux下 随机生成key; g8 F/ e4 [( o! \% c1 w5 X/ D
- SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" ); 3 c5 g2 w4 i8 n O
- secureRandom.setSeed(password.getBytes());
2 u7 {# d& }* y F. T* v0 K4 G - kgen.init(128, secureRandom);
/ m* L. m5 `& g- q- [ ^8 p P+ a; ?9 L - //kgen.init(128, new SecureRandom(password.getBytes()));
6 J$ f" n6 {1 W - SecretKey secretKey = kgen.generateKey();
% l0 S7 f7 U& q5 f - byte[] enCodeFormat = secretKey.getEncoded(); ; H$ J) s+ w; D- ]
- SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 5 I* {3 b! Y$ ?
- Cipher cipher = Cipher.getInstance("AES");// 创建密码器
+ G( V2 H, {( I: w G; H - byte[] byteContent = content.getBytes("utf-8"); : r( T( R- A* O$ Y, L2 s: w
- cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 . H/ t( n) B! D. @6 v) E2 I
- byte[] result = cipher.doFinal(byteContent);
0 h% Z; P% V+ t, \8 E$ e - return result; // 加密 % S0 [5 m; h5 m7 x7 d
- } catch (NoSuchAlgorithmException e) { 0 _' H/ ?1 `9 a( i
- e.printStackTrace();
/ ]# B+ j0 R% {+ X8 l! g - } catch (NoSuchPaddingException e) { . B+ K L: `, s+ m* z1 |
- e.printStackTrace(); & G" j$ f5 s$ q
- } catch (InvalidKeyException e) {
: `6 F( P, l" z1 U/ O4 X - e.printStackTrace(); $ C0 C9 Q( Y e5 U
- } catch (UnsupportedEncodingException e) {
% t- k8 k0 ]/ e6 d; X4 Y& _ - e.printStackTrace(); & K3 F; d" }* t# W. Y
- } catch (IllegalBlockSizeException e) {
8 d; J: T ?, f; s/ y/ d0 P - e.printStackTrace(); 9 m) I a# m1 K/ J$ E& ]
- } catch (BadPaddingException e) {
/ ?# W7 `) r# }2 K2 ] - e.printStackTrace(); 0 C! s" ^8 Z& s7 k x" s' `7 V$ f1 X
- }
' n$ P2 i8 T p/ { M) p - return null; 6 F1 e/ I) l! d
- } ( y- t) t: k5 z* s
- 4 H/ F$ L2 |) k. Y' Z
- f: \1 p' |1 m) \$ N- /**解密
- }, `2 C; u3 f B( \: a6 ]1 N4 x6 ] - * @param content 待解密内容 3 S+ U8 q3 V+ H. X$ O9 v5 J* W
- * @param password 解密密钥
8 x0 L; T2 W1 u7 w Z - * @return ' u6 `" _, j5 J9 J
- */
. y" s+ M% \' W% |& Y1 E5 d - private static byte[] decrypt(byte[] content, String password) {
. I( e% F6 D- n% s7 o {) z - try {
$ S4 D) R3 z/ t! _" w; u/ C - KeyGenerator kgen = KeyGenerator.getInstance("AES"); : @ w4 f3 l% o5 [: K( A
- //防止linux下 随机生成key
: ?4 m1 [' n/ v# K4 y9 h3 i( l - SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
" k& I: f+ q5 C# i& J9 h - secureRandom.setSeed(password.getBytes()); : A# A. V& ?$ N" L; C( }
- kgen.init(128, secureRandom);8 @" I$ y* j. ^: T
- //kgen.init(128, new SecureRandom(password.getBytes())); / M( _! @! ^$ | Q a! S
- SecretKey secretKey = kgen.generateKey(); ]2 h H: \) o& n; m5 Q( a7 q
- byte[] enCodeFormat = secretKey.getEncoded(); 5 j, c n2 x" A3 l' P
- SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); " q `! O% K0 {+ ?8 U- q
- Cipher cipher = Cipher.getInstance("AES");// 创建密码器
$ T+ U! Z. r: c) ^ - cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
4 o5 @; W0 J) S - byte[] result = cipher.doFinal(content);
) h0 S8 |! c$ \" F3 a" i1 P - return result; // 加密 9 V0 k5 `2 P2 j% i$ [1 F
- } catch (NoSuchAlgorithmException e) {
* d% B% C/ @* u5 N3 l. t4 u0 ~* O - e.printStackTrace(); 7 S5 D% B6 ?( Z' o+ n
- } catch (NoSuchPaddingException e) {
5 O! \1 D0 [+ ]% r - e.printStackTrace();
4 Z5 K1 V- d5 J* A% j. `9 ?3 X - } catch (InvalidKeyException e) { % X% h% N! ~; M5 {
- e.printStackTrace(); 6 i0 `7 v0 Z K0 |& c
- } catch (IllegalBlockSizeException e) { 0 d, r, l3 W B" W
- e.printStackTrace();
" I$ L! d: D- ?& Q - } catch (BadPaddingException e) {
+ F* h9 W8 ~9 h0 Y - e.printStackTrace();
1 G% I" Q4 U" E7 m, J - }
; S: C! a- \$ i k9 b - return null;
6 z+ b* @) @" ?# X8 t7 y7 F5 r) ` - } . F! `* f( F [/ L6 E
- 1 F2 m3 C# a# u) g
- /**将二进制转换成16进制
2 I* V$ H8 t% T* {2 b; K - * @param buf 6 K3 e) F( R, l
- * @return ) N! Q, i' q' k% @2 f7 _* |
- */
& u" T! b0 k9 v8 K - public static String parseByte2HexStr(byte buf[]) {
& C5 Y; f( O8 m+ _) h! @) \% p - StringBuffer sb = new StringBuffer();
' e; v5 \! W5 R4 G5 Z9 x - for (int i = 0; i < buf.length; i++) {
) @$ h- C& j+ X+ \ g! }% b+ r - String hex = Integer.toHexString(buf[i] & 0xFF); , M% M P$ ~4 P b% e' l
- if (hex.length() == 1) { 1 L; V- R& _ L; Q4 r3 C& u
- hex = '0' + hex;
& I: J3 L0 @* X" a+ y5 w9 X - }
+ I- \" b: q0 v2 a! w: U. _ - sb.append(hex.toUpperCase()); # K- |/ Z0 {/ S8 r! n! P
- } " q# V4 X9 Y1 a' \/ y, f6 W
- return sb.toString();
5 H. j2 ~) j6 b+ L4 q' P) K; U8 o - }
" G$ L( F- k- X8 m9 ~ - ; b& F6 g' X# G( ?/ b
+ E9 D$ d$ u" a, \- /**将16进制转换为二进制
4 f; n) D0 ?3 ?/ f, H - * @param hexStr
, X% o/ B: R0 R0 h$ b, f6 X6 ]% h - * @return
# s' y( o/ S6 J( w% U - */
" M( Y( U/ z5 S. N) j% P% M7 p - public static byte[] parseHexStr2Byte(String hexStr) { 0 ~0 ~+ v$ i# S# w8 T5 d+ X
- if (hexStr.length() < 1)
0 z$ J, O( ]( ?* W7 d0 V - return null; 0 y8 I& i& X7 Q; j3 G* G
- byte[] result = new byte[hexStr.length()/2];
) |8 T6 ?; M# J& Z - for (int i = 0;i< hexStr.length()/2; i++) { " U6 k& o$ y0 s, @ \9 z- c/ S
- int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); ) s1 j: m* x: h: l4 W
- int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
F" W! [+ x2 x$ h - result[i] = (byte) (high * 16 + low);
) s% }0 `+ g; A: W0 K! A9 _* r - }
: m* R& @. j: {5 M - return result;
/ s' M! l8 C: j$ _7 i - } $ v8 |' s2 M- V6 @
8 E/ S' F. _; f2 a+ u4 @1 _9 P
/ v) _& m9 }, ^4 ?$ F-
7 y; {- M- _" B1 L. c; M% E - }+ F3 ~) a0 S- L0 y( |. f
复制代码 : d9 X( W; E/ }3 p2 L$ d" |% ], @ q0 P
以上在linux测试ok 原文转自:http://konglx.iteye.com/blog/9540854 [: o# Z% C' h Q6 E
# F, O, X1 H) B y5 K. z
$ a" f: l# Y. O4 J( G$ w4 c0 p5 J7 L2 w$ u, E' ]: W
|