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的,这个原理都一样。


————————————————
版权声明:本文为CSDN博主「咆哮的程序猿」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/konkon2012/article/details/78505789

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AES(Advanced Encryption Standard,高级加密标准)是一种对称加密算法,常用于数据加密解密。而CBC(Cipher Block Chaining,密码块链)模式是一种加密算法的工作模式。PKCS5Padding是填充模式,用于将不满整块长度的数据进行填充,以满足加密算法的要求。 在使用H5进行AES CBC PKCS5Padding算法解密时,我们首先需要准备好密钥和加密后的数据。密钥可以是一个字符串,而加密后的数据通常是经过Base64编码的字符串。 接下来,我们需要将Base64编码的字符串解码成二进制数据,并将解码后的数据进行分块。每个分块的长度应该与密钥的长度相同,通常为16字节(128位)。如果数据的长度不是密钥长度的整数倍,我们可以使用PKCS5Padding进行填充。 然后,我们需要使用AES算法和CBC工作模式创建一个解密器。解密器需要接收密钥和初始向量(IV)作为参数。初始向量是一个随机生成的数据块,用于与第一个分块进行异或运算。 接下来,我们可以以分块的形式将加密数据输入到解密器中,并获得解密后的数据。解密器会自动对数据进行解密和去除填充。 最后,我们可以将解密后的数据转换回字符串形式,以得到我们想要的明文。 需要注意的是,在使用H5进行AES CBC PKCS5Padding算法解密时,我们需要确保密钥的正确性,以及正确的数据分块和填充。如果出现了错误,可能导致解密失败或明文数据损坏。因此,在使用这种算法进行数据加密解密时,建议仔细检查每个步骤的实现,并保持与其他参与方的一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值