Andriod和java后台通信加密----RSA+AES加密通信

安卓apk反编译的问题很让人头疼,对于一些机密的数据,不加密传输要是被提取出来是会造成巨大损失,研究了两种方式(相似的)

第一种:

1 首先需要有一对RSA的公钥和私钥 , 然后私钥留在服务器,公钥随apk发布(即安卓端写成文件,用的是时候读取,我感觉不是绝对安全,但相对方便);

2 通信的时候,首先由android端,随机生成一个字符串作为AES加密算法的key,用AES加密算法来加密与服务器传输的主要内容(因为AES速度比较快);

3 然后客户端再使用RSA的公钥将AES的key进行加密,与AES加密后的内容一同传输给服务器; 

4 服务器端先用RSA的私钥将AES的key进行解密,然后使用这个key来解密传输的内容;

5 需要注意的是,android端的AES加密算法和服务器的AES加密算法的默认序列(默认序列就是决定根据传入key生成真正加解密key的一个东西,类似c++生成随机数的玩意)是不同的,所以网上的那些AES加密算法都只适合android和android,服务器和服务器之间的使用,不适合android和服务器之间使用;

第二种(我个人认为非常安全,但是效率可能没这么高):

1 首先安卓程序打开的时候携带imsi和公钥(生成方式自己定,可以每次换,但是我觉得可以每天或者一段时间换一次)请求java接口;

2 然后java端用安卓的公钥加密AES的key,返回给安卓端;

3 然后安卓端再使用AES的key加密数据加密后的内容传输给服务器; 

4 服务器端解密传输的内容(key可以服务端定期更换);

上代码:

安卓AES:


import android.util.Base64;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * Created by Administrator on 2018/10/14.
 */

public class Aes {


    private static String AesKey = "12345678910Asdfx";// 密钥
    private static String ivParameter = "12345678910Asdfx";// 密钥默认偏移,可更改
    public static String Jie_Mi(String encData)  throws Exception {
        //获取AESkey
        Key secretKey = new SecretKeySpec(AesKey.getBytes(), "AES"); //密钥
        //获取加密工具
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //初始化加密工具
        cipher.init(Cipher.DECRYPT_MODE,secretKey,new IvParameterSpec(ivParameter.getBytes()));
        //还原文本框的base64文本为密文
        byte[] bytes = Base64.decode(encData, Base64.DEFAULT);
        //把密文解密为明文
        byte[] bytes1  =cipher.doFinal(bytes);
        return new String(bytes1);
    }

    public static String Jia_Mi(String srcData)  throws Exception {
        //获取AESkey
        Key secretKey = new SecretKeySpec(AesKey.getBytes(), "AES"); //密钥
        //获取加密工具
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //初始化加密工具
        cipher.init(Cipher.ENCRYPT_MODE,secretKey,new IvParameterSpec(ivParameter.getBytes()));
        //放入我们要加密的内容 并加密
        byte[] bytes = cipher.doFinal(srcData.getBytes());
        //得到的字节在进行Base64换算
        byte[] base = Base64.encode(bytes,Base64.DEFAULT);
        return new String(base).replaceAll("(\r\n|\r|\n|\n\r)", "");
    }
    public static String buildReqStr(String data) {
        String dataNew = data.replace("\\n", "");
        String origin = "{\"data\":\"" + dataNew + "\"}";
        return origin;
    }

}

javaAES:

加密:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Encoder;

public class Base64AesEncrypt {

    /**
     * BASE64加密
     * @param base64Content	被加密的字符串
     * @return
     */
    public static String encryptBASE64(String base64Content) {
        byte[] bt = base64Content.getBytes();
        String aesContent = (new BASE64Encoder()).encodeBuffer(bt);
        return aesContent;
    }

    /**
     * AES加密
     * @param aesContent	被Base64加密过的字符串
     * @param key			秘钥
     * @param ivParameter	偏移量
     * @return
     */
    public static String encryptAES(String aesContent,String key, String ivParameter) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] raw = key.getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(aesContent.getBytes("utf-8"));
            return new BASE64Encoder().encode(encrypted);//此处使用BASE64做转码。
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

解密:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;

public class Base64AesDecipher {
    /**
     * base64解密
     * @param content	被AES解密过的字符串
     * @return
     */
    public static String DecipherBase64(String content){
        byte[] b = null;
        String result = null;
        if (content != null) {
            BASE64Decoder decoder = new BASE64Decoder();
            try {
                b = decoder.decodeBuffer(content);
                result = new String(b, "utf-8");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * @param content		被Base64+AES加密过的字符串
     * @param aesKey		秘钥
     * @param ivParameter	偏移量
     * @return
     */
    public static String decryptAES(String content, String aesKey,String ivParameter) {
        try {
            byte[] raw = aesKey.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(content);//先用base64解密
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original,"utf-8");
            return originalString;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

}

RAS加密:

public class RSAUtils {
 
	/**
	 * 生成公钥和私钥
	 */
	public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException {
		HashMap<String, Object> map = new HashMap<String, Object>();
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
		keyPairGen.initialize(1024);
		KeyPair keyPair = keyPairGen.generateKeyPair();
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		map.put("public", publicKey);
		map.put("private", privateKey);
		return map;
	}
 
	/**
	 * 公钥加密
	 */
	public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception {
		/* 这块将padding变成和服务器默认的一致 */
		Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		// 模长
		int key_len = publicKey.getModulus().bitLength() / 8;
		// 加密数据长度 <= 模长-11
		String[] datas = splitString(data, key_len - 11);
		String mi = "";
		// 如果明文长度大于模长-11则要分组加密
		for (String s : datas) {
			mi += bcd2Str(cipher.doFinal(s.getBytes()));
		}
		return mi;
	}
 
	/**
	 * 私钥解密
	 */
	public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		// 模长
		int key_len = privateKey.getModulus().bitLength() / 8;
		byte[] bytes = data.getBytes();
		byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
		// 如果密文长度大于模长则要分组解密
		String ming = "";
		byte[][] arrays = splitArray(bcd, key_len);
		for (byte[] arr : arrays) {
			ming += new String(cipher.doFinal(arr));
		}
		return ming;
	}
 
	/**
	 * ASCII码转BCD码
	 *
	 */
	public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
		byte[] bcd = new byte[asc_len / 2];
		int j = 0;
		for (int i = 0; i < (asc_len + 1) / 2; i++) {
			bcd[i] = asc_to_bcd(ascii[j++]);
			bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
		}
		return bcd;
	}
 
	public static byte asc_to_bcd(byte asc) {
		byte bcd;
		if ((asc >= '0') && (asc <= '9'))
			bcd = (byte) (asc - '0');
		else if ((asc >= 'A') && (asc <= 'F'))
			bcd = (byte) (asc - 'A' + 10);
		else if ((asc >= 'a') && (asc <= 'f'))
			bcd = (byte) (asc - 'a' + 10);
		else
			bcd = (byte) (asc - 48);
		return bcd;
	}
 
	/**
	 * BCD转字符串
	 */
	public static String bcd2Str(byte[] bytes) {
		char temp[] = new char[bytes.length * 2], val;
		for (int i = 0; i < bytes.length; i++) {
			val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
			temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
 
			val = (char) (bytes[i] & 0x0f);
			temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
		}
		return new String(temp);
	}
 
	/**
	 * 拆分字符串
	 */
	public static String[] splitString(String string, int len) {
		int x = string.length() / len;
		int y = string.length() % len;
		int z = 0;
		if (y != 0) {
			z = 1;
		}
		String[] strings = new String[x + z];
		String str = "";
		for (int i = 0; i < x + z; i++) {
			if (i == x + z - 1 && y != 0) {
				str = string.substring(i * len, i * len + y);
			} else {
				str = string.substring(i * len, i * len + len);
			}
			strings[i] = str;
		}
		return strings;
	}
 
	/**
	 * 拆分数组
	 */
	public static byte[][] splitArray(byte[] data, int len) {
		int x = data.length / len;
		int y = data.length % len;
		int z = 0;
		if (y != 0) {
			z = 1;
		}
		byte[][] arrays = new byte[x + z][];
		byte[] arr;
		for (int i = 0; i < x + z; i++) {
			arr = new byte[len];
			if (i == x + z - 1 && y != 0) {
				System.arraycopy(data, i * len, arr, 0, y);
			} else {
				System.arraycopy(data, i * len, arr, 0, len);
			}
			arrays[i] = arr;
		}
		return arrays;
	}
 
 
	/**
	 * 使用模和指数生成RSA公钥
	 * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
	 * /None/NoPadding】
	 *
	 * @param modulus
	 *            模
	 * @param exponent
	 *            指数
	 * @return
	 */
	public static RSAPublicKey getPublicKey(String modulus, String exponent) {
		try {
			BigInteger b1 = new BigInteger(modulus);
			BigInteger b2 = new BigInteger(exponent);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
			return (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
 
	/**
	 * 使用模和指数生成RSA私钥
	 * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
	 * /None/NoPadding】
	 *
	 * @param modulus
	 *            模
	 * @param exponent
	 *            指数
	 * @return
	 */
	public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
		try {
			BigInteger b1 = new BigInteger(modulus);
			BigInteger b2 = new BigInteger(exponent);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
			return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

需要注意的是安卓和java这里不太一样

//安卓
//        Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding",new BouncyCastleProvider());
//java
        Cipher cipher = Cipher.getInstance("RSA");

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值