该加密方法主要为满足差异化要求,加密字符限定---字母数字下划线。
密文结果跟两个数据集挂钩,即a方生成的密文,a方解析无误,但b方解析结果存异。详见数据集上注释。
代码如下:
package util;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
/**
* 加密(字符限定数字字母下划线[0-9a-zA-Z_])
* @author pangjs ~ 2013-07-11 下午07:28:21
*/
public class Encryptor {
// '~'只是占位,除'~'在首位占位外,数组内的字符顺序可任意调换,不能增加,共63个可用字符[0-9a-zA-Z_]
private static final char[] universe = new char[]{
'~','a','b','c','d','0','1','2','3','4','5','6','8','9','_','7','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',
'Z','Y','X','W','V','U','T','S','R','Q','P','O','N','M','L','K','J','I','H','G'};
private static final Map<Character,Integer> universeMap = new HashMap<Character,Integer>(64, 1f);
// 用作输出,保证同数组内无重复即可,字符任意,顺序任意。 加几组减几组都没事,不用改代码
private static final char[][] show = new char[][]{
{'1','5','2','7','6','0','8','3','A','a'},
{'2','e','f','a','K','w','3','D','n','6'},
{'b','d','f','u','n','m','5','t','2','z'},
{'w','t','Z','G','H','R','x','a','A','f'},
{'@','#','$','%','&','+','w','V','B','2'}};
//分隔符没有特殊要求,但是不能等同于密文显示字符 show[]中字符
private static final char SEPERATE_KEY = '=';
// private static final String START = "song";
// private static final String END = ":-)";
private static final String START = "";
private static final String END = "";
static{
for(int i=0;i<universe.length;i++){
universeMap.put(universe[i],i);
}
}
private Encryptor(){}
/**
* 加密方法
* @param source:需要加密的字符串 ,数字、字母或者下划线组成
* @return 密文
*/
public static String encrypt(final String source){
if(source == null || source.trim().isEmpty() || !source.matches("^[a-zA-Z0-9_]+$")){
throw new EncryptException("超出数字字母下划线范围了,我不行了...");
}
if(source.length()<11){
return en1(en0(source,1));
}
String digit = "";
char[] src = source.toCharArray();
int length = src.length;
for(int i = (length-1)/10; i>0; i--){
String temp = en0(new String(src,length-i*10,10),1);
char[] chr = new char[64];
for(int j=0;j<7;j++){
chr[j]='0';
}
System.arraycopy(temp.toCharArray(), 0, chr, 64-temp.length(), temp.length());
digit += new String(chr,0,64);
}
digit = en0(new String(src, 0, length%10==0?10:length%10),0) + digit;
return en1(digit);
}
private static String en1(String digit){
digit = new BigInteger(digit, 2).toString(10);
StringBuilder need = new StringBuilder(START+SEPERATE_KEY);
int length = digit.length();
for(int i = 0; i<length; i++){
need.append(show[i%show.length][digit.charAt(i) - '0']);
}
need.append(SEPERATE_KEY+END);
return need.toString();
}
private static String en0(final String source, final int mode){
long result = 0L;
int a = 0, temp, length = source.length();
boolean isOver5 = false;
for(int i = 0; i<length; i++){
temp = universeMap.get(source.charAt(i));
a = (temp<<(6*(isOver5?(i-5):i)))|a;
if(i == 4){
result = (long)a<<32;
a = 0;
isOver5 = true;
}
}
result = isOver5 ? a|result : (long)a<<32*mode;
int pos = 64;
char[] buf = new char[pos];
char[] bin = {'0', '1'};
for( ;result!=0 ; result>>>=1){
buf[--pos] = bin[(int)result&1];
}
return new String(buf, pos, 64-pos);
}
// public static void main(String[] args) throws Exception {
// String s = "AadsabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_A";
// System.out.println("原文: "+s);
// String en = encrypt(s);
// System.out.println("密文: "+en);
// System.out.println("解密: "+decrypt(en));
// System.out.println("解密=原文 ? "+decrypt(en).equals(s));
// }
/**
*
* @param encoded
* @return
*/
public static String decrypt(String encoded){
encoded=encoded.substring(encoded.indexOf(SEPERATE_KEY)+1, encoded.lastIndexOf(SEPERATE_KEY));
StringBuilder need=new StringBuilder();
int length = encoded.length();
for(int i=0;i<length;i++){
char temp=encoded.charAt(i);
for(int j=0;j<10;j++){
if(temp==show[i%show.length][j]){
need.append(j);
break;
}
}
}
encoded = new BigInteger(need.toString(),10).toString(2);
length = encoded.length();
if(length<65){
return de0(new String(encoded));
}
String source = "";
char[] src = encoded.toCharArray();
for(int i = (length-1)/64; i>0; i--){
source += de0(new String(src,length-i*64,64));
}
return source = de0(new String(src, 0, length%64)) + source;
}
private static String de0(final String encoded){
long get=Long.parseLong(encoded,2);
StringBuilder need=new StringBuilder();
int curr;
if((get<<32)==0){
get=get>>32;
}else{
for(int i=0;i<5;i++){
if((curr=(int)(get&0x3fL))==0){
get=get>>(30-6*i);
break;
}else{
need.append(universe[curr]);
}
get=get>>6;
}
get=get>>2;
}
for(int i=0;i<5;i++){
if((curr=(int)(get&0x3fL))==0){
break;
}else{
need.insert(i, universe[curr]);
}
get=get>>6;
}
return need.toString();
}
}
class EncryptException extends RuntimeException{
private static final long serialVersionUID = -9018864433826547470L;
public EncryptException(String message) {
super(message);
}
}