Android开发笔记(七十二)数据加密算法

来源:互联网 发布:产品网络推广策划书 编辑:程序博客网 时间:2024/04/28 16:49

编码算法

URL编码

URL编码其实并非加解密算法,只是对特殊字符进行字符转义,从而方便在URL中传输参数。URL编码有两种方式,一种是狭义的URL编码,另一种是广义的URL编码。
狭义的URL编码指的是只对汉字进行编码,相关代码参见《Android开发笔记(六十三)HTTP访问的通信方式》。
广义的URL编码指的是除了汉字之外,还对其他特殊字符进行编码,如空格转换为“%20”,其他的“?”、“&”“/”也分别转换为“%3F”、“%26”、“%2F”。广义的URL编码可直接使用URLEncoder的encode方法,URL解码使用URLDecoder的decode方法,代码示例如下:
//URL编码public static String encodeURL(String str) {String encode_str = str;try {encode_str = URLEncoder.encode(str, "utf-8");} catch (Exception e) {e.printStackTrace();}return encode_str;}//URL解码public static String decodeURL(String str) {String decode_str = str;try {decode_str = URLDecoder.decode(str, "utf-8");} catch (Exception e) {e.printStackTrace();}return decode_str;}



BASE64编码

BASE64是一种针对字节流的编码工具,用于把不可见的字节流转换为可见的字符串。如果把待加密的数据先转为字节流,然后再把字节流通过BASE64编码成字符串,就好像是完成了加密操作。同时,这个字符串也可以通过BASE64解码为原始数据,因此,我们也可以把BASE64编码看作是一种简单的可逆加密算法。


BASE64有两种编码方式,一种是SUN的,另一种是Apache的。
SUN的BASE64编码,编码算法在sun.misc.BASE64Encoder的encode函数,解码算法在sun.misc.BASE64Decoder的decodeBuffer函数。但是SUN的这个包不在Java的核心库内,所以Android上会报方法找不到的错误。要想在Android上也能使用SUN的BASE64,有两种方式,一种是导入rt.jar包,另一种是在工程中直接加入SUN的源码。
Apache的BASE64编码,编码算法在Base64的encodeBase64String函数,解码算法在Base64的decodeBase64函数。Apache方式对应的jar包名称是commons-codec-***.jar,可是Android内部有相同包名的方法,编译的时候不会报错,运行时便会报方法找不到。要想正常运行,得下载源码后修改包名,避免与系统自带的包冲突。


加密算法

MD5加密

MD5是不可逆的加密算法,也就是无法解密。MD5的加密实现在commons-codec-***.jar中,但是该包的MD5加密函数md5Hex在java环境可以正常运行,但在Android上运行会报错:java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString。这个报错与上面Apache的BASE64编码的问题是一样的,解决该问题有三个办法:
1、使用MessageDigest方式进行MD5加密;
2、下载org.apache.commons.codec的源码,改个包名,在Android环境重新编译打成jar;
3、使用下面代码实现曲线加密:
String md5Str = new String(Hex.encodeHex(DigestUtils.md5(raw)));


具体的MD5加密示例代码如下:
import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import org.apache.commons.codec.binary.Hex;import org.apache.commons.codec.digest.DigestUtils;public class MD5Util {/* * 1.一个运用基本类的实例 MessageDigest 对象开始被初始化。该对象通过使用 update 方法处理数据。 任何时候都可以调用 * reset 方法重置摘要。 一旦所有需要更新的数据都已经被更新了,应该调用 digest 方法之一完成哈希计算。 * 对于给定数量的更新数据,digest 方法只能被调用一次。 在调用 digest 之后,MessageDigest 对象被重新设置成其初始状态。 */public static String encrypByMd5(String raw) {String md5Str = raw;try {MessageDigest md = MessageDigest.getInstance("MD5");md.update(raw.getBytes());byte[] encryContext = md.digest();int i;StringBuffer buf = new StringBuffer("");for (int offset = 0; offset < encryContext.length; offset++) {i = encryContext[offset];if (i < 0) {i += 256;}if (i < 16) {buf.append("0");}buf.append(Integer.toHexString(i));}md5Str = buf.toString();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return md5Str;}/* * 2.使用开发的jar直接应用 使用外部的jar包中的类:import * org.apache.commons.codec.digest.DigestUtils; 对上面内容的一个封装使用方便 */public static String encrypByMd5Jar(String raw) {//String md5Str = DigestUtils.md5Hex(raw);String md5Str = new String(Hex.encodeHex(DigestUtils.md5(raw)));return md5Str;}}


RSA加密

RSA使用公钥加密,在另一端使用私钥加密,这样即使加密的公钥被泄露,对方没有私钥仍然无法正确解密。
下面是RSA加密的几个注意事项:
1、需要导入bcprov-jdk16-1.46.jar;
2、RSA加密的结果是byte字节流,得经过BASE64编码,形成文本字符串后方可正常传输;
3、有时候要对加密前的字符串做reverse倒序处理;


AES加密

AES是设计用来替换DES的高级加密算法。下面是AES算法的代码示例:
import java.security.SecureRandom;import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;public class AesCipher {    private static final String Algorithm = "AES";    private final static String HEX = "0123456789ABCDEF";    private static void appendHex(StringBuffer sb, byte b) {        sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));    }        public static String encrypt(String key, String src) throws Exception {        byte[] rawKey = getRawKey(key.getBytes());        byte[] result = encrypt(rawKey, src.getBytes());        return toHex(result);    }    public static String decrypt(String key, String encrypted) throws Exception {        byte[] rawKey = getRawKey(key.getBytes());        byte[] enc = toByte(encrypted);        byte[] result = decrypt(rawKey, enc);        return new String(result);    }    private static byte[] getRawKey(byte[] seed) throws Exception {        KeyGenerator kgen = KeyGenerator.getInstance(Algorithm);        // SHA1PRNG 强随机种子算法, 要区别4.2以上版本的调用方法         SecureRandom sr = null;       if (android.os.Build.VERSION.SDK_INT >= 17) {         sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");       }else {         sr = SecureRandom.getInstance("SHA1PRNG");       }        sr.setSeed(seed);        kgen.init(256, sr);//256 bits or 128 bits,192bits        SecretKey skey = kgen.generateKey();        byte[] raw = skey.getEncoded();        return raw;    }    private static byte[] encrypt(byte[] key, byte[] src) throws Exception {        SecretKeySpec skeySpec = new SecretKeySpec(key, Algorithm);        Cipher cipher = Cipher.getInstance(Algorithm);        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);        byte[] encrypted = cipher.doFinal(src);        return encrypted;    }        private static byte[] decrypt(byte[] key, byte[] encrypted) throws Exception {        SecretKeySpec skeySpec = new SecretKeySpec(key, Algorithm);        Cipher cipher = Cipher.getInstance(Algorithm);        cipher.init(Cipher.DECRYPT_MODE, skeySpec);        byte[] decrypted = cipher.doFinal(encrypted);        return decrypted;    }        public static String toHex(String txt) {        return toHex(txt.getBytes());    }        public static String fromHex(String hex) {        return new String(toByte(hex));    }    public static byte[] toByte(String hexString) {        int len = hexString.length()/2;        byte[] result = new byte[len];        for (int i = 0; i < len; i++) {            result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();        }        return result;    }        public static String toHex(byte[] buf) {        if (buf == null) {            return "";        }        StringBuffer result = new StringBuffer(2*buf.length);        for (int i = 0; i < buf.length; i++) {            appendHex(result, buf[i]);        }        return result.toString();    }    }


3DES加密

3DES(或称为Triple DES)是三重数据加密算法,它相当于对每个数据块应用三次DES加密算法。因为原先DES算法的密钥长度过短,使得容易遭到破解,所以3DES通过增加密钥的长度,从而防范被暴力破解,因此3DES不是设计全新的密码算法。实际开发中,3DES的密钥必须是24位的字节数组,过短或过长在运行时都会报错“java.security.InvalidKeyException”。另外,3DES加密生成的是字节数组,也得通过BASE64编码为文本字符串。


具体的3DES加密过程,除了密钥不同之外,还存在两种加密方式:
1、使用加密算法“DESede”,此时初始化Cipher对象只需传入密钥;
2、使用加密算法“desede/CBC/PKCS5Padding”,此时初始化Cipher对象除了传入密钥,还需传入一个字节数组的参数对象即IvParameterSpec;


下面是DESede方式的代码示例:
import android.annotation.SuppressLint;import java.io.IOException;import java.io.UnsupportedEncodingException;import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;import com.example.exmencrypt.base64.BASE64Decoder;import com.example.exmencrypt.base64.BASE64Encoder;public class Des3Util {      // 定义加密算法,DESede即3DES      private static final String Algorithm = "DESede";    @SuppressLint("TrulyRandom")    private static byte[] encryptMode(String key, byte[] src) {        try {            SecretKey deskey = new SecretKeySpec(build3DesKey(key), Algorithm);            Cipher cipher = Cipher.getInstance(Algorithm);            cipher.init(Cipher.ENCRYPT_MODE, deskey);            return cipher.doFinal(src);        }catch (Exception e) {            e.printStackTrace();            return null;        }    }    private static byte[] decryptMode(String key, byte[] src) {        try {            SecretKey deskey = new SecretKeySpec(build3DesKey(key), Algorithm);            Cipher cipher = Cipher.getInstance(Algorithm);            cipher.init(Cipher.DECRYPT_MODE, deskey);            return cipher.doFinal(src);        }catch (Exception e) {            e.printStackTrace();            return null;        }    }      //根据字符串生成密钥24位的字节数组    private static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {        byte[] key = new byte[24];        byte[] temp = keyStr.getBytes("UTF-8");          if (key.length > temp.length) {            System.arraycopy(temp, 0, key, 0, temp.length);        }else {            System.arraycopy(temp, 0, key, 0, key.length);        }        return key;    }        public static String encrypt(String key, String raw) {    byte[] enBytes = encryptMode(key, raw.getBytes());    BASE64Encoder encoder = new BASE64Encoder();    return encoder.encode(enBytes);    }        public static String decrypt(String key, String enc) {try {    BASE64Decoder decoder = new BASE64Decoder();byte[] enBytes = decoder.decodeBuffer(enc);    byte[] deBytes = decryptMode(key, enBytes);    return new String(deBytes);} catch (IOException e) {e.printStackTrace();    return enc;}    }}


下面是desede/CBC/PKCS5Padding方式的代码示例:
import android.annotation.SuppressLint;import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.DESedeKeySpec;import javax.crypto.spec.IvParameterSpec;public class Des3Cipher {    private static final String Algorithm = "desede";    // 向量      private final static String iv = "01234567";    // 加解密统一使用的编码方式      private final static String encoding = "utf-8";      @SuppressLint("TrulyRandom")public static String encrypt(String secretKey, String plainText) throws Exception {      SecretKey deskey = null;        DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(Algorithm);        deskey = keyfactory.generateSecret(spec);          Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");        IvParameterSpec ips = new IvParameterSpec(iv.getBytes());        cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);        byte[] encryptData = cipher.doFinal(plainText.getBytes(encoding));        return Base64Util.encode(encryptData);    }        public static String decrypt(String secretKey, String encryptText) throws Exception {      SecretKey deskey = null;        DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(Algorithm);        deskey = keyfactory.generateSecret(spec);                Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");        IvParameterSpec ips = new IvParameterSpec(iv.getBytes());        cipher.init(Cipher.DECRYPT_MODE, deskey, ips);        byte[] decryptData = cipher.doFinal(Base64Util.decode(encryptText));        return new String(decryptData, encoding);    }  }



点击下载本文用到的数据加密算法的工程代码



点此查看Android开发笔记的完整目录
0 0
原创粉丝点击