• PHP与JAVA使用AES128位加密通信

    本来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的文档再说吧。