数据加密常用算法介绍

前言

用户数据无论保存在SharePreferences,还是保存在SQLite数据库里,都有必要对关键数据进行加密。加密算法多种多样。常见的有MD5、RSA、AES、3DES。

1.MD5加密

MD5是不可逆的加密算法,也就是无法解密,主要用于客户端的用户密码加密,MD5算法的加密代码如下:

public class MD5Util{
          public static String encryp(String raw){
                     String md5Str=raw;
                     try{
                     MessageDigest md = MessageDigest.getInstance("MD5");
                     md.update(raw.getBytes());
                     byte[] encryContext=md.digets();
                     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.RSA加密

RSA算法在客户端使用公钥加密,在服务端使用私钥解密。这样一来,即使加密的公钥被泄露,没有私钥仍然无法解密。
下面是RSA加密的3个注意事项。

(1)需要导入加密算法的依赖包bcprov-jdk16-1.46.jar,该jar包要放在当前模块的libs目录下。
(2)RSA在加密的结果是字节数组,经过BASE64编码才能形成最终的加密字符串
(3)根据需求要对加密前的字符串做reverse倒序处理。

public class RSAUtil {
	private static final String TAG = "RSAUtil";
	private static final String Algorithm = "RSA";
	private static String RSAKeyStore = "E:/RSAKey.txt";

生成密钥对
	private static KeyPair generateKeyPair() throws Exception {
		try {
			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(Algorithm,
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
 这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会降低
			final int KEY_SIZE = 1024;
			keyPairGen.initialize(KEY_SIZE, new SecureRandom());
			KeyPair keyPair = keyPairGen.generateKeyPair();
			saveKeyPair(keyPair);
			return keyPair;
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}

	private static KeyPair getKeyPair() throws Exception {
		FileInputStream fis = new FileInputStream(RSAKeyStore);
		ObjectInputStream oos = new ObjectInputStream(fis);
		KeyPair kp = (KeyPair) oos.readObject();
		oos.close();
		fis.close();
		return kp;
	}

	private static void saveKeyPair(KeyPair kp) throws Exception {
		FileOutputStream fos = new FileOutputStream(RSAKeyStore);
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(kp);
		oos.close();
		fos.close();
	}

生成公钥
	private static RSAPublicKey generateRSAPublicKey(byte[] modulus,
			byte[] publicExponent) throws Exception {
		KeyFactory keyFac = null;
		try {
			keyFac = KeyFactory.getInstance(Algorithm,
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
		} catch (NoSuchAlgorithmException ex) {
			throw new Exception(ex.getMessage());
		}

		RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
				modulus), new BigInteger(publicExponent));
		try {
			return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
		} catch (InvalidKeySpecException ex) {
			throw new Exception(ex.getMessage());
		}
	}

生成私钥
	private static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
			byte[] privateExponent) throws Exception {
		KeyFactory keyFac = null;
		try {
			keyFac = KeyFactory.getInstance(Algorithm,
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
		} catch (NoSuchAlgorithmException ex) {
			throw new Exception(ex.getMessage());
		}

		RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
				modulus), new BigInteger(privateExponent));
		try {
			return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
		} catch (InvalidKeySpecException ex) {
			throw new Exception(ex.getMessage());
		}
	}

 通过公钥byte[]将公钥还原,适用于RSA算法
	private static PublicKey getPublicKey(byte[] keyBytes)
			throws NoSuchAlgorithmException, InvalidKeySpecException {
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(Algorithm);
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}

 通过私钥byte[]将公钥还原,适用于RSA算法
	private static PrivateKey getPrivateKey(byte[] keyBytes)
			throws NoSuchAlgorithmException, InvalidKeySpecException {
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(Algorithm);
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}

	加密
	private static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
		try {
			Cipher cipher = Cipher.getInstance(Algorithm,
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
			cipher.init(Cipher.ENCRYPT_MODE, pk);
			int blockSize = cipher.getBlockSize();
			int outputSize = cipher.getOutputSize(data.length);
			int leavedSize = data.length % blockSize;
			int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
					: data.length / blockSize;
			byte[] raw = new byte[outputSize * blocksSize];
			int i = 0;
			while (data.length - i * blockSize > 0) {
				if (data.length - i * blockSize > blockSize) {
					cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
				} else {
					cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
				}
				i++;
			}
			return raw;
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}

	//解密
	private static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
		try {
			Cipher cipher = Cipher.getInstance(Algorithm,
					new org.bouncycastle.jce.provider.BouncyCastleProvider());
			cipher.init(cipher.DECRYPT_MODE, pk);
			int blockSize = cipher.getBlockSize();
			ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
			int j = 0;

			while (raw.length - j * blockSize > 0) {
				bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
				j++;
			}
			return bout.toByteArray();
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}

	// 使用N、e值还原公钥
	private static PublicKey getPublicKey(String modulus, String publicExponent, int radix)
			throws NoSuchAlgorithmException, InvalidKeySpecException {
		BigInteger bigIntModulus = new BigInteger(modulus, radix);
		BigInteger bigIntPrivateExponent = new BigInteger(publicExponent, radix);
		RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus,
				bigIntPrivateExponent);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}

	// 使用N、d值还原私钥
	private static PrivateKey getPrivateKey(String modulus, String privateExponent, int radix)
			throws NoSuchAlgorithmException, InvalidKeySpecException {
		BigInteger bigIntModulus = new BigInteger(modulus, radix);
		BigInteger bigIntPrivateExponent = new BigInteger(privateExponent, radix);
		RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(bigIntModulus,
				bigIntPrivateExponent);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}

	//加密函数
	public static String encodeRSA(RSAKeyData key_data, String src) {
		if (key_data == null) {
			//默认的密钥对
			key_data = new RSAKeyData();
			key_data.public_key = "10001";
			key_data.private_key = "";
			key_data.modulus = "c7f668eccc579bb75527424c21be31c104bb44c921b4788ebc82cddab5042909eaea2dd706431531392d79890f9091e13714285a7e79e9d1836397f847046ef2519c9b65022b48bf157fe409f8a42155734e65467d04ac844dfa0c2ae512517102986ba9b62d67d4c920eae40b2f11c363b218a703467d342faa81719f57e2c3";
			key_data.radix = 16;
		}
		try {
			PublicKey key = getPublicKey(key_data.modulus, key_data.public_key, key_data.radix);
			String rev = encodeURL(new StringBuilder(src).reverse().toString());
			byte[] en_byte = encrypt(key, rev.getBytes());
			String base64 = encodeURL(ConvertBytesToBase64.BytesToBase64String(en_byte));
			return base64;
		} catch (Exception e) {
			e.printStackTrace();
			return "RSA加密失败";
		}
	}

	//URL编码
	private 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解码
	private 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;
	}

	public static class RSAKeyData {
		public String modulus;
		public String public_key;
		public String private_key;
		public int radix;

		public RSAKeyData() {
			modulus = "";
			public_key = "";
			private_key = "";
			radix = 0;
		}
	}

}

3.AES加密

AES是设计用来替换DES的高级加密算法。(该算法是可逆算法,支持对加密字符串进行解密,前提是解密是密钥必须与加密是一致)。
下面是该算法加密和解密的代码

public class AesUtil {

	private static final String Algorithm = "AES";
	private final static String HEX = "0123456789ABCDEF";

	//加密函数。key为密钥
	public static String encrypt(String key, String src) throws Exception {
		byte[] rawKey = getRawKey(key.getBytes());
		byte[] result = encrypt(rawKey, src.getBytes());
		return toHex(result);
	}

	//解密函数。key值必须和加密时的key一致
	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 void appendHex(StringBuffer sb, byte b) {
		sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
	}

	private static byte[] getRawKey(byte[] seed) throws Exception {
		KeyGenerator kgen = KeyGenerator.getInstance(Algorithm);
		// SHA1PRNG 强随机种子算法, 要区别Android 4.2.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位或128位或192位
		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;
	}

	private 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;
	}

	private 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();
	}

}

4. 3DES加密

3DES(tripe DES)是三重数据加密算法,相当于对每个数据块应用3次DES加密算法。3DE算法通过增加密钥的长度防范加密数据被破解。在实际开发时候,3DES的密钥必须是24位的字节数组,过短过长在运行时都会报错java.security.InvalidKeyException。另外,3DES加密生成的是字节数组,也得通过BASE64编码位文本形式的加密字符串。
该算法的加密和解密代码如下:

public class Des3Util {
	  
    // 定义加密算法,DESede即3DES  
    private static final String Algorithm = "DESede";

	//加密函数。key为密钥
    public static String encrypt(String key, String raw) {
    	byte[] enBytes = encryptMode(key, raw.getBytes());
    	BASE64Encoder encoder = new BASE64Encoder();
    	return encoder.encode(enBytes);
    }

	//解密函数。key值必须和加密时的key一致
    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;
		}
    }

    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;
    }
    
}

下篇将分析对APK安装包安全加固过程

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值