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
- Android开发笔记(七十二)数据加密算法
- Android 数据加密算法
- Android 数据加密算法总结
- (七十二)while循环
- iOS开发-数据加密算法AES
- 技术分享连载(七十二)
- 【Android数据加密与完整性校验之RSA加密算法】Android应用开发中如何使用RSA加密算法对数据进行校验
- Android Api Demos登顶之路(七十二)Graphics-->Color Filters
- Android应用开发中如何使用RSA加密算法对数据进行校验
- Android应用开发中如何使用RSA加密算法对数据进行校验
- Android数据加密之异或加密算法
- Android数据加密之异或加密算法
- Android数据加密之异或加密算法
- Android开发笔记(二十九)使用SharedPreferences存取数据
- Android开发笔记(五十四)数据共享接口ContentProvider
- Android 应用安全开发之浅谈加密算法
- 数据加密算法
- 数据加密算法
- android 一个手机可以打开 另一个手机打开就崩溃
- HTML5移动开发实战必备知识——本地存储(2)
- nodejsURL
- Android 反编译
- mac 打开.ashx
- Android开发笔记(七十二)数据加密算法
- android学习之RadioButton
- C语言中fflush函数的使用方法
- android中SimpleAdapter的编程实例
- Java 回顾笔记8内部类
- INSTALL_FAILED_SHARED_USER_INCOMPATIBLE错误解决
- android sqlite查询方式
- openGL的光照与材料(一)
- android studio gradle介绍