JAVA 自定义的base64编解码

想必大家在项目开发中或多或少的接触过base64编码,说它是一种加密方式,未免太过了。其实就是一种为了防止被肉眼直接看到而做的一种转码。

下面来说一下base64编码的原理,有三个字节转换成四个字节,假如一个字节数组是长度是3,如下:

01110010  11001010   00110111  一共24个bit,每六个一组,前面补充00  
这3个字节转换后变成    00011100   00101100  00101000   00110111

根据以上原理,就可以把一个字节数组转换成一个 每个字节的值在  0~63 (0000000 ~ 00111111)之内的字节数组。

接下来就是根据这个字节的值当做一个下标,寻找此下标对应的字母或者符号,恰好是64种下标。对于字节不足的,不能被3整除的字节数组,末尾补充一个不在这个64种符号或者字母之内的符号,解码时去掉这个特殊符号。

package com.ryx.main;
/**
 * 
 * @author lq
 *
 */
public class Base64New {
	
	private static final int BASE = 3;
	private static final int EXPAND = 4;
	private static final int SIGN = -128;
	private static final char END = '$';
	//base64的基准字符,可以自定义,不过最好是可打印字符
	private static final String str = "<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{";
	
	public static String encodeBase64Str(String str){
		return new String(encodeBase64(str));
	}
	
	public static byte[] encodeBase64(String str){
		return encodeBase64(str.getBytes());
	}
	
	public static byte[] encodeBase64(byte[] data){
		int len = data.length;
		int overBytes = len%BASE;
		int lenBytes = len/BASE;
		
		int encodeBytesLen = 0;
		if(overBytes == 0){
			encodeBytesLen = lenBytes*EXPAND;
		}else{
			encodeBytesLen = (lenBytes+1)*EXPAND;
		}
		
		byte[] encodeBytes = new byte[encodeBytesLen];
		int step = 0;
		int encodeIndex = 0;
		byte b1,b2,b3,m0,m1;
		for(int i=0;i<lenBytes;i++){
			step = i*3;
			//取出三个字节
			b1 = data[step];
			b2 = data[step+1];
			b3 = data[step+2];
			//获取第一个字节的最后两位
			m0 = (byte) (b1&0x03);
			//获取第二个字节的最后四位
			m1 = (byte) (b2&0x0f);
			// 字节&-128,非负数都为0,负数的话把高位11转换成00
			byte b1Index = (byte)((b1&SIGN)==0?b1>>2:b1>>2^0xc0);
		    byte b2Index = (byte)((b2&SIGN)==0?b2>>4:b2>>4^0xf0);
		    byte b3Index = (byte)((b3&SIGN)==0?b3>>6:b3>>6^0xfc);
		    //根据字节的数值当做下标,寻找对应的字符
		    encodeBytes[encodeIndex]= (byte) str.charAt(b1Index);
		    encodeBytes[encodeIndex+1]= (byte) str.charAt(b2Index|(m0<<4));
		    encodeBytes[encodeIndex+2]= (byte) str.charAt(b3Index|(m1<<2));
		    encodeBytes[encodeIndex+3]= (byte) str.charAt(b3&0x3f);
		    encodeIndex+=4;
		}
		//当剩下一个字节,或者两个字节时,需要做的处理
		if(overBytes == 1){
			b1 = data[len-1];
			byte b1Index = (byte)((b1&SIGN)==0?b1>>2:b1>>2^0xc0);
			m0 = (byte) (b1&0x03);
			encodeBytes[lenBytes*EXPAND]= (byte) str.charAt(b1Index);
			encodeBytes[lenBytes*EXPAND+1]= (byte) str.charAt((m0<<4));
			encodeBytes[lenBytes*EXPAND+2]= END;
			encodeBytes[lenBytes*EXPAND+3]= END;
		}else if(overBytes == 2){
			b1 = data[len-2];
			b2 = data[len-1];
			byte b1Index = (byte)((b1&SIGN)==0?b1>>2:b1>>2^0xc0);
			byte b2Index = (byte)((b2&SIGN)==0?b2>>4:b2>>4^0xf0);
			m0 = (byte) (b1&0x03);
			m1 = (byte) (b2&0x0f);
			encodeBytes[lenBytes*EXPAND]= (byte) str.charAt(b1Index);
			encodeBytes[lenBytes*EXPAND+1]= (byte) str.charAt(b2Index|(m0<<4));
			encodeBytes[lenBytes*EXPAND+2]= (byte) str.charAt((m1<<2));
			encodeBytes[lenBytes*EXPAND+3]= END;
		}
		return encodeBytes;
	}
	//根据上面的逻辑反推解码,应该很简单了
	public static byte[] decodeBase64(byte[] data){
		if(data.length == 0){
			return new byte[0];
		}
		int len = 0;
		if((len = data.length%EXPAND)!=0){
			throw new IllegalArgumentException("data is not base 64 bytes");
		}
		len = data.length/EXPAND;
		byte[] decodeBytes = new byte[len*BASE];
		int byteLen = 0;
		int decodeIndex = 0;
		byte b1,b2,b3,b4;
		for(int i=0;i<len;i++){
			decodeIndex = i*4;
			b1 = data[decodeIndex];
			b2 = data[decodeIndex+1];
			b3 = data[decodeIndex+2];
			b4 = data[decodeIndex+3];
			if(b3!=END&&b4!=END){
				//无补充符号
				b1 = (byte) str.indexOf(b1);
				b2 = (byte) str.indexOf(b2);
				b3 = (byte) str.indexOf(b3);
				b4 = (byte) str.indexOf(b4);
				decodeBytes[byteLen++] = (byte) (b1<<2|b2>>4);
				decodeBytes[byteLen++] = (byte) (((b2&0xf)<<4)|((b3>>2)&0xf));
				decodeBytes[byteLen++] = (byte) (b3<<6|b4);
			}else if(b3==END){
				b1 = (byte) str.indexOf(b1);
				b2 = (byte) str.indexOf(b2);
				decodeBytes[byteLen++] = (byte) (b1<<2|b2>>4);
			}else if(b4==END){
				b1 = (byte) str.indexOf(b1);
				b2 = (byte) str.indexOf(b2);
				b3 = (byte) str.indexOf(b3);
				decodeBytes[byteLen++] = (byte) (b1<<2|b2>>4);
				decodeBytes[byteLen++] = (byte) (((b2&0xf)<<4)|((b3>>2)&0xf));
			}
		}
		byte[] retBytes = new byte[byteLen];
		System.arraycopy(decodeBytes, 0, retBytes, 0, byteLen);
		return retBytes;
	}
	
	public static byte[] headAndTailEncodeBase64(String str){
		return headAndTailEncodeBase64(str.getBytes());
	}
	//头尾字节交叉后的编码处理
	public static byte[] headAndTailEncodeBase64(byte[] data){
		int len = data.length;
		if(len==0){
			return new byte[0];
		}
		int half = data.length/2;
		int over = data.length%2;
		byte[] newByte = new byte[len];
		for(int i=0;i<half;){
			newByte[i*2] = data[i];
			newByte[((++i)*2-1)] = data[len-i];
		}
		if(over!=0){
			newByte[len-1] = data[half];
		}
		return encodeBase64(newByte);
	}

	public static byte[] headAndTailDecodeBase64(byte[] data){
		byte[] ret = decodeBase64(data);
		if(ret.length==0){
			return new byte[0];
		}
	    int len = ret.length;
	    int half = ret.length/2;
	    int over = ret.length%2;
	    byte[] newByte = new byte[len];
		for(int i=0;i<half;){
			newByte[i] = ret[i*2];
			newByte[len-(++i)] = ret[(i*2-1)];
		}
		if(over!=0){
			newByte[half] = data[len-1];
		}
		return newByte;
	}
	
	public static void main(String[] args) {
		byte[] data = "你好哈".getBytes();
		System.out.println(new String(headAndTailEncodeBase64(data)));
		System.out.println(new String(headAndTailDecodeBase64(headAndTailEncodeBase64("你好哈".getBytes()))));
	}
}



 

想弄明白base64,或者想定义自己的base64,了解原理之后,最好知道这三个运算符的作用   &   |   ^ ,对base64算法就清楚了,还有记住编码时,是把字节当下标寻找对应的字符,解码时根据字符寻找对应的下标,剩下的就看自己怎么去处理字节了,最后两个编解码方法是一个头尾字节交叉后的编解码算法。

了解此算法,可以定义自己的base128编码都不是问题。

小弟第一次写博客,希望读者给出意见,版面估计很难看。








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值