使用时,只需要跟android端和后端定义好里面的编码表即可。
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: Base64Custom
* @Description: base64自定义加密
* @author: xiaofei
*/
public class Base64Custom {
/**
* 编码表
*/
private static final byte[] STANDARD_ENCODE_TABLE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
/**
* 替换16进制的后六位字母
*/
public static final HashMap<Integer, String> hexMap = new HashMap<>();
static {
hexMap.put(10, "A");
hexMap.put(11, "B");
hexMap.put(12, "C");
hexMap.put(13, "D");
hexMap.put(14, "E");
hexMap.put(15, "F");
}
/**
* 加密
*/
public static class Encoder {
/**
* 加密
*
* @param str 加密字符串
* @return
*/
public static String encode(String str) {
return encode(str.getBytes());
}
public static String encode(byte[] b) {
String strArr[] = new String[b.length];
for (int i = 0; i < b.length; i++) {
strArr[i] = decimalToOther(2, String.valueOf((byte) b[i] & 0xff));
}
String encodeByte = encode0(strArr);
return encodeByte;
}
/**
* Base 64 编码规则:
* --:错误1.将byte数组中的值转为二进制,将所有二进制数的长度相加,看长度是否为8的倍数,如果不足,则在每个数组元素的二进制前面补0,直到长度满足8的倍数
* 1. 将byte数组的值转为二进制并放入数组,将数组中的每个元素的长度变成8个bit位,(即如果长度是6,则在值前面补两个0),最后按顺序拼接成一个完整的字符串
* 2.将字符串以6位分组,不足的,要在末尾补0,达到6的倍数(记下补0的次数)
* 3.将 每个分组的字符串拿出来,转为十进制以这个为下标,去查表,取得所需的对应编码值
* 4.将值(可以拼接成字符串,也可以byte数组的形式返回)如果第二部在末尾补0了,每补"00",就在值后拼接一个'='
*
* @param binaryStrArr
* @return
*/
private static String encode0(String[] binaryStrArr) {
// 标记第二部,以6分组加 0 的次数
int len = 0;
String binaryStr = "";
int strArrLength = getStringArrLength(binaryStrArr);
// 将二进制的编码,以8位为一组,//不足的前面补0
for (int i = 0; i < binaryStrArr.length; i++) {
binaryStrArr[i] = addZeroFirst(binaryStrArr[i], 8);
}
binaryStr = getLongStrToStrArr(binaryStrArr);
// 分成6 位一组的字符串,不足末尾补0
int mod6 = binaryStr.length() % 6;
if (mod6 != 0) {
len = 6 - mod6;
binaryStr = binaryStr.concat(addZero(len));
}
// 按6个长度分组
String[] splitForNum = splitForLength(binaryStr, 6);
StringBuffer sbf = new StringBuffer();
int lastLen = len / 2;
// 将截取的二进制字符串 转十进制
for (int i = 0; i < splitForNum.length; i++) {
int index = Integer.valueOf(otherToDecimal(2, splitForNum[i]));
sbf.append((char) STANDARD_ENCODE_TABLE[index]);
}
// 每加 00;则输出结果 加 =
for (int i = splitForNum.length; i < splitForNum.length + lastLen; i++) {
sbf.append('=');
}
return sbf.toString();
}
}
/**
* 解密
*/
public static class Decoder {
/**
* 解密
*
* @param str 解密字符串
* @return
*/
public static String decodeByte(String str) {
String longStr = decode0(str);
// 按8分组
String[] binaryEightStr = splitForLength(longStr, 8);
byte[] b = new byte[binaryEightStr.length];
for (int i = 0; i < binaryEightStr.length; i++) {
// 去除前面多余的0
binaryEightStr[i] = removeStartingNumStr(binaryEightStr[i], 0);
// 转为十进制
int decimalValue = Integer.valueOf(otherToDecimal(2, binaryEightStr[i]));
b[i] = (byte) decimalValue;
}
return new String(b);
}
/**
* 1. 去除字符串中的"=",并记录下"="出现的次数
* 2. 去除后的字符串,分成字符串数组,每个值去查 base64标准表,得到对应的下标索引,放入到一个数组中
* 3. 将数组拼接成一个完整的二进制字符串,并且去除末尾多余的0(通过"="出现的次数*2)
*
* @return
*/
private static String decode0(String str) {
int indexOf = str.indexOf("=");
int equalsCount = 0;
if (indexOf != -1) {
str = str.substring(0, indexOf);
equalsCount = str.length() - indexOf;
}
byte[] bytes = str.getBytes();
String[] strArr = new String[bytes.length];
String[] binaryStrArr = new String[bytes.length];
for (int i = 0; i < bytes.length; i++) {
// 返回 -1 的原因,二分查找,要求查找的数组是有序的....
strArr[i] = String.valueOf(searchIndex(STANDARD_ENCODE_TABLE, bytes[i]));
String strIndex = decimalToOther(2, strArr[i]);
binaryStrArr[i] = addZeroFirst(strIndex, 6);
}
String longStr = getLongStrToStrArr(binaryStrArr);
// 去除末尾添加的0
longStr.substring(0, longStr.length() - (equalsCount << 1));
return longStr;
}
}
/* ******************************** 公共方法 ******************************** */
/**
* 无序数组的查找
* 如果是有序的,Arrays.binarySearch()二分查找
*
* @param b
* @param key
* @return 返回该元素在数组中的下标, 如果有数组中要查询的值有多个, 则返回第一次出现的索引 -1:表示数组中不存在该值
*/
public static int searchIndex(byte[] b, byte key) {
byte[] b2 = {key};
String str = new String(b);
String keyStr = new String(b2);
if (str.contains(keyStr)) {
return str.indexOf(keyStr);
} else {
return -1;
}
}
/**
* 返回string 的单个字符的String 数组形式,而不是字符数组形式
*
* @param str
* @return
*/
public static String[] getStrings(String str) {
int j = str.length();
String[] strArr = new String[j];
for (int i = 0; i < j; i++) {
strArr[i] = str.substring(i, i + 1);
}
return strArr;
}
/**
* 反转
*
* @param result
* @return
*/
public static String reverse(String result) {
StringBuffer sbf = new StringBuffer();
for (int i = 0, j = result.length(); i < j; i++) {
sbf.append(result.substring(j - i - 1, j - i));
}
return sbf.toString();
}
/**
* 返回传入的数量的"0"字符串
*
* @param size
* @return
*/
public static String addZero(int size) {
StringBuffer sbf = new StringBuffer();
for (int i = 0; i < size; i++) {
sbf.append("0");
}
return sbf.toString();
}
/**
* 根据位数自动添加缺少的0,将0补在开头
* 补全二进制的0
*
* @return 返回补全后的字符串
*/
public static String addZeroFirst(String str, int num) {
int mod = str.length() % num;
int len = 0;
if (mod == 0) {
return str;
} else if (mod != 0) {
len = num - mod;
}
StringBuffer sbf = new StringBuffer();
for (int i = 0; i < len; i++) {
sbf.append("0");
}
return sbf.toString().concat(str);
}
/**
* 根据传入长度截取字符串,返回字符串数组
* 注意,位数不够的请自行补0
*
* @param str
* @param num
* @return
*/
public static String[] splitForLength(String str, int num) {
String[] strArr = new String[str.length() / num];
for (int i = 0; i < strArr.length; i++) {
strArr[i] = str.substring((0 + i) * num, (1 + i) * num);
}
return strArr;
}
/**
* 获得string数组的数组各个元素的长度之和
*
* @param strArr
* @return
*/
public static int getStringArrLength(String[] strArr) {
int count = 0;
for (String str : strArr) {
count += str.length();
}
return count;
}
/**
* 获得字符串数组的各个下标拼接的长字符串
*
* @param strArr
* @return
*/
public static String getLongStrToStrArr(String[] strArr) {
return getLongStrToIndex(strArr, 0, strArr.length);
}
public static String getLongStrToIndex(String[] strArr, int startIndex, int endIndex) {
String longStr = "";
for (int i = startIndex; i < endIndex; i++) {
longStr += strArr[i];
}
return longStr;
}
/**
* 去除以特定数字开头的子字符串,直到后面跟着的是其他子字符串,
* 返回一个去除后的新字符串
*
* @param str
* @param num 单个数字,范围:0-9
*/
public static String removeStartingNumStr(String str, int num) {
return removeStartingStr(str, String.valueOf(num));
}
/**
* 去除以特定字符(注意:只能是单个字符)开头的子字符串,直到后面跟着的是其他子字符串,
* 返回一个去除后的新字符串
*
* @param str
* @param childrenStr
* @return
*/
public static String removeStartingStr(String str, String childrenStr) {
String[] strings = getStrings(str);
Integer index = null;
for (int i = 0; i < strings.length; i++) {
if (strings[i].equals(childrenStr)) {
index = i;
} else {
break;
}
}
if (null != index) {
str = str.substring(index + 1);
}
return str;
}
/**
* 十进制转其他进制 方法:辗转相除,取余数的反值
*
* @param radix 进制类型
* @param numStr 要转换字符串的string 形式
* @return
*/
public static String decimalToOther(int radix, String numStr) {
if (radix == 0 || radix > 16) {
return null;
}
// 返回为2需要转换
int regex = judgeInteger(radix, numStr.trim());
if (regex == 2) {
String result = reverse(division(numStr.trim(), radix));
if (radix == 8) {
result = "0".concat(result);
} else if (radix == 16) {
result = "0x".concat(result);
}
return result;
} else {
// 不处理, 1或0
return numStr;
}
}
/**
* 其他进制转十进制
*
* @param radix 进制类型:
* @param numStr 需要转换的数
* @return 方法:阶乘法
*/
public static String otherToDecimal(int radix, String numStr) {
if (radix == 0 || radix > 16) {
return null;
}
numStr = numStr.trim();
if (radix == 16) {
// 去除16进制字符的标记0x,并将字母转为大写
numStr = numStr.replaceFirst("0x", "").toUpperCase();
} else if (radix == 8) {
// 去除8进制字符标记 : 第一位是0
if (numStr.indexOf(0) == 0) {
numStr = numStr.substring(1);
}
}
return factorial(numStr, radix);
}
/**
* 辗转除radix法
*
* @param numStr
* @return
*/
public static String division(String numStr, int radix) {
BigInteger bigStr = new BigInteger(numStr);
BigInteger bigDix = new BigInteger(String.valueOf(radix));
StringBuffer sbf = new StringBuffer();
while (bigStr.compareTo(bigDix) >= 0) {
// 商是0,余数是1
BigInteger[] result = bigStr.divideAndRemainder(bigDix);
BigInteger temp = result[0];
// 余数不会大于除数,所以可以转为int类型
int temp2 = Integer.valueOf(result[1].toString());
// 如果16进制则转为字母
if (radix == 16 && hexMap.containsKey(temp2)) {
sbf.append(hexMap.get(temp2));
} else {
sbf.append(temp2);
}
bigStr = temp;
}
sbf.append(bigStr.toString());
return sbf.toString();
}
/**
* 按位取值 乘 进制的次方,相加
*
* @param numStr
* @param radix
* @return
*/
public static String factorial(String numStr, int radix) {
BigInteger sum = new BigInteger("0");
BigInteger bitValue = new BigInteger("0");
// 从最高位开始取,取值*进制^位数-1
for (int i = 0, numLen = numStr.length(); i < numLen; i++) {
String bitString = numStr.substring(i, i + 1);
if (radix == 16 && hexMap.containsValue(bitString)) {
for (Map.Entry<Integer, String> entry : hexMap.entrySet()) {
if (entry.getValue().equals(bitString)) {
bitValue = new BigInteger(String.valueOf(entry.getKey()));
}
}
} else {
bitValue = new BigInteger(bitString);
}
// int b = radix;
BigInteger b = new BigInteger(String.valueOf(radix));
BigInteger bRadix = new BigInteger(String.valueOf(radix));
for (int k = 1; k < numLen - i - 1; k++) {
b = b.multiply(bRadix);
}
if (i == numLen - 1) {
// 最后一位的次方结果总是1
b = new BigInteger("1");
}
// sum += bitValue*b;//位置*for循环次方的结果,然后相加这些结果
sum = sum.add(bitValue.multiply(b));
}
return sum.toString();
}
/**
* 判断是否需要进行转换
*
* @param numStr 待转换的数字
* @param radix 进制类型
* @return 0:代表为0; 1:代表小于要转换的进制位,无需转换
* 2:需要转换
*/
public static int judgeInteger(int radix, String numStr) {
// 判断是否和0相等
if (String.valueOf(0).equals(numStr)) {
return 0;
}
// 判断数字有无小数点
if (numStr.contains(".")) {
// 暂时无处理小数功能
return 1;
} else {
BigDecimal bg = new BigDecimal(numStr);
int i = bg.compareTo(new BigDecimal(radix));
if (i == -1) {
return 1;
} else {
return 2;
}
}
}
/**
* 测试
*
* @param args
*/
public static void main(String[] args) {
String encode = Encoder.encode("sss");
String decode = Decoder.decodeByte("BDUsBJ==");
System.out.println(encode);
System.out.println(decode);
}
}
打赏
当前共有 0 条评论