文章首发于:clawhub.club
项目中用到了AES加密,在windows上运行的好好的,但是在linux下,解密时就会抛出:javax.crypto.BadPaddingException: Given final block not properly padded。记录一下,以后不要踩这种坑。
出问题的代码
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
|
public static byte[] encrypt(String content, String password) { try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance("AES"); byte[] byteContent = content.getBytes(StandardCharsets.UTF_8); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] result = cipher.doFinal(byteContent); return result; } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return null; }
public static byte[] decrypt(byte[] content, String password) { try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, key); byte[] result = cipher.doFinal(content); return result;
} catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return null; }
|
原因分析
为什么在windos上运行没问题,而linux上却不行呢?
忘了这段代码在哪抄的了,反正就是有个坑,就是:SecureRandom这个东西,它内部的实现完全看操作系统状态,他生成的key在windows上完全相同,但是在linux上却是不同的。
##解决办法
网上查的方法都是调用 getInstance 方法之后再调用 setSeed 方法。
我采取的是直接去掉SecureRandom。
解决的源代码
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
|
public static byte[] encrypt(byte[] data, byte[] key) throws Exception { Key secretKey = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return cipher.doFinal(data); }
public static byte[] decrypt(byte[] data, byte[] key) throws Exception { Key secretKey = new SecretKeySpec(key, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, secretKey); return cipher.doFinal(data); }
|
附上网上摘得解决办法
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
|
private static final String ENCODING = "UTF-8";
public static final String KEY_ALGORITHM = "AES";
public static final String SIGN_ALGORITHMS = "SHA1PRNG";
public static String encrypt(String content, String key) { try { KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM); SecureRandom random = SecureRandom.getInstance(SIGN_ALGORITHMS); random.setSeed(key.getBytes(ENCODING)); kgen.init(128, random); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, KEY_ALGORITHM); Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); byte[] byteContent = content.getBytes(ENCODING); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); byte[] byteRresult = cipher.doFinal(byteContent); StringBuffer sb = new StringBuffer(); for (int i = 0; i < byteRresult.length; i++) { String hex = Integer.toHexString(byteRresult[i] & 0xFF); if (hex.length() == 1) hex = '0' + hex; sb.append(hex.toUpperCase()); } return sb.toString(); } catch (Exception e) { e.toString(); } return null; }
public static String decrypt(String content, String key) { if (content.length() < 1) return null; byte[] byteRresult = new byte[content.length() / 2]; for (int i = 0; i < content.length() / 2; i++) { int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16); byteRresult[i] = (byte) (high * 16 + low); } try { KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM); SecureRandom random = SecureRandom.getInstance(SIGN_ALGORITHMS); random.setSeed(key.getBytes(ENCODING)); kgen.init(128, random); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, KEY_ALGORITHM); Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); byte[] result = cipher.doFinal(byteRresult); return new String(result, ENCODING); } catch (Exception e) { e.toString(); } return null; }
|
参考
javax.crypto.BadPaddingException: Given final block not properly padded