现象描述:1 _; ]0 c+ Q$ l2 u7 A
4 E/ I! x' L+ t5 _# R( m0 l
windows上加解密正常,linux上加密正常,解密时发生如下异常:
2 M7 M5 u1 [9 t& d, i. D7 k% A. B5 W: C/ \: P4 m4 w
javax.crypto.BadPaddingException: Given final block not properly padded2 Y& L4 L6 X6 U2 ]. a% [
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)( ?$ J# z, K; D+ {. |' ]7 P4 ] |
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)5 g6 i! U/ X" S. |/ B/ y
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
/ n- i. Q* V5 t Z7 W2 k5 f at javax.crypto.Cipher.doFinal(DashoA13*..)
* ]( K1 g. \; C at chb.test.crypto.AESUtils.crypt(AESUtils.java:386)& `! Q2 p$ ?. i3 ^: v3 p4 s S
at chb.test.crypto.AESUtils.AesDecrypt(AESUtils.java:254)
8 w z( ]# u: z8 m# ]1 L- F at chb.test.crypto.AESUtils.main(AESUtils.java:40) 解决方法:
o/ E5 C0 h1 K( R7 j" C7 m( o' y
B9 J( ^2 N: I: K经过检查之后,定位在生成KEY的方法上,如下:; _( F( w# y; J
- public static SecretKey getKey (String strKey) {
0 E) M# J. d1 a. |2 S6 x - try {
8 Y7 z- B9 K* ^) f - KeyGenerator _generator = KeyGenerator.getInstance( "AES" );: o; U7 N0 j) w# g& K
- _generator.init(128, new SecureRandom(strKey.getBytes()));' A# |& d1 Z7 L7 [8 q. F( G
- return _generator.generateKey();
- K8 ?% m4 B- J - } catch (Exception e) {
, P! G" [" y, h. x - throw new RuntimeException( " 初始化密钥出现异常 " );1 D9 g) V) ]0 J D( m2 ]+ k
- }% |% h- c2 p% L+ n. t% l
- }
复制代码 修改到如下方式,问题解决:* O. z3 U" Q- P% h0 E' Q* e
- public static SecretKey getKey(String strKey) {# c( L3 f' Y) C0 p* K; z
- try { ) T c2 E# I' w& I" N
- KeyGenerator _generator = KeyGenerator.getInstance( "AES" );
( A! J! g, h% j5 l - SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );6 W. ~. s0 w( ]5 E; m7 l$ s! L
- secureRandom.setSeed(strKey.getBytes());) T2 {2 r* h6 S" R6 r3 u% R) e
- _generator.init(128,secureRandom);3 V' P* J9 `* }3 U7 }
- return _generator.generateKey(); J3 F% z: d% z) ?
- } catch (Exception e) {3 A' V$ E. }: L6 a/ l1 b9 d
- throw new RuntimeException( " 初始化密钥出现异常 " );8 l, E; y9 h1 i1 N; u' N" E
- }- B9 S1 X. {7 Y
- }
复制代码 原因分析: M% z' l+ E- G. j1 {: Q
SecureRandom 实现完全隨操作系统本身的內部狀態,除非調用方在調用 getInstance 方法之後又調用了 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。3 n6 [6 E5 J3 n0 n1 O
5 w# m6 B* W) R5 f4 I. L
原因二:- w* Q9 t: Y: L- [0 F
4 C7 v; M) g: T3 Z- }) d1、加密完byte[] 后,需要将加密了的byte[] 转换成base64保存,如:
0 g" X$ a4 r" \: @( Z3 ^+ }! BBASE64Encoder base64encoder = new BASE64Encoder();
; l8 |1 V5 k6 C$ XString encode=base64encoder.encode(bytes);
. Y+ w, E, s! H. o7 t0 I b/ p- F; D( P$ C
2、解密前,需要将加密后的字符串从base64转回来再解密,如: + S, c1 }9 b. R
BASE64Decoder base64decoder = new BASE64Decoder();
, s4 [8 m& |: k% bbyte[] encodeByte = base64decoder.decodeBuffer(str);
% X L5 W+ p$ R, i( M/ W4 e7 ~1 A. O3 |9 L( g
: u5 V" L! \5 x完整例子:; J! x+ x5 `3 G2 r3 v. X7 J
- package com.travelsky.tdp.pkgStock.util;
$ `. k$ |. ? w# H( H - 2 C7 `: C6 I9 E" N$ b2 e
- import java.io.IOException;
/ s5 |; C+ O' G" E9 c - import java.io.UnsupportedEncodingException;
7 X) t0 p' Y b+ }$ Y4 w - import java.security.InvalidKeyException;
, u0 r p& j" V, E( E - import java.security.NoSuchAlgorithmException;' R/ P. S( g) {# k
- import java.security.SecureRandom;; @+ k$ g8 M" [1 W
- & t) Y- E- K9 P
- import javax.crypto.BadPaddingException;1 \- q- l, |! W& e6 @6 m
- import javax.crypto.Cipher;
+ E" t% ?5 B1 f" O - import javax.crypto.IllegalBlockSizeException;9 I* |5 o' \0 r3 n4 f. \( ^( j6 n' u
- import javax.crypto.KeyGenerator;
$ U, }$ v6 c! J% a6 l9 l - import javax.crypto.NoSuchPaddingException;
4 o: J. ]; H; I' i7 w! v - import javax.crypto.SecretKey;4 w, k+ E* N; t' O" X- {7 @) r7 W2 V
- import javax.crypto.spec.SecretKeySpec;
1 V- v$ x/ Z/ ^& r - - L! G+ X5 K4 V0 ^
- import sun.misc.BASE64Decoder;4 T0 z' m6 Z! v! ]
- import sun.misc.BASE64Encoder;3 N& i3 P( @8 n3 h) _
+ f4 t; L; e% k& v8 z* z- public class SecurityAES {/ m( S9 {5 \/ Y3 n. f
- private final static String encoding = "UTF-8"; # n' K0 g+ w% \# s; b
- /**; o/ F; @0 T- p* b& _# C
- * AES加密
: B7 M; K0 W7 c# P- @. p - * ; T# T! i7 o& H- ^- B
- * @param content& F4 P I( @4 N, g' L
- * @param password
9 ? b d& v7 f8 v# [% P C1 F - * @return
& A. F/ c/ a& q9 Q* ?; N - */
/ X! \# l8 i: `9 _3 Z# Y% t - public static String encryptAES(String content, String password) {7 `, _7 h- C" \+ ~( B( X! y! S
- byte[] encryptResult = encrypt(content, password);
1 d. v8 h" i& r - String encryptResultStr = parseByte2HexStr(encryptResult);
/ `' U# l* [2 M9 B - // BASE64位加密 w3 }2 ?$ v9 S4 d8 w7 B
- encryptResultStr = ebotongEncrypto(encryptResultStr);; _1 I! R+ d9 s! n) A+ P
- return encryptResultStr;
( @7 N. @0 {8 L) L- ]+ { - }
0 o. V K6 U* B, I' u- D8 z% S$ c( x - ( a W. j g8 i* {. i3 h0 T
- /**1 N$ k4 q6 S" Z
- * AES解密
; ?: q& s0 p' q9 J0 E - *
+ b5 D6 |& l! V0 G% b" q - * @param encryptResultStr
7 o Q1 w9 U4 t, `( |4 @ - * @param password2 t5 x+ R! D! {' Y/ [4 P5 s
- * @return
/ T8 _' s- Q/ ~4 G% v/ T - */
* |: m! R5 c) _; q( v - public static String decrypt(String encryptResultStr, String password) {- o+ p" ~4 W Y) ] f2 s
- // BASE64位解密# U+ Q& X5 F/ I, D& ]
- String decrpt = ebotongDecrypto(encryptResultStr);
8 g* e# ~3 u, O. S) r - byte[] decryptFrom = parseHexStr2Byte(decrpt);
: v. Y% r' }' d8 H3 |/ j; v) Q" c - byte[] decryptResult = decrypt(decryptFrom, password);
& T4 w' M0 c+ K! v. G - return new String(decryptResult);
) q3 Q, _$ v5 W. Q" Y& q - }
/ E; [, _+ W1 E) X
$ V7 a. k: @3 v! ?9 g& N' Y- /**6 _+ [5 l1 j) Y" o
- * 加密字符串
+ k h# z# G4 E' F& ^" M - */
! x# A1 o- @ i% X' u/ V# F( V - public static String ebotongEncrypto(String str) {
* @: i# Y2 R* E; J0 A8 p9 [ - BASE64Encoder base64encoder = new BASE64Encoder();0 z4 W& s0 `- ]6 \4 S" @- j9 d
- String result = str;# f* _* I7 d3 ^" c( V( s/ j9 f
- if (str != null && str.length() > 0) {5 E' z. h* M4 |) |3 r/ k! d# M1 n
- try {
) q8 x% q$ A: ^. E* X+ `! O - byte[] encodeByte = str.getBytes(encoding);
+ H* X# W- t0 r2 L* e, E( o* Z7 L - result = base64encoder.encode(encodeByte);
7 g1 ^5 N% w( A6 T! @ - } catch (Exception e) {) v; r V% `6 o' I2 j1 @6 Z% X
- e.printStackTrace();
. {% m3 }1 l; X- ^* H - }
( {# d6 \/ X; V' |& [ - }
8 X* E+ E" D. K% C - //base64加密超过一定长度会自动换行 需要去除换行符
7 f3 W9 m2 @9 ?) _, e& P - return result.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");
- ~! {6 }- [2 _) U- x) F - }
: ?" A7 U* X& _6 a# j3 b
) ^ \6 d: H2 m1 y" P0 Z2 t- /**
/ h. B( l6 r; d! g - * 解密字符串
p' z0 P. p1 I9 z! `2 ~ - */) o* T" E& g$ Z
- public static String ebotongDecrypto(String str) { V( Q+ \) q* @% D$ B! I7 j4 B
- BASE64Decoder base64decoder = new BASE64Decoder();' a3 x5 F; o' s
- try {
( L! H4 r( u. r# A - byte[] encodeByte = base64decoder.decodeBuffer(str);7 r, t- d; K1 m' b% @+ ]1 }) @
- return new String(encodeByte);. ?9 `' P& P1 m9 t, u5 X9 |
- } catch (IOException e) {& [6 [: n& U4 J& ~1 r7 _
- e.printStackTrace();4 \ K H& |: i( `
- return str;
/ Y1 Z) K* V+ j" b- T. O. e - }+ \1 h- z7 j& s/ [) W% |
- }
1 }' N! B4 `! B& ? - /**
8 u1 E( r4 ]/ ?2 `' q0 S# Z - * 加密
3 e" f- V( B3 g- d1 S* y! o3 c - *
6 t3 Y$ J" [5 ]$ Y, B - * @param content 需要加密的内容
4 M& B. E) Z7 @4 \9 U' v - * @param password 加密密码
& {% y; M& J8 y - * @return Q0 C( r0 [0 N4 Z# ?) W$ C4 `
- */ . k' y/ D: z9 T, @" w+ h
- private static byte[] encrypt(String content, String password) { 7 Q5 b. P2 v' t& t
- try { 0 P L% \( h ~& p3 d% w+ s9 r
- KeyGenerator kgen = KeyGenerator.getInstance("AES");
9 B* r; T6 ~8 c/ } l - //防止linux下 随机生成key/ I1 h) C- y0 a! K% e0 y
- SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
9 O7 W/ v: _- g - secureRandom.setSeed(password.getBytes());
9 g! k7 H3 o7 C) P - kgen.init(128, secureRandom);
7 O, b- q9 B* O- b# \$ c - //kgen.init(128, new SecureRandom(password.getBytes()));
4 a& ?' `% m7 _8 y8 B7 f - SecretKey secretKey = kgen.generateKey();
# z+ O9 \/ k" c$ l - byte[] enCodeFormat = secretKey.getEncoded();
: j( x) ]" m$ E4 a - SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
4 n" P0 J. \6 b8 [0 _4 `# _2 B - Cipher cipher = Cipher.getInstance("AES");// 创建密码器 % o; @* V$ k( e
- byte[] byteContent = content.getBytes("utf-8"); + R. _1 u+ p. e4 M# ^6 R; D' a
- cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
T; A# d `8 m! H& x# [. r - byte[] result = cipher.doFinal(byteContent);
7 e3 g3 w8 w/ F - return result; // 加密 ( F8 M: [& p" M# x+ {' B& s
- } catch (NoSuchAlgorithmException e) { 2 k% S- X: C& L' D" w
- e.printStackTrace(); ! ]# a5 w2 n8 ]% k( W
- } catch (NoSuchPaddingException e) { & `$ I0 }# z" T. H; ^
- e.printStackTrace(); 2 v, b: H1 d$ m4 }; w
- } catch (InvalidKeyException e) {
; a7 O9 m0 F1 R2 v - e.printStackTrace();
+ a: e4 I9 {# {/ _. O! o - } catch (UnsupportedEncodingException e) { 4 h+ r) x$ V: Z0 l4 ]9 W' T% b" x' g
- e.printStackTrace(); 4 s% z9 p7 v. y. a' ], g0 G; H
- } catch (IllegalBlockSizeException e) {
6 c1 o4 S3 T+ w: G6 ]3 ^! j- F - e.printStackTrace();
) t( G5 |9 C: L; g0 e - } catch (BadPaddingException e) {
( m$ W$ R9 K5 E# F - e.printStackTrace();
" c4 D6 t2 |) n - }
2 ~- {% [0 e+ i$ W" f/ l0 b. l" I - return null;
2 V5 A& P, G- o9 @9 e - } , H5 H* c" L: D7 J6 c0 X: c
5 v8 N9 U7 X% O7 {0 t0 s$ v
7 _/ o* W' L4 f; m ?+ J- /**解密 " \3 ]" h! z( {0 j K
- * @param content 待解密内容 ^$ t" U. r9 U* Y
- * @param password 解密密钥 6 R7 o; _# n# S0 G& B$ i C" T
- * @return 4 s' Y! Z. {' t8 q7 R3 K% n
- */ 6 ] ?1 n& ]/ R/ `1 x" Z6 P
- private static byte[] decrypt(byte[] content, String password) {
* ^2 {+ _1 s) `2 v/ B( i - try {
8 u" S1 A$ N8 y( } - KeyGenerator kgen = KeyGenerator.getInstance("AES"); # h. o( j2 W$ J1 _2 B
- //防止linux下 随机生成key8 o! }8 ?% V/ d1 V( I" A9 S+ |
- SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
' Z6 B x5 E7 e2 |) k1 L - secureRandom.setSeed(password.getBytes());
% J- {. `' @6 f' f. {, Y4 j - kgen.init(128, secureRandom);' M7 l8 O4 o- X& b5 U7 H
- //kgen.init(128, new SecureRandom(password.getBytes())); ; M1 {* _ W" [7 n9 l5 k4 l \3 F
- SecretKey secretKey = kgen.generateKey();
! Y' A- S. Y3 E5 Z, v0 f3 U( j. \+ H - byte[] enCodeFormat = secretKey.getEncoded();
; T1 W; Y/ o v: ]& b) i - SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); * H% S1 @! k" I7 j! H. @6 G6 J
- Cipher cipher = Cipher.getInstance("AES");// 创建密码器
( l H' l. z$ J" k, s/ }/ r - cipher.init(Cipher.DECRYPT_MODE, key);// 初始化 ) `' b( R; S# e j, ]7 d! o: X
- byte[] result = cipher.doFinal(content); # i. y& D6 P- {/ x# T7 }$ p
- return result; // 加密
0 |- l1 a& w1 _0 o0 I - } catch (NoSuchAlgorithmException e) { ; D/ x7 j3 v" b g- Y( ?
- e.printStackTrace(); . e u# g" P, f" N. _
- } catch (NoSuchPaddingException e) { 9 Q3 N, ]% [' \/ g
- e.printStackTrace(); v$ C; l# w# M3 u3 W* _
- } catch (InvalidKeyException e) {
; T/ Z: j% R! S' R - e.printStackTrace();
& [* [; _3 q% _* U" G8 |. w - } catch (IllegalBlockSizeException e) {
4 t; G6 s# m1 c - e.printStackTrace();
8 L* W: u$ a. p2 S3 t! j - } catch (BadPaddingException e) {
6 s. ]0 n/ x- O- v' y; B" r0 d+ U$ n9 E - e.printStackTrace(); ! p& l, T! ~( V% W7 U$ W/ ^
- }
8 C: g. D8 X8 I" a - return null;
w! I Q$ |2 x - }
7 R. L. T8 Q3 @4 D% i - ; a0 W3 g" \2 ~' R
- /**将二进制转换成16进制 7 U% i1 M9 r. P: R0 J9 F
- * @param buf
8 Q% M7 I4 f3 k: d- h - * @return
# l" ]0 S7 N- W( l - */ : L* @2 C) ^2 r0 s- f8 ^* I- u: `
- public static String parseByte2HexStr(byte buf[]) { 6 V0 E6 y- _7 k9 W# ^) B; E! y
- StringBuffer sb = new StringBuffer(); 5 g0 \6 ~& Z# d& z
- for (int i = 0; i < buf.length; i++) { $ o3 f/ @( n5 ^ R
- String hex = Integer.toHexString(buf[i] & 0xFF);
+ \: x+ B. R/ b: n9 B - if (hex.length() == 1) { " c7 B) r8 g7 \; w9 D
- hex = '0' + hex; 3 P6 {; V/ Z) @. V$ X
- }
; F5 T" Z! t ^ - sb.append(hex.toUpperCase());
/ _5 h5 f7 ?* O2 t& Y& J6 i$ a - } 0 X' _# K2 P4 n1 U! Z
- return sb.toString(); " r% e3 |* j: Y+ p
- } 6 Y& B1 J4 g, \$ [
- 0 b+ \+ z% t9 p7 j7 Z
- : }9 W4 f: v) G( O K
- /**将16进制转换为二进制
) N3 a9 F8 O" d0 s) j0 ] - * @param hexStr - p( |1 u% C' W2 t
- * @return * W6 I6 [* Y9 I* k
- */ # O; l. Q* N3 Z/ o
- public static byte[] parseHexStr2Byte(String hexStr) {
U3 h: Y( A' u; Q/ q! x - if (hexStr.length() < 1) . Z! `1 o, I+ f
- return null;
6 x" O, j& a! g# i; } - byte[] result = new byte[hexStr.length()/2]; ( j+ o& }! w" I* B5 s \ @# n6 A
- for (int i = 0;i< hexStr.length()/2; i++) {
2 }5 D. ~+ E, E7 t: y1 j - int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); ! `( e! l4 [$ g, w( T
- int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); ; T9 V7 \# N3 ~! O
- result[i] = (byte) (high * 16 + low); " x" G2 f' f1 K
- }
1 ], k2 `+ _6 }$ w) L5 u& r" P - return result;
# M: d7 L3 K- U" [) m0 c. e2 S/ Y - }
7 h' n) p$ }% d8 U: s
$ ?: C; x, p9 ~$ o- 6 L! L0 Y1 ?$ Q' s
- 2 p& \/ i% T a: K. r0 t
- }4 h a8 r- V6 d$ R, Y5 P
复制代码 ) H! I+ t( H& d# s4 Y& G0 o$ |- M
以上在linux测试ok 原文转自:http://konglx.iteye.com/blog/954085) O2 M2 G( f/ C! B1 B2 B1 n% S# W
. T$ C( s# l) r$ F' r* C4 C. \" N; ^
; ^( T! N/ J5 F4 C
. E! A" s2 w8 L% w$ n |