android加密,php解密 , AES,CBC, PKCS7Padding
数据加密的技术分为两类,即对称加密和非对称加密。对称加密以数据加密标准(DES,Data Encryption Standard)算法为典型代表,非对称加密通常以RSA(RivestShamir Adleman)算法为代表。对称加密的加***和解***相同,而非对称加密的加***和解***不同,加***可以公开而解***需要保密。
DES比较老的算法,一共有三个参数入口(原文,**,加密模式)。而3DES只是DES的一种模式,是以DES为基础更安全的变形,对数据进行了三次加密,也是被指定为AES的过渡算法。AES是高级加密标准,新一代标准,加密速度更快,安全性更高。AES**长度可以选择128位(16字节),192位(24字节)和256位(32字节)**。AES算法的所有参数都是字节码的(包括**),因此字符串字符需要转换成字节码后进行加密。
小提示:我们日常使用的MD5,SHA1属于摘要算法,并非上述加密范畴之内。
废话不说了,在安卓端,我做了一个AESCryptUtil类,来实现加密算法,我的加密方式为 : AES/CBC/PKCS7Padding
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.UnsupportedEncodingException;
public class AESCryptUtil {
/** 算法/模式/填充 **/
private static final String CipherMode = "AES/CBC/PKCS7Padding";
// 创建**, 长度为128位(16bytes), 且转成字节格式
private static SecretKeySpec createKey(String key) {
byte[] data = null;
if (key == null) { key = ""; }
StringBuffer sb = new StringBuffer(16);
sb.append(key);
while (sb.length() < 16) { sb.append("0"); }
if (sb.length() > 16) { sb.setLength(16); }
try { data = sb.toString().getBytes("UTF-8");}
catch (UnsupportedEncodingException e) { e.printStackTrace(); }
return new SecretKeySpec(data, "AES");
}
// 创建初始化向量, 长度为16bytes, 向量的作用其实就是salt
private static IvParameterSpec createIV(String iv) {
byte[] data = null;
if (iv == null) { iv = ""; }
StringBuffer sb = new StringBuffer(16);
sb.append(iv);
while (sb.length() < 16) { sb.append("0"); }
if (sb.length() > 16) { sb.setLength(16); }
try { data = sb.toString().getBytes("UTF-8"); }
catch (UnsupportedEncodingException e) { e.printStackTrace(); }
return new IvParameterSpec(data);
}
/****************************************************************************/
// 加密字节数据, 被加密的数据需要提前转化成字节格式
private static byte[] encrypt(byte[] content, String key, String iv) {
try {
SecretKeySpec secretKeySpec = createKey(key);
IvParameterSpec ivParameterSpec = createIV(iv);
Cipher cipher = Cipher.getInstance(CipherMode);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] result = cipher.doFinal(content); // 加密
return result;
} catch (Exception e) { e.printStackTrace(); }
return null;
}
// 加密字符串数据, 返回的字节数据还需转化成16进制字符串
public static String encrypt(String content, String key, String iv) {
byte[] data = null;
try { data = content.getBytes("UTF-8"); }
catch (Exception e) { e.printStackTrace(); }
data = encrypt(data, key, iv);
return byte2hex(data);
}
/****************************************************************************/
// 解密字节数组
private static byte[] decrypt(byte[] content, String key, String iv) {
try {
SecretKeySpec secretKeySpec = createKey(key);
IvParameterSpec ivParameterSpec = createIV(iv);
Cipher cipher = Cipher.getInstance(CipherMode);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) { e.printStackTrace(); }
return null;
}
// 解密(输出结果为字符串), 密文为16进制的字符串
public static String decrypt(String content, String password, String iv) {
byte[] data = null;
try { data = hex2byte(content); }
catch (Exception e) { e.printStackTrace(); }
data = decrypt(data, password, iv);
if (data == null) return null;
String result = null;
try { result = new String(data, "UTF-8");
} catch (UnsupportedEncodingException e) { e.printStackTrace(); }
return result;
}
/****************************************************************************/
// 字节数组转成16进制大写字符串
private static String byte2hex(byte[] b) {
String tmp = "";
StringBuffer sb = new StringBuffer(b.length * 2);
for (int n = 0; n < b.length; n++) {
tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (tmp.length() == 1) { sb.append("0"); }
sb.append(tmp);
}
return sb.toString().toUpperCase();
}
// 将16进制字符串转换成字节数组
private static byte[] hex2byte(String inputString) {
if (inputString == null || inputString.length() < 2) { return new byte[0]; }
inputString = inputString.toLowerCase();
int l = inputString.length() / 2;
byte[] result = new byte[l];
for (int i = 0; i < l; ++i) {
String tmp = inputString.substring(2 * i, 2 * i + 2);
result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
}
return result;
}
}
有了这样一个Util类,使用加密就非常方便了,使用方式如下:
String key = MainApp.getAESkey(); // "781E5E245D69B566"
String iv = MainApp.getAESiv(); // "9F0885C2D686C418"
String name = "richie";
String result = AESCryptUtil.encrypt(name, key, iv);
Log.e("MainActivity", "result:" + result); // E80A6DD061E8CB53ABED62C7DCCEEEFA
String name2 = AESCryptUtil.decrypt(result, key, iv);
Log.e("MainActivity", "name:" + name2); // richie
运行结果为:E80A6DD061E8CB53ABED62C7DCCEEEFA
最后是我们的PHP端,代码如下:
// "AES/CBC/PKCS7Padding"
define('SECRETKEY', '781E5E245D69B566');
define('SECRETIV', '9F0885C2D686C418');
// 加密方法
function encrypt($str) {
$str = addPKCS7Padding($str);
$encrypt_str = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, SECRETKEY, $str, MCRYPT_MODE_CBC, SECRETIV);
return strToHex($encrypt_str);
}
// 解密方法
function decrypt($str) {
$str = hexToStr($str);
$encrypt_str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, SECRETKEY, $str, MCRYPT_MODE_CBC, SECRETIV);
$encrypt_str = removePKSC7Padding($encrypt_str);
return $encrypt_str;
}
// 填充算法
function addPKCS7Padding($source) {
$source = trim($source);
$block = mcrypt_get_block_size('rijndael-128', 'cbc');
$pad = $block - (strlen($source) % $block);
if ($pad <= $block) {
$char = chr($pad);
$source .= str_repeat($char, $pad);
}
return $source;
}
// 移去填充算法
function removePKSC7Padding($source) {
$char = substr($source, -1);
$num = ord($char);
$source = substr($source, 0, -$num);
return $source;
}
// 十六进制转字符串
function hexToStr($hex) {
$string="";
for($i=0;$i<strlen($hex)-1;$i+=2)
$string.=chr(hexdec($hex[$i].$hex[$i+1]));
return $string;
}
// 字符串转十六进制
function strToHex($string) {
$hex="";
$tmp="";
for($i=0;$i<strlen($string);$i++){
$tmp = dechex(ord($string[$i]));
$hex.= strlen($tmp) == 1 ? "0".$tmp : $tmp;
}
$hex=strtoupper($hex);
return $hex;
}
// 加密
$string = encrypt('richie'); // E80A6DD061E8CB53ABED62C7DCCEEEFA
print_r($string);
echo '<hr>';
// 解密
$string = decrypt($string); // richie
print_r($string);
输出结果为同安卓端是一样的!
特别需要指出的就是,php和android两者的加密模式必须一致,即:AES/CBC/PKCS7Padding,当然了秘钥和盐值也必须一致。
最后需要指出的是密文的呈现方式,我这里使用16进制,也有人使用base64的,这个原理都一样。
上一篇: java发送邮件-模板
下一篇: 三、HQL语句--where(限制)
推荐阅读
-
android加密,php解密 , AES,CBC, PKCS7Padding
-
Node Java相互使用AES-256-CBC对数据进行加密解密实现
-
AES-CBC-128 对称加解密C#和php
-
PHP 实现AES/CBC/PKCS5Padding加解密(对称加密)
-
简单的Python3例子-CBC模式的AES加密解密
-
Android网络数据传输安全——AES加密解密(ECB模式)
-
android、ios、php之间AES加密解密!
-
android Base64 AES加密解密
-
Android-ios-php Rsa加密解密
-
Android、iOS和Java通用的AES128加密解密示例代码