一,数据加密方式
BASE64:编码方式(8位字节代码),二进制与字符串相互转换
MD5:Message Algorithm(消息摘要算法第五版),散列函数(哈希算法)_不可逆,压缩性
DES:Data Encrytion Standard(数据加密标准),对应算法是DEA
特点:1. 对称加密 2. 同一个SK
AES:Advanced Encrytion Standard(高级加密标准)
特点:1. 对称加密 2. 一个SK扩展成多个子SK,轮加密
RSA:特点:
1. 非对称加密,即:PK与SK不是同一个
2. PK用于加密,SK用于解密
3. PK决定SK,但是PK很难算出SK(数学原理:两个大质数相乘,积很难因式分解)
4. 速度慢,只对少量数据加密
DES加密:
AES加密:
RSA加密:
SSL使用RSA:
加密相关方法及api
1,MessageDigest是Java自带的类
MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。
MessageDigest 对象开始被初始化。该对象通过使用 update()方法处理数据。任何时候都可以调用 reset()方法重置摘要。一旦所有需要更新的数据都已经被更新了,应该调用digest() 方法之一完成哈希计算。
2,Java cipher加密与解密
https://blog.csdn.net/sweetgirl520/article/details/78189742
ENCRYPT_MODE,加密数据
DECRYPT_MODE,解密数据
WRAP_MODE,将一个Key封装成字节,可以用来进行安全传输
UNWRAP_MODE,将前述已封装的密钥解开成java.security.Key对象
3,SecretKeySpec类
SecretKeySpec类是KeySpec接口的实现类,用于构建秘密密钥规范。可根据一个字节数组构造一个SecretKey.
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");//// 定义加密算法,通过AES算法得到的密钥
4, IvParameterSpec
如果加密时采用DES/CBC/PKCS5Padding时,且使用了:
IvParameterSpec iv = new IvParameterSpec("12345678".getBytes("UTF-8"));
https://blog.csdn.net/jjwwmlp456/article/details/20960029
二,项目中的加密
例一:
接口传输的参数只支持两个参数“si”和“pa”。
“si”参数:原始参数+合作商标识,udid,版本号,时间戳,手机系统类型等拼接成key=value字符进行MD5。
“pa”参数:原始参数+合作商标识,udid,版本号,时间戳,手机系统类型等拼接成key=value字符转换为Json进行DES加密,并进行Base64编码.
参数传递以及数据返回格式统一采用Json的方式进行传输。
如:http://{域名}/api/{接口标识}/{接口方法}?si={MD5}&pa={BASE64}
JSONObject paObject //所有的请求参数
HashMap param = new HashMap();
Iterator it = paObject.keys();
while (it.hasNext()) {
String key = it.next().toString();
param.put(key, paObject.getString(key));
}
String si = DetectTool.getSign(param);
String pa = EncryptUtil.encrypt(paObject.toString());
//MD5加密
public static String getSign(HashMap params){
Log.e("11111111111111111", params.toString());
// 先将参数以其参数名的字典序升序进行排序
Map sortedParams = new TreeMap(params);
Set> entrys = sortedParams.entrySet();
// 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
StringBuilder basestring = new StringBuilder();
for (Entry param : entrys) {
basestring.append(param.getKey()).append("=").append(param.getValue());
}
Log.e("11111111111111111", basestring.toString());
/*****************对排序后的参数进行MD5散列函数运算***********************/
byte[] hash;
try {
hash = MessageDigest.getInstance("MD5").digest(basestring.toString().getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Huh, MD5 should be supported?", e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Huh, UTF-8 should be supported?", e);
}
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10) hex.append("0");
hex.append(Integer.toHexString(b & 0xFF));
}
/*****************对排序后的参数进行MD5散列函数运算***********************/
//返回md5加密后的字符串注意统一转化为大写
return hex.toString().toUpperCase();
}
//base64 加密
public static String encrypt(String input) throws Exception {
return base64Encode(desEncrypt(input.getBytes()));
}
private static String base64Encode(byte[] s) {
if (s == null) {
return null;
}
BASE64Encoder b = new BASE64Encoder();
return b.encode(s);
}
例二:
接口参数 Sign 类型String : 接口签名,验证请求是否合法
接口参数 params 类型String : AES加密的json字符串,封装了所有的参数Json格式为 {“account”:”tome”,”password”,”123456”}
//map转string
String paramsJson = new Gson().toJson(paramMap);
//获取时间戳
String timeStamp = getTimeStampStr();
//请求参数
Map params = new HashMap<>();
params.put("sign", getSign(timeStamp, paramsJson));
params.put("timeStamp", timeStamp);
params.put("params", encrypt(paramsJson));
// 数据加密密钥
private static final String KEY = "~!]'/78m[;.QWEh6";
//生成签名的干扰盐值
private static final String SALT = "~!QAZpl,123sdd4jbr5IJN@#,./[;.[]";
// 初始化向量
private static final String IV = "=RFGpl,$%^098xbg";
//
private String getSign(String timeStamp, String paramsJson) {
String str = timeStamp + SALT + paramsJson;
return MD5Util.getMD5(str).toUpperCase();
}
//对字符串md5加密
public static String getMD5(String str) {
byte[] hash = null;
try {
hash = MessageDigest.getInstance("MD5").digest(str.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
} catch (UnsupportedEncodingException e) {
}
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10) hex.append("0");
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
}
//方法二: md5加密
public final static String MD5(String s, String encodingType) {
char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
try {
// 按照相应编码格式获取byte[]
byte[] btInput = s.getBytes(encodingType);
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return "-1";
}
}
// AES加密的json字符串
private String encrypt(String paramsJson) {
String enValue = "";
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] raw = KEY.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
IvParameterSpec ips = new IvParameterSpec(IV.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ips);
byte[] encrypted = cipher.doFinal(paramsJson.getBytes("utf-8"));
enValue = Base64.encodeToString(encrypted, Base64.DEFAULT);// 此处使用BASE64做转码。
} catch (Exception e) {
e.printStackTrace();
}
return enValue;
}
//获取时间戳
protected String getTimeStampStr() {
return String.valueOf(DateFormatUtils.formatDate(new Date().getTime(), "yyyy-MM-dd HH:mm:ss"));
}
===================请求加密的参数======================
token:756CDE7185783065638C9DCB142F00F1
params:yfOCeqjjrgFIWNffMVVMDQ==
timeStamp:2018-09-06 13:46:31
sign:FC9714BA81403836D0D75D23465C7ACF
===================请求加密的参数======================
例三:
参数传递以及数据返回格式统一采用Json的方式进行传输。
签名说明:服务器获取请求参数后,排除掉sign参数后, 对剩下所有参数按照参数名进行升序排序,然后构造成a=1&b=2&c=3&d=4格式后, 进行MD5加密
//所有的参数json
JSONObject paObject = getPaObject(params);
HashMap map = new HashMap();
Iterator it = paObject.keys();
while (it.hasNext()) {
String key = it.next();
map.put(key, paObject.getString(key));
}
/****************数据加密*****************/
String si = DetectTool.getSign(map);
String pa = DetectTool.getPara(paObject);
/****************数据加密*****************/
//okthhp网络请求
FormBody.Builder encodingBuilder = new FormBody.Builder();
Iterator iterator = paObject.keys();
while (iterator.hasNext()) {
String key = iterator.next();
encodingBuilder.add(key, paObject.getString(key));
}
encodingBuilder.add("sign", si);
encodingBuilder.add("param", paObject.toString());
RequestBody body = encodingBuilder.build();
builder.url(url);
builder.post(body);
public static String getSign(Map params) {
// 先将参数以其参数名的字典序升序进行排序
Map sortedParams = new TreeMap(params);
Set> entrys = sortedParams.entrySet();
// 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
StringBuilder basestring = new StringBuilder();
for (Map.Entry param : entrys) {
basestring.append(param.getKey()).append("=").append(param.getValue());
}
/*****************对排序后的参数进行MD5散列函数运算***********************/
String hex = EncryptUtils.encryptMD5ToString(basestring.toString());
/*****************对排序后的参数进行MD5散列函数运算***********************/
//返回md5加密后的字符串注意统一转化为大写
return hex.toString().toUpperCase();
}
/**
* MD5加密
*
* @param data 明文字符串
* @return 16进制密文
*/
public static String encryptMD5ToString(String data) {
return encryptMD5ToString(data.getBytes());
}
/**
* MD5加密
*
* @param data 明文字节数组
* @return 16进制密文
*/
public static String encryptMD5ToString(byte[] data) {
return ConvertUtils.bytes2HexString(encryptMD5(data));
}
/**
* MD5加密
*
* @param data 明文字节数组
* @return 密文字节数组
*/
public static byte[] encryptMD5(byte[] data) {
return hashTemplate(data, "MD5");
}
/**
* hash加密模板
*
* @param data 数据
* @param algorithm 加密算法
* @return 密文字节数组
*/
private static byte[] hashTemplate(byte[] data, String algorithm) {
if (data == null || data.length <= 0) return null;
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
md.update(data);
return md.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* MD5加密
*
* @param data 明文字节数组
* @return 16进制密文
*/
public static String encryptMD5ToString(byte[] data) {
return ConvertUtils.bytes2HexString(encryptMD5(data));
}
/**
* byteArr转hexString
* 例如:
* bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns 00A8
*
* @param bytes 字节数组
* @return 16进制大写字符串
*/
public static String bytes2HexString(byte[] bytes) {
if (bytes == null) return null;
int len = bytes.length;
if (len <= 0) return null;
char[] ret = new char[len << 1];
for (int i = 0, j = 0; i < len; i++) {
ret[j++] = hexDigits[bytes[i] >>> 4 & 0x0f];
ret[j++] = hexDigits[bytes[i] & 0x0f];
}
return new String(ret);
}
public static String getPara(@NonNull JSONObject paObject) {
return EncryptUtils.encryptDES2Base64(paObject.toString());
}
//秘钥
public static String strkey = "12345678";
/**
* DES加密后转为Base64编码字符串,使用默认秘钥
*
* @param input 明文
* @return
*/
public static String encryptDES2Base64(String input) {
return EncodeUtils.base64Encode2String(encryptDES(input.getBytes(), strkey));
}
/**
* des加密
*
* @param datasource byte[]
* @param password String
* @return byte[]
*/
public static byte[] encryptDES(byte[] datasource, String password) {
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes());
//创建一个密匙工厂,然后用它把DESKeySpec转换成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
//Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES");
//用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
//现在,获取数据并加密
//正式执行加密操作
return cipher.doFinal(datasource);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* Base64编码
*
* @param input 要编码的字节数组
* @return Base64编码后的字符串
*/
public static String base64Encode2String(byte[] input) {
return Base64.encodeToString(input, Base64.NO_WRAP);
}