现象描述:
0 H! D8 l2 K3 W6 e# w9 F# b, R4 Y" q
windows上加解密正常,linux上加密正常,解密时发生如下异常:
3 k+ T, F' o7 D2 m% k3 f8 n* }2 g1 y" ^/ l1 s) {( s$ y Y2 \
javax.crypto.BadPaddingException: Given final block not properly padded
8 I$ N" w. A1 R" a( o at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)/ i& M! v5 h- r6 d
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
- K. M" t4 c! l/ [5 Y0 Q9 k; L at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)- I7 H0 D( ^* X+ c& |
at javax.crypto.Cipher.doFinal(DashoA13*..)
1 g( C& ~- D( u' V% G at chb.test.crypto.AESUtils.crypt(AESUtils.java:386)$ m0 `) j) F* P
at chb.test.crypto.AESUtils.AesDecrypt(AESUtils.java:254)
. ^9 }$ u, y0 q+ u) z8 Y at chb.test.crypto.AESUtils.main(AESUtils.java:40) 解决方法:# @+ ]2 D/ h5 b% F3 f6 Z0 u
7 \# L' J7 C9 n5 }% ] I经过检查之后,定位在生成KEY的方法上,如下:0 `7 G; D$ M1 k: U5 Y# ~, ?0 D: W
- public static SecretKey getKey (String strKey) {
2 ?) n6 [6 W* c5 N0 y: U - try {
: ]' J K; D4 n z - KeyGenerator _generator = KeyGenerator.getInstance( "AES" );
7 I+ Q# f" Q5 b, X6 O! ^ - _generator.init(128, new SecureRandom(strKey.getBytes()));3 `6 ?3 `, g: m3 b) b5 N9 l/ ]) I8 x
- return _generator.generateKey();) }9 @4 g+ |; l& P* R3 P R
- } catch (Exception e) {. p6 _$ ^/ b, R3 B. T# D1 X3 A
- throw new RuntimeException( " 初始化密钥出现异常 " );9 `3 u! B+ [/ Y8 u" c! `" H
- }" v) f2 f4 [- j, E
- }
复制代码 修改到如下方式,问题解决:
9 e2 V: L5 H# K$ M) W- public static SecretKey getKey(String strKey) {
2 _- b) j" U$ `# g/ T x( { - try {
( {- `1 y) h( p+ |! E( J - KeyGenerator _generator = KeyGenerator.getInstance( "AES" );
" N; f5 z+ t: H! `+ w4 V/ p3 Z - SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
$ h2 L- G; d& ~& o& Z+ R - secureRandom.setSeed(strKey.getBytes());: f* D1 @" N* ^& h" u! P
- _generator.init(128,secureRandom);
; C- z' Y9 {# M7 L6 p4 u( N9 g - return _generator.generateKey();
2 t: a6 {! J# F3 N5 h4 H7 c: ] - } catch (Exception e) {
, d3 ~0 `# [! P9 W: ]! ^4 @" M4 L - throw new RuntimeException( " 初始化密钥出现异常 " );* {/ [8 N/ l$ t' G- B) N6 p, \
- }
# [$ `& B9 P" v R - }
复制代码 原因分析6 R8 _2 n, e$ E! V' S+ g, k5 G
SecureRandom 实现完全隨操作系统本身的內部狀態,除非調用方在調用 getInstance 方法之後又調用了 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。
9 \( @! U: c+ a0 L3 N3 Q+ n0 h0 S6 f0 W R
原因二:- F* e, B8 ~- e: P, I$ a2 W
( l# O+ ]3 S9 L5 n) d, k
1、加密完byte[] 后,需要将加密了的byte[] 转换成base64保存,如:
. L7 @! B1 Q) PBASE64Encoder base64encoder = new BASE64Encoder();
+ w- d0 x, L9 I. S4 hString encode=base64encoder.encode(bytes);
! k/ s% q b! Q7 r. W! [0 R0 H2 J# I- k) ~
2、解密前,需要将加密后的字符串从base64转回来再解密,如: " b) h/ T1 R9 f7 k; L& h
BASE64Decoder base64decoder = new BASE64Decoder();
& Y: R6 p7 i' K4 q0 T; Kbyte[] encodeByte = base64decoder.decodeBuffer(str); : N* U! c: K' v
- g5 O8 I' B. Y
/ s4 k5 C" m5 A ?; |$ Q8 B2 g完整例子:
( v! r* g* p H4 r" c% K- package com.travelsky.tdp.pkgStock.util;
- z7 k0 ^8 S3 L1 N; d$ U
+ B, r* \6 h8 Y2 F- import java.io.IOException;
3 \; m4 @) q. `7 l. H8 W1 x - import java.io.UnsupportedEncodingException;! o3 s4 n* j# t
- import java.security.InvalidKeyException;
% ^; O$ \ E" i1 h% G8 M6 k - import java.security.NoSuchAlgorithmException;+ O" R/ `' k) {
- import java.security.SecureRandom;
4 X$ \* o% { [0 y - " d6 N" K: k5 q/ V) p& v
- import javax.crypto.BadPaddingException;* p: N4 R; |" P; S U2 V
- import javax.crypto.Cipher;$ n9 x m$ S: p/ a [5 \
- import javax.crypto.IllegalBlockSizeException;* S8 ?8 e- c( Z
- import javax.crypto.KeyGenerator;
# B, D# [0 `& k, _ - import javax.crypto.NoSuchPaddingException;9 H0 @7 t5 X# q, j- X
- import javax.crypto.SecretKey;6 K) w/ l4 Q5 z' _8 q
- import javax.crypto.spec.SecretKeySpec;
/ S w; G4 M& D7 u - 4 k6 \, x) I# n1 ]8 z( V8 V
- import sun.misc.BASE64Decoder;3 z6 F8 g A+ H3 K; l( j
- import sun.misc.BASE64Encoder;* Y5 |1 n/ S# z, K
" `2 P# [$ h& }% V* Y- public class SecurityAES { v7 r9 W% y" x
- private final static String encoding = "UTF-8";
9 m+ u1 h" W5 [; }+ [+ H# u# J - /**
( |2 ?: s( Y9 P X( l - * AES加密$ T0 D+ {( _9 W3 m. \9 e/ O& A; q
- * ) m, D; a$ d( i! ?. p4 }
- * @param content# Y. C4 L! E; m# X! B/ x
- * @param password
, G1 o5 n: y; U: D; i9 ~ - * @return3 T% g! O; S) b( r% p- z
- */
0 i( S; O% ~* @. Y2 _/ Z - public static String encryptAES(String content, String password) {- ]( h0 S, z: I* e3 [
- byte[] encryptResult = encrypt(content, password);
( }% L% _( Z8 z1 H$ V - String encryptResultStr = parseByte2HexStr(encryptResult);
$ R$ z# ?* z9 a, \ - // BASE64位加密
' G5 V! B7 d3 F1 V% Y - encryptResultStr = ebotongEncrypto(encryptResultStr);; h. j! G' b. p0 J
- return encryptResultStr;! h) e" f- S' r F& m4 D- c- Q% z
- }: a( @! x; L) P5 L
" ]' z1 ?* e4 b3 k! \5 ~, z% [- /**
+ o4 p l; j4 |6 j - * AES解密/ Z3 F+ o! D- U0 ~- V5 i, N
- * 2 ~- i: f- M* I f; `! o1 a
- * @param encryptResultStr
/ h% C3 I$ O6 B: M) ], A K% _8 _+ X - * @param password
3 |! _7 F# v- Q; c - * @return
) j! b# n3 X! T+ w; c7 k3 l - */* V( w' R( s9 q/ Z
- public static String decrypt(String encryptResultStr, String password) {4 r" {% i+ X; h, V. Y
- // BASE64位解密
9 x' x3 e+ ^* N3 j2 l. ^ - String decrpt = ebotongDecrypto(encryptResultStr);
. w+ _7 }; { V& j9 n; w - byte[] decryptFrom = parseHexStr2Byte(decrpt); c4 C2 ?1 T: m2 X$ w z3 i! `8 n
- byte[] decryptResult = decrypt(decryptFrom, password);
% I: _: Q2 c* D6 ]' P, D' }8 V) i - return new String(decryptResult);
4 T( g% |+ }( d1 g1 T- W# x - }
! F4 L$ k8 G! @: P
3 N1 K% }0 r4 ], L+ c0 R" C- /** W2 J) A7 J/ t6 }* @: P
- * 加密字符串
* C" V* j0 X: @2 O6 a# v - */' A. f9 L! R( K
- public static String ebotongEncrypto(String str) {, W2 L" z+ Z: u( ?, B- z: R5 F
- BASE64Encoder base64encoder = new BASE64Encoder();! i& C- Z0 Y ^* n" J
- String result = str;
) i4 s3 [1 ?! f. g' Q f2 X! ? - if (str != null && str.length() > 0) {
4 u1 S; Q. V+ }; P - try {
- P9 m- J! ]/ Z! G& T0 _+ ~9 S - byte[] encodeByte = str.getBytes(encoding);
9 G3 ~7 Q4 a u: \3 v- S# C( f - result = base64encoder.encode(encodeByte);0 D9 w3 B! Z0 t& P
- } catch (Exception e) {
% Y7 u/ x* @. m$ P - e.printStackTrace();
' G m$ [# \4 ^ - }
- F6 G3 M5 h6 E0 _: H O# j: b - }% a2 r. G/ M5 u5 W
- //base64加密超过一定长度会自动换行 需要去除换行符
1 q- r V. o6 B4 K4 M% | - return result.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");
( m% S+ R4 ~! ?0 |( s - }3 y$ r# M1 E8 {( [% X/ w
% a. @1 H j8 ]7 W. n- /**
% u) d0 A( y; y( x) B - * 解密字符串
: s1 w& c) l: P - */
, R5 f: r( h% ~2 _ - public static String ebotongDecrypto(String str) {
9 N: A! p0 n/ ?9 ]4 [3 J - BASE64Decoder base64decoder = new BASE64Decoder();
; T/ Y7 g5 b. E$ S - try {
/ F0 A: W; z, v7 @( K/ a2 C* G - byte[] encodeByte = base64decoder.decodeBuffer(str);: O' m% q7 v8 U) y
- return new String(encodeByte);2 g* o" y" c0 o/ P3 |* ]
- } catch (IOException e) {
4 @1 N" f1 m" }2 u7 v - e.printStackTrace();
# K( p4 ~) O, K, w9 [ - return str;
" X* H9 r2 |: [$ W - }+ ]3 @2 s; I/ H; _$ z4 N
- }
2 H8 J3 X( S2 c: |. _ - /**
% B! P8 P6 _7 r; N" a - * 加密 5 M7 p) [5 `8 K# g8 `- @ M
- *
! c- F4 G1 p% Z( |9 ^# @ - * @param content 需要加密的内容 2 {# x3 i) g1 s3 [) T
- * @param password 加密密码 ! G! V8 n' Q$ ]1 k' ~" x4 U. J4 x3 ^
- * @return / h% F" T$ V* P" S
- */
3 D6 n( _1 p# E6 m - private static byte[] encrypt(String content, String password) { $ a/ t5 Q' V% n/ [$ y# X* a* R
- try { & A2 S |8 E& H% y# H4 S
- KeyGenerator kgen = KeyGenerator.getInstance("AES");
% z9 ]- A' a: D/ {- Y4 d - //防止linux下 随机生成key
2 r2 o; ? U/ K6 u; d - SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
: C4 O; s8 x X# H- R - secureRandom.setSeed(password.getBytes()); / O, \9 S" u, \3 D U
- kgen.init(128, secureRandom);
0 H: R" J$ }" v9 _ - //kgen.init(128, new SecureRandom(password.getBytes()));
0 C+ E' r. Y f/ B T/ @ - SecretKey secretKey = kgen.generateKey(); " ?; D. k; W8 h, I% P
- byte[] enCodeFormat = secretKey.getEncoded();
/ N, D2 A# v2 x - SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 5 T C2 G" Y* d$ u1 g7 V v4 c
- Cipher cipher = Cipher.getInstance("AES");// 创建密码器 4 z0 i( N/ f B6 m( ]! ^
- byte[] byteContent = content.getBytes("utf-8"); 7 }5 v' c0 T3 Z( p7 J7 B& T
- cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 4 Y1 ^6 ]# t- N) ~
- byte[] result = cipher.doFinal(byteContent);
- E4 Q2 Q0 A" {* ~/ P6 L2 k- X - return result; // 加密
4 F9 S u: p$ i' X, i - } catch (NoSuchAlgorithmException e) {
$ t% S, P( r% W& A, T - e.printStackTrace();
9 Y' _8 q, P; {/ K$ o% p - } catch (NoSuchPaddingException e) {
8 W4 u' s+ B+ R- O4 C; l - e.printStackTrace();
9 e. F% f7 h1 } - } catch (InvalidKeyException e) { * W9 u0 P0 X, p# x9 u8 Q$ c7 x: u( @
- e.printStackTrace();
, p* F8 e# O l; \" b+ |" q/ M - } catch (UnsupportedEncodingException e) { ) I" }4 K; h+ \( T6 E
- e.printStackTrace(); % R6 y2 S4 g0 R b8 a( v8 s
- } catch (IllegalBlockSizeException e) { : @3 I. s3 I) E2 k
- e.printStackTrace();
: j& L9 j* m8 b - } catch (BadPaddingException e) { 3 E W; s3 b3 A, _3 S# I6 k" w
- e.printStackTrace(); ]& S( c R/ h* P, |
- }
3 w+ H7 x3 S9 a - return null; , E; `! [6 X3 _9 O
- } 0 U; @8 P! F+ T; @8 y0 L
- , ~+ K- r5 v' Z$ \0 P/ r
- 3 H$ O% e0 [5 a
- /**解密 ; W& V0 b4 z5 J0 i# a
- * @param content 待解密内容
( |) J- O$ V x0 k5 B; m - * @param password 解密密钥
& b/ }* b' S. H9 D6 X - * @return 6 j, Z7 ?% Q" _
- */
4 X( }$ n9 }" p$ j& S6 { - private static byte[] decrypt(byte[] content, String password) {
- B0 N, x7 D6 M+ S, { - try {
c: C# W' _2 Y+ _, E( P - KeyGenerator kgen = KeyGenerator.getInstance("AES");
- ] P! M. U- d8 r - //防止linux下 随机生成key# z2 _9 G! Z( E0 O6 P
- SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" ); / }- H5 T0 h* [2 e. ^
- secureRandom.setSeed(password.getBytes()); % h! ~2 x' p- Y0 k0 _
- kgen.init(128, secureRandom);8 P$ |$ k% @% w" D' _/ t; u/ I
- //kgen.init(128, new SecureRandom(password.getBytes())); 2 }6 @" R, z" h7 m
- SecretKey secretKey = kgen.generateKey(); $ W. \3 @' i( W4 Z ^7 G; k
- byte[] enCodeFormat = secretKey.getEncoded();
9 _" O% F+ E; Q0 f4 r7 o8 m - SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
- H) d' C0 u+ k. _0 p - Cipher cipher = Cipher.getInstance("AES");// 创建密码器
) ~4 g3 J: j4 m; g8 n' i3 G0 W - cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
3 Y9 B W. h. o - byte[] result = cipher.doFinal(content); ) E" n/ R/ H# N- l% r
- return result; // 加密 ' A# M$ t, b, e& {6 `/ M
- } catch (NoSuchAlgorithmException e) {
5 y, `& Y1 m7 h& \/ ] - e.printStackTrace();
8 T- N1 V5 a6 o- U8 P5 p( R/ T3 w - } catch (NoSuchPaddingException e) {
$ D! c! m7 I7 I0 i" s% ~ - e.printStackTrace(); # e3 m) R3 I: M" r
- } catch (InvalidKeyException e) { , @4 L9 ?; N* }& t1 S
- e.printStackTrace();
$ d2 q. M. g: L$ U; a; ~ - } catch (IllegalBlockSizeException e) {
* i( Z+ d ]: N6 W0 V1 d7 V - e.printStackTrace(); 2 R3 {" m: E8 G5 K6 D- I" B
- } catch (BadPaddingException e) {
- Q! y+ t! d: Q7 `5 w u, g - e.printStackTrace();
! S, G' X' G* L! [- y+ x( R9 H - }
; g' s! V! b# T; @; U - return null;
5 w5 ^: Y3 [4 ?, I8 |' q - } 8 [0 D5 Q, E! {: V1 G& R5 s
- $ j9 H" z( G$ j" E% C
- /**将二进制转换成16进制
9 F0 e4 Q2 n) s5 S2 t+ U - * @param buf
- H8 d$ S: h" D5 b - * @return
6 X( S5 ?* E/ y" h1 b2 y - */ " A( z% H, V1 \% j
- public static String parseByte2HexStr(byte buf[]) {
) u. s" ^: d% n) h5 q - StringBuffer sb = new StringBuffer(); 7 y# n! c* p3 V5 h
- for (int i = 0; i < buf.length; i++) { * c) m; d2 N" C5 f H
- String hex = Integer.toHexString(buf[i] & 0xFF);
" s" k) r9 ?1 B: Y - if (hex.length() == 1) { / e+ N. r) Y+ ]+ ` v$ n
- hex = '0' + hex;
. M: ?9 c' G2 b4 f; T - }
9 I$ V5 h1 T6 T5 F5 S - sb.append(hex.toUpperCase()); @: b9 `+ j/ w* D2 B' t
- }
* Z4 D( m# S k- \) f4 O - return sb.toString();
2 f8 m) @9 c: r6 \: V - }
6 k Q7 e7 @( Z$ F8 ~# ~% U3 z
9 J3 n0 G; m; s0 R- _8 t5 t. m- 7 L/ }% ? _2 U* w4 M& b0 R' Q v! k
- /**将16进制转换为二进制
2 \5 M- D" a$ b. b - * @param hexStr 0 q7 r) H" q" V2 C: g: ^ E
- * @return
- \8 ~* {9 `& R+ r5 k. D - */ . k$ m. P2 y# R/ a" H) K
- public static byte[] parseHexStr2Byte(String hexStr) { * s* |' l/ X' g
- if (hexStr.length() < 1) , h7 I. d( v( n {! \" {
- return null;
5 n G/ b- v" c. w ?& n - byte[] result = new byte[hexStr.length()/2]; 4 d, J. H G% P0 u( k
- for (int i = 0;i< hexStr.length()/2; i++) { - w# s+ C% ^* k) d- E) a
- int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); 5 w& X3 S) L* T; k+ ~8 H" m; ^, ?8 {
- int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); $ \, s; w& N' s) [
- result[i] = (byte) (high * 16 + low);
* Y/ _7 F: q- L7 @+ Z. g' S% I - }
' p4 [& t* x6 h5 ~, `7 k! s) V - return result; * u9 Z$ p; ], Y9 S
- }
' `/ _; M9 \ D' @) J4 p - 8 |- ], T* w# P# k1 l. q5 {
- * L3 R; V" @) O2 S$ m) b) X
- & _9 y: ]& M& t, o, N" t4 Y
- }
6 ~% M+ Y! p7 ~
复制代码 4 L; u: Y8 h3 j* B" V
以上在linux测试ok 原文转自:http://konglx.iteye.com/blog/954085
- v+ n& j0 [/ f% _0 U3 {
! X0 T/ r: Z" T# b
& i; E6 z* N: v
1 o* S8 \8 ~2 P' A2 b9 D |