本来JAVA和JSP之间加密通信好好的,相同的函数,相同的处理,不会有其他大问题。不过有时候就是蛋疼啊,于是就有了PHP与JAVA间使用AES进行加密通信。
PHP的AES128位由mcrypt模块提供,称为MCRYPT_RIJNDAEL_128。
JAVA的AES默认就是128位的。
加密模式有好几种,不同的语言不同的库支持的情况不同。这里选择的是安全且通用的CBC模式。
至于padding,这是最头疼的问题,因为PHP的padding与Java的padding不一样。如果使用NoPadding,则默认又用不了CBC模式。所以,最好的解决方法是自己padding——在原文末尾加上若干个空格,使原文凑齐16的倍数的长度。当然,原文末尾也可能是空格结束啊,那怎么办?没办法,只有强制原文末尾加上一个换行。这样子,每次解密后,将最右边的换行以及其右边的空格裁剪掉,就得到原文了。
另外,为了兼容,在加密和解密时,需要将内容转换成16进制的字符数组。这样一来,即使加密/解密的内容不是普通文本,而是二进制数据,也可以轻松传送啦。
JAVA方面
初始化代码:
try { cipherEnc = Cipher.getInstance("AES/CBC/NoPadding"); } catch (NoSuchAlgorithmException ex) { ex.printStackTrace(); } catch (NoSuchPaddingException ex) { ex.printStackTrace(); } try { cipherDec = Cipher.getInstance("AES/CBC/NoPadding"); } catch (NoSuchAlgorithmException ex) { ex.printStackTrace(); } catch (NoSuchPaddingException ex) { ex.printStackTrace(); } key = new SecretKeySpec(keyStr.getBytes(), "AES"); iv = new IvParameterSpec(ivStr.getBytes());
加密解密及其核心函数:
public static String padRight(String s, int n) { return String.format("%1$-" + n + "s", s); } public static String padLeft(String s, int n) { return String.format("%1$#" + n + "s", s); } public String encrypt(SecretKeySpec enc_key, IvParameterSpec enc_iv, String str){ byte[] ret = null; try { cipherEnc.init(Cipher.ENCRYPT_MODE, enc_key, enc_iv); ret = cipherEnc.doFinal(padRight(str, ((int)Math.ceil(str.length() / 16.0))*16).getBytes()); } catch (Exception ex) { ex.printStackTrace(); return null; } return byteArray2HexString(ret); } /* * str is Hex String */ public String decrypt(SecretKeySpec dec_key, IvParameterSpec dec_iv, String str){ byte[] ret = null; try { cipherDec.init(Cipher.DECRYPT_MODE, dec_key, dec_iv); ret = cipherDec.doFinal(hexString2ByteArray(str)); } catch (Exception ex) { ex.printStackTrace(); return null; } try { return new String(ret, "UTF-8"); } catch (UnsupportedEncodingException e) { return null; } } static final char[] HEX_CHAR_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; public static String byteArray2HexString(byte[] b) { if (b == null) { return null; } final StringBuilder hex = new StringBuilder(2 * b.length); for (final byte by : b) { hex.append(HEX_CHAR_TABLE[(by & 0xF0) >> 4]).append(HEX_CHAR_TABLE[(by & 0x0F)]); } return hex.toString(); } public static byte[] hexString2ByteArray(String s) { if (s == null) { return null; } byte high, low; int len = s.length() / 2; byte[] b = new byte[len]; for(int i=0, k=0; i<len; i++, k+=2) { high = (byte) (Character.digit(s.charAt(k), 16) & 0x0F); low = (byte) (Character.digit(s.charAt(k+1), 16) & 0x0F); b[i] = (byte) ((high<<4) | low); } return b; }
PHP方面
加密解密部分及其核心函数
static function encrypt($enc_key, $enc_iv, $data){ $pad = str_pad($data, ceil(strlen($data)/16.0)*16, " "); $method = MCRYPT_RIJNDAEL_128; $mode = MCRYPT_MODE_CBC; $td = mcrypt_module_open($method, '', $mode, ''); mcrypt_generic_init ( $td , $enc_key , $enc_iv); $encrypt = mcrypt_generic($td, $pad); mcrypt_generic_deinit($td); mcrypt_module_close($td); return bin2hex($encrypt); } static function decrypt($dec_key, $dec_iv, $data){ $method = MCRYPT_RIJNDAEL_128; $mode = MCRYPT_MODE_CBC; $td = mcrypt_module_open($method, '', $mode, ''); mcrypt_generic_init ( $td , $dec_key , $dec_iv); $decrypt = mdecrypt_generic($td, hex2bin($data)); mcrypt_generic_deinit($td); mcrypt_module_close($td); return $decrypt; } if(!function_exists('hex2bin')) { /** * Converts the hex representation of data to binary * * http://www.php.net/manual/en/function.hex2bin.php * * @param string $str Hexadecimal representation of data * * @return string Returns the binary representation of the given data */ function hex2bin($data) { return pack("H*" , $data); } }
就是这样啦。什么?不懂怎么用?那就看看AES的文献,看看Java和PHP的文档再说吧。
0
这个,真的看不懂。太深奥的代码了。
暂时还用不着PHP与JAVA之间进行通讯
java部分不行。。。出错,麻烦整理到一个文件啊。
//PHP 完全可以使用和Java一样的PKCS5Padding
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
感谢提供PKCS5Padding函数,不知道java的blocksize是多少?