论坛首页 Java企业应用论坛

奥巴码 Obama(v1.1开始支持编解码中文等多字节字符)

浏览 7124 次
精华帖 (0) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2011-10-13   最后修改:2011-10-18
v1.2 update:
下载地址:http://aobama.googlecode.com/files/_Obama64.java
*  1)v1.2添加两个类似钩子的加解密函数(_encode和_decode),方便自定义简单的加解密过程
*  2)废弃@Deprecated的方法未填加钩子方法
*  3)优化init方法
	// 加密钩子, 约定返回一个0-127的值
	private static int _encode(byte plaintext, byte secret){
		return plaintext ^ secret;
//		return plaintext > 64 ? plaintext - 64 : plaintext + 64; //自定义加密,例子1
//		return plaintext ^ 0x55;  //自定义加密,例子2
	}
	
	// 解密钩子, 约定返回一个0-127的值
	private static int _decode(byte cryptograph, byte secret){
		return cryptograph ^ secret;
//		return cryptograph > 64 ? cryptograph - 64 : cryptograph + 64;//自定义解密,例子1
//		return cryptograph ^ 0x55;  //自定义加密,例子2
	}


=1.1版本,支持中文等多字节字符的编解码
v1.1源文件下载:http://aobama.googlecode.com/files/Obama64.java
update:
*  1)v1.1开始支持多字节字符,对应的编码/解码接口为:
*  编码:byte[] encode(byte[] content)
*  解码:byte[] decode(byte[] content)
* 上述两个方法与v1.0中的编码思路一致,通过在每三字节前加一字节记录这三字节mod64的情况
*  不同之处在于记录字节使用两个bit位来记录(v1.0中记录ASCII只用一个bit位),所以相对于
*  base64其编码长度仅多一个Bluff code所占的字节
*  2)v1.0中所有方法都改为 xxxAsciixxx, 以表明只支持ASCII字符
*  3)v1.1仍然支持BLUFF功能

//测试
public static void main(String[] args) throws UnsupportedEncodingException  {
		
		Obama64.BLUFF = true;
		
		String str = "大象、大象,你的鼻子为什么那么长?~~~~\t!@#$#$%^%^$%&#123";
		
		byte[] content = str.getBytes("UTF-16BE");
		
		for(int i = 0; i<3; i++){
			System.out.println("\"Obama64:\"");
			byte[] en = encode(content);
			System.out.println(new String(en));
			System.out.println(new String(decode(en), "UTF-16BE"));
			System.out.println("\"Base64:\"");
			en = Base64.encodeBase64(content);
			System.out.println(new String(en));
			System.out.println(new String(Base64.decodeBase64(en), "UTF-16BE"));
			System.out.println("-----------------------------------------------");
		}
}


//结果
"Obama64:"
sxGsrbDrkxGsrlDaAPFDgmiD8PVH-3pFOoA4IrTFZacd3wYavSLB3fdavsLK3wDa3sLS3sCaDsLR3wRaTsLC3bqassLC3ssaDsLQ3sear
大象、大象,你的鼻子为什么那么长?~~~~	!@#$#$%^%^$%&#123
"Base64:"
WSeMYTABWSeMYf8MT2B2hJ87W1BOOk7ATkiQo05IlX//HwB+AH4AfgB+AAkAIQBAACMAJAAjACQAJQBeACUAXgAkACUAJgAjADEAMgAz
大象、大象,你的鼻子为什么那么长?~~~~	!@#$#$%^%^$%&#123
-----------------------------------------------
"Obama64:"
NxCV-bT-dxCV-lTvPPeT4mnTUPsXr3yeLoPg2rDefaxkBwSvaSO3BfkvasO7BwTvBsOYBsGvTsO0Bw0vDsOGBb6vVsOGBsVvTsO_BsFv-
大象、大象,你的鼻子为什么那么长?~~~~	!@#$#$%^%^$%&#123
"Base64:"
WSeMYTABWSeMYf8MT2B2hJ87W1BOOk7ATkiQo05IlX//HwB+AH4AfgB+AAkAIQBAACMAJAAjACQAJQBeACUAXgAkACUAJgAjADEAMgAz
大象、大象,你的鼻子为什么那么长?~~~~	!@#$#$%^%^$%&#123
-----------------------------------------------
"Obama64:"
cx4wDbrDox4wDlrHqPYrCmNrmPuaT3cYIoqGOr-YhapzjwFHXS2ljfzHXs20jwrHjs2ejsgHrs27jw7H-s2gjbAHws2gjswHrs2MjsSHD
大象、大象,你的鼻子为什么那么长?~~~~	!@#$#$%^%^$%&#123
"Base64:"
WSeMYTABWSeMYf8MT2B2hJ87W1BOOk7ATkiQo05IlX//HwB+AH4AfgB+AAkAIQBAACMAJAAjACQAJQBeACUAXgAkACUAJgAjADEAMgAz
大象、大象,你的鼻子为什么那么长?~~~~	!@#$#$%^%^$%&#123
-----------------------------------------------


引用
=1.0版本=========================


类似Base64的功能,即对目标字符串编码为不易识别的编码串,同时提供解码。v1.0只支持对基于ASCII的字串编解码。
源文件下载:http://aobama.googlecode.com/files/Obama.java

思路:
  • 类似base64采用码表,通过将源字符对应值转换到码表坐标[0-63]来实现源字符到码表字符的映射。
  • 与base64不同的是,base64采用截取6位重新构造的方式来将源字符串各字符对应值限制到[0-63],而该方法是通过上图所示:将各字符mod64,并将每6个源字符组合成一组,将它们mod64的信息统一存放在一个字符中(这个字符前6位的每一位用0或1来记录6字符与64的关系),并放置在每组之前。
  • 通过在编码字符串前放置一个Bluff字符,来进一步扰乱编码字符并实现一定程度编码的随机功能。
  • 解码的时候,则从Bluff字符后,每7个一组进行解码,先将编码字符通过解码表查出其在编码表中对应的值,然后通过位操作从每组首字符中取得mod64的信息,从而还原出对应源字符在Bluff扰乱后的一个值,再通过Bluff字符对扰乱做逆操作,从而获得源编码
  • init()方法实现将编码表和解码表重排序,以避免不同的用户对相同字符串的编码产生相同的编码结果


特点:
  • 相比base64编码后的字符/节串,其长度更精短,base64编码后的字串会比原串长1/3左右,该方法为1/6
  • 编码/解码速度更快(相比apache commons中的base64实现),对700字节的字符串编/解码100万次(单位:nanoTime):

  •         ·base64:32951698610

            ·aobama:18900134515
  • 提供对同一源字串BLUFF编码功能:

  •         ·例如,源字符串为:http://code.google.com/hosting/createProject01

            ·通过打开BLUFF开关,对该原串多次encode调用,每次将产生不同的编码串,但对这些不同的编码结果都能解码回源串,例如:

                    ·第一次:Kk2_Aunjjxh1YGoPYW1T20SWh1Wo1PxZAjjhexhKqE4PEmKJW0lV_ZZA

                    ·第二次:rkmgfeBNjz6XsMcPslXRmDSl6XlcXPzPfNN6ez6rbCQPC2rIlDlSgPPf

                    ·第三次:jkrXlcbPjwigd9ePdfgOr8SfigfegPwNlPPiewimBv5PvKm7f8lpXNNl

                    ·第四次:Wk-HjxhAjun4ktFPkZ4L-USZn4ZF4PuWjAAneunJ3a1Pa7JKZUlyHWWj

                   ·...

            ·对上述四个不同的编码结果调用decode方法都将得到源串http://code.google.com/hosting/createProject01


部分代码:
引用
码表

	
	/** 编码基表 */
	private static final char base_encode[] = {
		// 默认序列
	    'P', 'e', 'r', 'Q', 'f', 'w', '7', 'g', 'i', 'p', 	/*  0- 9 */
	    '8', '9', 'B', 'd', 'O', 'v', '6', 'S', 'D', 'M', 	/* 10-19 */
	    'b', 's', 'R', 'C', 'N', 'c', 'm', '5', 'l', 'z', 	/* 20-29 */
	    'I', 'X', 'o', 'j', 'H', '2', 'x', 'W', '1', 'J', 	/* 30-39 */
	    'V', 'h', 'G', '0', 'Y', 'q', 'E', 'T', 'k', '3', 	/* 40-49 */
	    'a', 'L', 'y', 'n', 't', 'U', 'u', 'Z', '4', 'K', 	/* 50-59 */
	    'F', 'A', '_', '-'									/* 60-63 */ //95,45, 
	};
	
	/** 解码参照表 */
	private static int base_decode[] = {
		// 参照编码表默认序列的值序
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  			/*  0- 9 */
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  			/*  10- 19 */
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  			/*  20- 29 */
		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  			/*  30- 39 */
		-1, -1, -1, -1, -1, 63, -1, -1, 43, 38,  			/*  40- 49 */
		35, 49, 58, 27, 16, 6, 10, 11, -1, -1,  			/*  50- 59 */
		-1, -1, -1, -1, -1, 61, 12, 23, 18, 46,  			/*  60- 69 */
		60, 42, 34, 30, 39, 59, 51, 19, 24, 14,  			/*  70- 79 */
		0, 3, 22, 17, 47, 55, 40, 37, 31, 44,  				/*  80- 89 */
		57, -1, -1, -1, -1, 62, 0, 50, 20, 25,  			/*  90- 99 */
		13, 1, 4, 7, 41, 8, 33, 48, 28, 26,  				/*  100- 109 */
		53, 32, 9, 45, 2, 21, 54, 56, 15, 5,  				/*  110- 119 */
		36, 52, 29, -1, -1, -1, -1, -1, -1		 			/*  120- 128 */	
	};
	
	/**
	 * 重排序编码基表和对应的解码表
	 */
	public static void init(){
		
		// 重排序编码基表
		ArrayList<Character> list = new ArrayList<Character>();
		for(char c : base_encode)
			list.add(c);
		Collections.shuffle(list);
		for(int i=0; i<list.size(); i++)
			base_encode[i] = list.get(i);
		
		// 根据重排序后的编码基表初始化解码表
		initDecode();
	}


引用
通用的编解码方法(对于ASCII和多字节字符)

	public static byte[] encode(byte[] content){
		if(content==null || content.length==0)
			return content;
		
		int len = content.length;
		
		byte[] cArray = new byte[len + (int)Math.ceil(len/3.0d) + 1];
		
		if(BLUFF){
			int s = 0;
			int r = new Random().nextInt(26);
			boolean u = ((r ^ len) & 1) == 1;
			s = u ? 65 : 97;
			cArray[0] = (byte)(r + s);
		}else{
			cArray[0] = DEF_SECRET;
		}
		
		byte c = 0;
		int n = 0;
		int mark = 0;
		int pos = 0;
		int segs = 0;
		for(int i=0; i<len; i+=3){
			mark = 1+i+segs;
			for(int k=0; (k<3) && (pos<len); k++){
				c = content[pos];
				
				if(c<0){
					c = (byte)~c;
					cArray[mark] |= (2<<(k<<1));
				}
				
				n = c ^ cArray[0]; 
				n ^= k;
				
				cArray[mark] |= ((n>>>6)<<(k<<1)); 
				
				cArray[mark+k+1] = (byte)base_encode[n & MASK_64];
				pos++;
			}
			segs++;
			cArray[mark] = (byte)base_encode[cArray[mark]];
		}
		
		return cArray;
	}
	
	public static byte[] decode(byte[] content){
		
		if(content==null || content.length==0)
			return content;
		
		int len = content.length;
		
		byte[] cArray = new byte[len - 1 - (int)Math.ceil((len-1)/4.0)];
		
		byte secret = content[0];
		byte c = 0;
		int mark = 0;
		int index = 0;
		int tmp = 0;
		for(int i=1; i<len; i+=4){
			mark = base_decode[content[i]];
			for(int k=0, pos=i + k + 1; k<3 && pos<len; k++, pos++){
				c = content[pos];
				tmp = mark>>>(k<<1); 
				cArray[index] = (byte)((base_decode[c] + ((tmp&1)<<6))^ k ^secret);
				if((tmp & 2) > 0)
					cArray[index] = (byte)~cArray[index];
				index++;
			}
		}
		
		return cArray;
	}



引用
编解码ASCII字符的方法,相比通用方法速度更快,且编码后的字节数更精短

	
	
		/** 
	 * 	编码
	 * */
	public static byte[] encodeAsciiBytes(byte[] content){
		
		if(content==null || content.length==0)
			return null;
		
		int len = content.length;
		
		byte[] cArray = new byte[len + (int)Math.ceil(len/6.0d) + 1];
		
		if(BLUFF){
			int s = 0;
			int r = new Random().nextInt(26);
			boolean u = ((r ^ len) & 1) == 1;
			s = u ? 65 : 97;
			cArray[0] = (byte)(r + s);
		}else{
			cArray[0] = DEF_SECRET;
		}
		
		
		byte c = 0;
		int n = 0;
		int mark = 0;
		int pos = 0;
		int segs = 0;
		for(int i=0; i<len; i+=6){
			mark = 1+i+segs;
			for(int k=0; (k<6) && (pos<len); k++){
				c = content[pos];
				n = c ^ cArray[0]; 
				n ^= k;
				cArray[mark] |= ((n>>>6)<<k); 
				
				cArray[mark+k+1] = (byte)base_encode[n & MASK_64];
				pos++;
			}
			segs++;
			cArray[mark] = (byte)base_encode[cArray[mark]];
		}
		
		return cArray;
		
	}
	
	public static byte[] encodeAsciiBytes(String content){
		
		if(content==null || content.length()==0)
			return null;
		
		int len = content.length();
		
		byte[] cArray = new byte[len + (int)Math.ceil(len/6.0d) + 1];
		
		if(BLUFF){
			int s = 0;
			int r = new Random().nextInt(26);
			boolean u = ((r ^ len) & 1) == 1;
			s = u ? 65 : 97;
			cArray[0] = (byte)(r + s);
		}else{
			cArray[0] = DEF_SECRET;
		}
		
		char c = '0';
		int n = 0;
		int mark = 0;
		int pos = 0;
		int segs = 0;
		
		for(int i=0; i<len; i+=6){
			mark = 1+i+segs;
			for(int k=0; (k<6) && (pos<len); k++){
				c = content.charAt(pos);
				n = c ^ cArray[0]; 
				n ^= k;
				cArray[mark] |= ((n>>>6)<<k); 
				
				cArray[mark+k+1] = (byte)base_encode[n & MASK_64];
				pos++;
			}
			segs++;
			cArray[mark] = (byte)base_encode[cArray[mark]];
		}
		
		return cArray;
		
	}
	
	public static String encodeAsciiString(String content){
		
		if(content==null || content.length()==0)
			return null;
		
		int len = content.length();
		
		char[] cArray = new char[len + (int)Math.ceil(len/6.0d) + 1];
		
		if(BLUFF){
			int s = 0;
			int r = new Random().nextInt(26);
			boolean u = ((r ^ len) & 1) == 1;
			s = u ? 65 : 97;
			cArray[0] = (char)(r + s);
		}else{
			cArray[0] = (char)DEF_SECRET;
		}
		
		char c = '0';
		int n = 0;
		int mark = 0;
		int pos = 0;
		int segs = 0;
		for(int i=0; i<len; i+=6){
			mark = 1+i+segs;
			for(int k=0; (k<6) && (pos<len); k++){
				c = content.charAt(pos);
				n = c ^ cArray[0]; 
				n ^= k;
				cArray[mark] |= ((n>>>6)<<k); 
				
				cArray[mark+k+1] = base_encode[n & MASK_64];
				pos++;
			}
			segs++;
			cArray[mark] = base_encode[cArray[mark]];
		}
		
		return new String(cArray);
		
	}
	
	public static String encodeAsciiString(byte[] content){
		
		if(content==null || content.length==0)
			return null;
		
		int len = content.length;
		
		char[] cArray = new char[len + (int)Math.ceil(len/6.0d) + 1];
		
		if(BLUFF){
			int s = 0;
			int r = new Random().nextInt(26);
			boolean u = ((r ^ len) & 1) == 1;
			s = u ? 65 : 97;
			cArray[0] = (char)(r + s);
		}else{
			cArray[0] = (char)DEF_SECRET;
		}
		
		byte c = 0;
		int n = 0;
		int mark = 0;
		int pos = 0;
		int segs = 0;
		for(int i=0; i<len; i+=6){
			mark = 1+i+segs;
			for(int k=0; (k<6) && (pos<len); k++){
				c = content[pos];
				n = c ^ cArray[0]; 
				n ^= k;
				cArray[mark] |= ((n>>>6)<<k); 
				
				cArray[mark+k+1] = base_encode[n & MASK_64];
				pos++;
			}
			segs++;
			cArray[mark] = base_encode[cArray[mark]];
		}
		
		return new String(cArray);
		
	}
	
	/** 解码 */
	public static String decodeAsciiString(String content){
		
		if(content==null || content.length()==0)
			return null;
		
		int len = content.length();
		
		char[] cArray = new char[len - 1 - (int)Math.ceil((len-1)/7.0)];
		
		char secret = content.charAt(0);
		char c = '0';
		int mark = 0;
		int index = 0;
		for(int i=1; i<len; i+=7){
			mark = base_decode[content.charAt(i)];
			for(int k=0, pos=i + k + 1; k<6 && pos<len; k++, pos++){
				c = content.charAt(pos);
//				cArray[index] = (char)((base_decode[c] + 64*((mark>>>k)&1))^ k ^secret);
				cArray[index] = (char)((base_decode[c] + (((mark>>>k)&1)<<6))^ k ^secret);
				index++;
			}
		}
		
		return new String(cArray);
	}
	
	public static String decodeAsciiString(byte[] content){
		
		if(content==null || content.length==0)
			return null;
		
		int len = content.length;
		
		char[] cArray = new char[len - 1 - (int)Math.ceil((len-1)/7.0)];
		
		byte secret = content[0];
		byte c = 0;
		int mark = 0;
		int index = 0;
		for(int i=1; i<len; i+=7){
			mark = base_decode[content[i]];
			for(int k=0, pos=i + k + 1; k<6 && pos<len; k++, pos++){
				c = content[pos];
				cArray[index] = (char)((base_decode[c] + (((mark>>>k)&1)<<6))^ k ^secret);
				index++;
			}
		}
		
		return new String(cArray);
	}
	
	public static byte[] decodeAsciiBytes(byte[] content){
		
		if(content==null || content.length==0)
			return null;
		
		int len = content.length;
		
		byte[] cArray = new byte[len - 1 - (int)Math.ceil((len-1)/7.0)];
		
		byte secret = content[0];
		byte c = 0;
		int mark = 0;
		int index = 0;
		for(int i=1; i<len; i+=7){
			mark = base_decode[content[i]];
			for(int k=0, pos=i + k + 1; k<6 && pos<len; k++, pos++){
				c = content[pos];
				cArray[index] = (byte)((base_decode[c] + (((mark>>>k)&1)<<6))^ k ^secret);
				index++;
			}
		}
		
		return cArray;
	}
	
	public static byte[] decodeAsciiBytes(String content){
		
		if(content==null || content.length()==0)
			return null;
		
		int len = content.length();
		
		byte[] cArray = new byte[len - 1 - (int)Math.ceil((len-1)/7.0)];
		
		byte secret = (byte)content.charAt(0);
		byte c = 0;
		int mark = 0;
		int index = 0;
		for(int i=1; i<len; i+=7){
			mark = base_decode[content.charAt(i)];
			for(int k=0, pos=i + k + 1; k<6 && pos<len; k++, pos++){
				c = (byte)content.charAt(pos);
				cArray[index] = (byte)((base_decode[c] + (((mark>>>k)&1)<<6))^ k ^secret);
				index++;
			}
		}
		
		return cArray;
	}


引用
测试

	public static void main(String[] args) throws UnsupportedEncodingException {
		
		// 如果希望不基于默认编码/解码表的话
		Obama.init(); 
		
		// 如果希望对相同字符串多次编码产生不同的编码结果
		Obama.BLUFF = true; 
		
		// 待编码的字符串
		String content = "http://aobama.googlecode.com/files/Obama.java"; 
		
		for(int i=0; i<3; i++){
			String encode = Obama.encodeAsciiString(content);
			String decode = Obama.decodeAsciiString(encode);
			System.out.println("编码后:" + encode);
			System.out.println("解码后:" + decode);
			System.out.println("---------------------------");
		}
		
	}


引用
测试结果

i=0
编码后:Qdb4Qn-ZKt30dNbRdtN8kmT8jd833Xzm0zkyaI0e9k2am3tmZtTdOy
解码后:http://aobama.googlecode.com/files/Obama.java
---------------------------
i=1
编码后:vdLxTupsKGM2JhLRJGhVBqTVrJVMMX6q26BDaP2XAB0aqMGqsGTJKD
解码后:http://aobama.googlecode.com/files/Obama.java
---------------------------
i=2
编码后:Kdvt8Ij9K4SOfFvRf4FQi7TQ-fQSSXU7OUiWanO1ZiKa7S4794Tf0W
解码后:http://aobama.googlecode.com/files/Obama.java
---------------------------

  • 大小: 35.1 KB
   发表时间:2011-10-14  
没人感兴趣吗?比如混乱和加密URL时很有用啊。。
0 请登录后投票
   发表时间:2011-10-14  
这个有时候很有需要,但好像一般又用不上
0 请登录后投票
   发表时间:2011-10-14  
我觉得很有用啊,比如有些资源不想爬虫程序有条理的爬取掉,比如从id 1 爬到 10000。可以使用该方法或base64对这些id编码。
还有就是数据传输的时候,这是一种比较好的加密的方法(肉眼难以识别,该方法和base64的编码一样,都是可破解的,虽然有些麻烦),base64就用来处理邮件传输。
不过目前这种方法如果按照目前思路实现编码多字节编码字符的话,编码后的长度和效率都比不上base64,所以只实现了ASCII部分,不过用来处理URL还是足够了,而且比base64更节省和高效
0 请登录后投票
   发表时间:2011-10-14  
Crusader 写道
我觉得很有用啊,比如有些资源不想爬虫程序有条理的爬取掉,比如从id 1 爬到 10000。可以使用该方法或base64对这些id编码。
还有就是数据传输的时候,这是一种比较好的加密的方法(肉眼难以识别,该方法和base64的编码一样,都是可破解的,虽然有些麻烦),base64就用来处理邮件传输。
不过目前这种方法如果按照目前思路实现编码多字节编码字符的话,编码后的长度和效率都比不上base64,所以只实现了ASCII部分,不过用来处理URL还是足够了,而且比base64更节省和高效

那个ID用类似UUID的东西查找就行了,我这里下载文件就是为每个文件设置一个UUID实现的
其他字符的话,可以先转换成%AB的编码啊
0 请登录后投票
   发表时间:2011-10-14   最后修改:2011-10-14
java_user 写道
Crusader 写道
我觉得很有用啊,比如有些资源不想爬虫程序有条理的爬取掉,比如从id 1 爬到 10000。可以使用该方法或base64对这些id编码。
还有就是数据传输的时候,这是一种比较好的加密的方法(肉眼难以识别,该方法和base64的编码一样,都是可破解的,虽然有些麻烦),base64就用来处理邮件传输。
不过目前这种方法如果按照目前思路实现编码多字节编码字符的话,编码后的长度和效率都比不上base64,所以只实现了ASCII部分,不过用来处理URL还是足够了,而且比base64更节省和高效

那个ID用类似UUID的东西查找就行了,我这里下载文件就是为每个文件设置一个UUID实现的
其他字符的话,可以先转换成%AB的编码啊


uuid有时候长度是问题
还有,如果我要和数据库id中存储的id进行相等对应呢?

你说的%AB的编码是指url中非url safe的进行URLEncoder吗,但是如果是url safe的字符,比如我上面编码表中的那些字符,我想隐藏url中的信息的时候,就可能考虑base64或该方法
0 请登录后投票
   发表时间:2011-10-14  
现在youku, taobao上面好多url貌似就做过类似转换,估计是防爬虫和内部信息泄露
0 请登录后投票
   发表时间:2011-10-14  
呃  对于开发企业应用,一般外网访问不进来,很少会去加密URL的...
0 请登录后投票
   发表时间:2011-10-15  
base32足矣
0 请登录后投票
   发表时间:2011-10-15  
我觉得不错,至少对于防止被爬虫下载flash或者之类资源的有帮助。

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics