/**
?*
?*/
package com.newegg.lab.framework.security;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import com.newegg.lab.framework.exception.EncodingException;
import com.newegg.lab.framework.util.StringPoolConstant;
import com.newegg.lab.framework.util.Validator;
/**
?*
?* @Discription 字符串的(編碼/加密)與(解碼/解密)
?*
?* 規則:
?*
?* 在Base64中,碼表是由[A-Z,a-z,0-9,+,/,=(pad)]組成的。
?* 而在這里,碼表由[a-z,2-7] abcdefghijklmnopqrstuvwxyz234567 組成的:
?* -----------------------------------------------
?* a b c d e f g h i j k? l? m? n? o? p? q? r
?* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
?* -----------------------------------------------
?*? s? t? u? v? w? x? y? z? 2? 3? 4? 5? 6? 7
?* 18 19 20 21 22 23 24 25 26 27 28 29 30 31
?* ------------------------------------------------
?*
?* 在Base64中,是將二進制連成一串,然后再按6位來分割,分割完后在前面補0,這個地球人都知道,不多說了。
?* 而在這里,在分割的那一步稍微有變動,是按5位來分割,如果剛好夠分,那就好了,如果不夠,那咋辦呢?
?*
?* 在Base64中,是用"="來解決的吧。
?* 而在這里,就是在前面補0,然后在后面再補零。
?*
?* 例如:字符串 "aaa",(編碼/加密)后是 "mfqwc"
?*
?* 二進制:01100001 01100001 01100001
?* 轉換后:(000)01100 (000)00101 (000)10000 (000)10110 (000)0001(0)
?* 十進制:??? 12????????? 5????????? 16???????? 22????????? 2
?* 碼表對應:?? m?????????? f????????? q????????? w?????????? c
?*
?* (解碼/解密)就更簡單了:
?*
?* 碼表對應:??? m?????? f??????? q??????? w?????? c
?* 十進制:???? 12?????? 5?????? 16?????? 22?????? 2
?* 二進制: 00001100 00000101 00010000 00010110 00000010
?* 去前0后:01100 00101 10000 10110 00010
?* 合并后: 0110000101100001011000010
?*
?* 然后把合并后的串的長度除一下8,發現多了個0:
?*
?* 二進制:01100001 01100001 01100001 0
?*
?* 多了就算了,不要了(其實是在{編碼/加密}的分割時候,在分剩的余數的后面補的0)。
?* 然后再將 byte[] 轉回字符串,OK!又見"aaa"了。
?*
?* 有一點值得注意的,UTF-8、GBK、GB18030 一般都沒什么問題,
?* 但是 GB2312 可能字符集不夠豐富,繁體字在decrypt的時候成問號了
?*
?* @Company 新蛋信息技術(西安)有限公司
?*
?* @Author Terry.B.Li
?*
?* @CreateDate 2009-2-4 下午02:47:32
?*
?* @Version V0.5
?*
?*/
public class EncryptDecrypt {
?? ?/**
?? ? * 碼表 [a-n,q-z,0-4,6-7,9]
?? ? */
?? ?private static final String CODEC_TABLE = "abcdefghijklmnqrstuvwxyz01234679";
?? ?/**
?? ? * 表示5bit的字節
?? ? */
?? ?public final static int FIVE_BIT = 5;
?? ?/**
?? ? * 表示8bit的字節
?? ? */
?? ?public final static int EIGHT_BIT = 8;
?? ?/**
?? ? * 表示二進制
?? ? */
?? ?public final static int BINARY = 2;
?? ?/**
?? ? * (編碼/加密)字符串,采用默認語言環境的 character set
?? ? * @param str?? ?需要(編碼/加密)的字符串
?? ? * @return?? ??? ?(編碼/加密)后的字符串
?? ? * @throws EncodingException
?? ? */
?? ?public static String encrypt(String str) throws EncodingException{
?? ??? ?return encrypt(str,null);
?? ?}
?? ?/**
?? ? * (編碼/加密)字符串
?? ? * @param str?? ??? ??? ?需要(編碼/加密)的字符串
?? ? * @param characterSet?? ?字符集
?? ? * @return?? ??? ??? ??? ?(編碼/加密)后的字符串
?? ? * @throws EncodingException
?? ? */
?? ?public static String encrypt(String str,String characterSet) throws EncodingException{
?? ??? ?if (Validator.isNull(str)) {
?? ??? ??? ?return StringPoolConstant.BLANK;
?? ??? ?}
?? ??? ?byte[] keyBytes = null;
?? ??? ?try {
?? ??? ??? ?if (Validator.isNotNull(characterSet)) {
?? ??? ??? ??? ?keyBytes = str.getBytes(characterSet);
?? ??? ??? ?}else{
?? ??? ??? ??? ?keyBytes = str.getBytes();
?? ??? ??? ?}
?? ??? ?} catch (UnsupportedEncodingException e) {
?? ??? ??? ?throw new EncodingException(e);
?? ??? ?}
?? ??? ?return encrypt(keyBytes);
?? ?}
?? ?/**
?? ? * (編碼/加密)字節數組
?? ? * @param bytes?? ?需要(編碼/加密)的字節數組
?? ? * @return?? ??? ?(編碼/加密)后的字符串
?? ? */
?? ?private static String encrypt(byte[] keyBytes){
?? ??? ?if (Validator.isNull(keyBytes) || keyBytes.length < 1) {
?? ??? ??? ?return StringPoolConstant.BLANK;
?? ??? ?}
?? ??? ?/*
?? ??? ? * 合并二進制碼,
?? ??? ? * 如:
?? ??? ? *???? 00101010 11010011 00101101 10100011
?? ??? ? *?? to
?? ??? ? *???? 00101010110100110010110110100011
?? ??? ? */
?? ??? ?StringBuilder mergrd = new StringBuilder();
?? ??? ?for (int i = 0; i < keyBytes.length; i++) {
?? ??? ??? ?FormatUtil.formatBinary(keyBytes[i], mergrd);
?? ??? ?}
?? ??? ?/*
?? ??? ? * 以5個bit為單位,計算能分多少組,
?? ??? ? * 如:
???????? *???? 00101010110100110010110110100011
?? ??? ? *?? to
?? ??? ? *???? 00101 01011 01001 10010 11011 01000 11
?? ??? ? *????????????????????????????????????????? |
?? ??? ? *?????????????????????????????????? (這個11為余下的位)
?? ??? ? */
?? ??? ?int groupCount = mergrd.length() / FIVE_BIT;
?? ??? ?// 計算余下的位數
?? ??? ?int lastCount = mergrd.length() % FIVE_BIT;
?? ??? ?// 類似數據分頁的算法,有余數的情況下需要加 1。
?? ??? ?if (lastCount > 0) {
?? ??? ??? ?groupCount += 1;
?? ??? ?}
?? ??? ?/*
?? ??? ? * (編碼/加密)
?? ??? ? */
?? ??? ?StringBuilder sbencryptd = new StringBuilder();
?? ??? ?// 循環所需的條件
?? ??? ?int forMax = groupCount * FIVE_BIT;
?? ??? ?// 每次遞增5位來截取
?? ??? ?for (int i = 0; i < forMax; i += FIVE_BIT) {
?? ??? ??? ?// 結束點
?? ??? ??? ?int end = i + FIVE_BIT;
?? ??? ??? ?/*
?? ??? ??? ? * 如果結束點比已合并的二進制碼串的長度要大,
?? ??? ??? ? * 相當于有余數,
???????????? * 并且表示當前循環到了(已合并的二進制碼串的長度 % FIVE_BIT)的那一截。
?? ??? ??? ? */
?? ??? ??? ?// 標記是否到了余數的那一截
?? ??? ??? ?boolean flag = false;
?? ??? ??? ?if (end > mergrd.length()) {
?? ??? ??? ??? ?/*
?? ??? ??? ??? ? * 如果結束點比已合并的二進制碼串的長度要大,
?? ??? ??? ??? ? * 結束點需要被重設為:
?? ??? ??? ??? ? * 已合并的二進制碼串的長度,等價于(i + lastCount). 并且重設標記。
?? ??? ??? ??? ? */
?? ??? ??? ??? ?end = (i + lastCount);
?? ??? ??? ??? ?flag = true;
?? ??? ??? ?}
?? ??? ??? ?// 截取
?? ??? ??? ?String strFiveBit = mergrd.substring(i, end);
?? ??? ??? ?// 截取后從二進制轉為十進制
?? ??? ??? ?int intFiveBit = Integer.parseInt(strFiveBit, BINARY);
?? ??? ??? ?if (flag) {
?? ??? ??? ??? ?/*
?? ??? ??? ??? ? * 如果結束點比已合并的二進制碼串的長度要大,
?? ??? ??? ??? ? * 或者是到了余數的那一截:
?? ??? ??? ??? ? * 需要左移操作,假設余下的二進制位為:11,
?? ??? ??? ??? ? * 那么需要從后面補0,左移操作后為 (000)11(000)
?? ??? ??? ??? ? */
?? ??? ??? ??? ?intFiveBit <<= (FIVE_BIT - lastCount);
?? ??? ??? ?}
?? ??? ??? ?// 利用該十進制數作為碼表的索引獲取對應的字符,并追加到sbencryptd
?? ??? ??? ?sbencryptd.append(CODEC_TABLE.charAt(intFiveBit));
?? ??? ?}
?? ??? ?return sbencryptd.toString();
?? ?}
?? ?/**
?? ? * (解碼/解密)字符串,采用默認語言環境的 character set。
?? ? *
?? ? * @param code
?? ? *??????????? 需要(解碼/解密)的字符串
?? ? *
?? ? * @return (解碼/解密)后的字符串
?? ? */
?? ?public static String decrypt(String code) {
?? ??? ?return decrypt(code, null);
?? ?}
?? ?/**
?? ? * (解碼/解密)字符串
?? ? *
?? ? * @param code
?? ? *??????????? 需要(解碼/解密)的字符串
?? ? * @param characterSet
?? ? *??????????? 字符集
?? ? *
?? ? * @return (解碼/解密)后的字符串
?? ? */
?? ?public static String decrypt(String code, String characterSet) {
?? ??? ?if (code == null || code.length() < 1) {
?? ??? ??? ?return "";
?? ??? ?}
?? ??? ?/*
?? ??? ? * 拆除每一個字符,從碼表里獲取相應的索引。
?? ??? ? */
?? ??? ?StringBuilder sbBinarys = new StringBuilder();
?? ??? ?for (int i = 0; i < code.length(); i++) {
?? ??? ??? ?// 從碼表里獲取相應的索引
?? ??? ??? ?int index = getCodecTableIndex(code.charAt(i));
?? ??? ??? ?// 將十進制的索引轉換為二進制串
?? ??? ??? ?String indexBinary = Integer.toBinaryString(index);
?? ??? ??? ?// 去掉前3個0,并且追加到sbBinarys
?? ??? ??? ?FormatUtil.formatBinary(indexBinary, sbBinarys, FIVE_BIT);
?? ??? ?}
?? ??? ?/*
?? ??? ? * 按8個bit拆分,剩下的余數扔掉。
?? ??? ? * 扔掉的余數是在(編碼/加密)的分割時候,在分剩的余數的后面補的0
?? ??? ? */
?? ??? ?byte[] binarys = new byte[sbBinarys.length() / EIGHT_BIT];
?? ??? ?for (int i = 0, j = 0; i < binarys.length; i++) {
?? ??? ??? ?// 每8個bit截取一份
?? ??? ??? ?String sub = sbBinarys.substring(j, j += EIGHT_BIT);
?? ??? ??? ?// 將截取下來的二進制串轉換為十進制
?? ??? ??? ?Integer intBinary = Integer.valueOf(sub, BINARY);
?? ??? ??? ?binarys[i] = intBinary.byteValue();
?? ??? ?}
?? ??? ?String decryptd = null;
?? ??? ?if (characterSet == null || characterSet.length() < 1) {
?? ??? ??? ?// 采用默認語言環境的 character set。
?? ??? ??? ?decryptd = new String(binarys);
?? ??? ?} else {
?? ??? ??? ?try {
?? ??? ??? ??? ?// 采用指定的 character set。
?? ??? ??? ??? ?return new String(binarys, characterSet);
?? ??? ??? ?} catch (UnsupportedEncodingException e) {
?? ??? ??? ??? ?// ignore...
?? ??? ??? ?}
?? ??? ?}
?? ??? ?return decryptd;
?? ?}
?? ?/**
?? ? * 根據所給出的字符,遍歷CODEC_TABLE,返回對應的下標。
?? ? * 如果沒找到,則返回 -1。
?? ? *
?? ? * @param code
?? ? *??????????? 在CODEC_TABLE范圍內的字符。
?? ? *
?? ? * @return 字符在CODEC_TABLE里對應的下標,如果沒找到,則返回 -1。
?? ? */
?? ?private static int getCodecTableIndex(char code) {
?? ??? ?for (int i = 0; i < CODEC_TABLE.length(); i++) {
?? ??? ??? ?if (CODEC_TABLE.charAt(i) == code) {
?? ??? ??? ??? ?return i;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?return -1;
?? ?}
?? ?/**
?? ? * 測試
?? ? * @param args
?? ? */
?? ?public static void main(String[] args) {
?? ??? ?try {
?? ??? ??? ?BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
?? ??? ??? ?while (true) {
?? ??? ??? ??? ?System.out.print("輸入字符號串:");
?? ??? ??? ??? ?String in = br.readLine();
?? ??? ??? ??? ?if ("exit".equalsIgnoreCase(in)) {
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?}
//?? ??? ??? ??? ?String encrypt = EncryptDecrypt.encrypt(in);
//
//?? ??? ??? ??? ?String decrypt = EncryptDecrypt.decrypt(encrypt);
//?? ??? ??? ??? ?System.out.println();
//?? ??? ??? ??? ?System.out.println("------------------------------test");
//?? ??? ??? ??? ?System.out.println("original: " + in);
//?? ??? ??? ??? ?System.out.println("encrypt: " + encrypt);
//?? ??? ??? ??? ?System.out.println("decrypt: " + decrypt);
//?? ??? ??? ??? ?System.out.println("------------------------------test");
?? ??? ??? ??? ?System.out.println();
?? ??? ??? ??? ?//gizdcojwhlalvr7s2cwa
?? ??? ??? ??? ?System.out.println("-------------------------------------------");
?? ??? ??? ??? ?System.out.println("編碼:"+EncryptDecrypt.encrypt("requirementDetailsVo.var_requirement.requirement_id=8a906aa71f347aa2011f347aa25f0003"));
?? ??? ??? ??? ?System.out.println("jie:"+EncryptDecrypt.decrypt(EncryptDecrypt.encrypt("requirementDetailsVo.var_requirement.requirement_id=8a906aa71f347aa2011f347aa25f0003")));
?? ??? ??? ??? ?System.out.println("解碼:"+EncryptDecrypt.decrypt(in));
//?? ??? ??? ??? ?System.out.println("解碼:"+EncryptDecrypt.decrypt(EncryptDecrypt.encrypt(in)));
?? ??? ??? ??? ?System.out.println("-------------------------------------------");
?? ??? ??? ??? ?System.out.println();
?? ??? ??? ?}
?? ??? ?} catch (IOException e) {
?? ??? ??? ?e.printStackTrace();
?? ??? ?} catch (EncodingException e) {
?? ??? ??? ?// TODO Auto-generated catch block
?? ??? ??? ?e.printStackTrace();
?? ??? ?}
?? ?}
}
/**
?*
?*/
package com.newegg.lab.framework.security;
/**
?*
?* @Discription
?*
?* @Company 新蛋信息技術(西安)有限公司
?*
?* @Author Terry.B.Li
?*
?* @CreateDate 2009-2-4 下午04:32:29
?*
?* @Version V0.5
?*
?*/
public class FormatUtil {
??? /**
??? ?* 格式化二進制。默認取8位,超過則截取,不足則補零。
??? ?* 格式:“00000000”,與NumberFormat的pattern:“########”類似。
??? ?*
??? ?* @author terry
??? ?* @version 2008-12-3 下午03:15:06
??? ?*
??? ?* @param binary
??? ?*??????????? 需要格式化的字節。
??? ?*
??? ?* @return 格式化后的字符串。
??? ?*/
??? public static String formatBinary(byte binary) {
??? ??? return formatBinary(binary, null).toString();
??? }
??? /**
??? ?* 格式化二進制,超過則截取,不足則補零。格式:“00000000”,與NumberFormat的pattern:“########”類似。
??? ?*
??? ?* @author terry
??? ?* @version 2008-12-3 下午03:15:09
??? ?*
??? ?* @param binary
??? ?*??????????? 需要格式化的字節。
??? ?* @param bitCount
??? ?*??????????? 需要格式化的位數。
??? ?*
??? ?* @return 格式化后的字符串。
??? ?*/
??? public static String formatBinary(byte binary, int bitCount) {
??? ??? return formatBinary(binary, null, bitCount).toString();
??? }
??? /**
??? ?* 格式化二進制,超過則截取,不足則補零。格式:“00000000”,與NumberFormat的pattern:“########”類似。
??? ?*
??? ?* @author terry
??? ?* @version 2008-12-3 下午03:15:12
??? ?*
??? ?* @param binary
??? ?*??????????? 需要格式化的字節。
??? ?* @param toAppendTo
??? ?*??????????? 追加到的Builder。
??? ?*
??? ?* @return 格式化后的StringBuilder。
??? ?*/
??? public static StringBuilder formatBinary(byte binary,
??? ??? ??? StringBuilder toAppendTo) {
??? ??? return formatBinary(binary, toAppendTo, EncryptDecrypt.EIGHT_BIT);
??? }
??? /**
??? ?* 格式化二進制,超過則截取,不足則補零。格式:“00000000”,與NumberFormat的pattern:“########”類似。
??? ?*
??? ?* @author terry
??? ?* @version 2008-12-3 下午03:15:16
??? ?*
??? ?* @param binary
??? ?*??????????? 需要格式化的字節。
??? ?* @param toAppendTo
??? ?*??????????? 追加到的Builder。
??? ?* @param bitCount
??? ?*??????????? 需要格式化的位數。
??? ?*
??? ?* @return 格式化后的StringBuilder。
??? ?*/
??? public static StringBuilder formatBinary(byte binary,
??? ??? ??? StringBuilder toAppendTo, int bitCount) {
??? ??? String strBinary = Integer.toBinaryString(binary);
??? ??? return formatBinary(strBinary, toAppendTo, bitCount);
??? }
??? /**
??? ?* 格式化二進制,超過則截取,不足則補零。格式:“00000000”,與NumberFormat的pattern:“########”類似。
??? ?*
??? ?* @author terry
??? ?* @version 2008-12-3 下午03:15:20
??? ?*
??? ?* @param binary
??? ?*??????????? 需要格式化的字節。
??? ?*
??? ?* @return 格式化后的字符串。
??? ?*/
??? public static String formatBinary(String binary) {
??? ??? return formatBinary(binary, null).toString();
??? }
??? /**
??? ?* 格式化二進制,超過則截取,不足則補零。格式:“00000000”,與NumberFormat的pattern:“########”類似。
??? ?*
??? ?* @author terry
??? ?* @version 2008-12-3 下午03:15:24
??? ?*
??? ?* @param binary
??? ?*??????????? 需要格式化的字節。
??? ?* @param bitCount
??? ?*??????????? 需要格式化的位數。
??? ?*
??? ?* @return 格式化后的字符串。
??? ?*/
??? public static String formatBinary(String binary, int bitCount) {
??? ??? return formatBinary(binary, null, bitCount).toString();
??? }
??? /**
??? ?* 格式化二進制,超過則截取,不足則補零。格式:“00000000”,與NumberFormat的pattern:“########”類似。
??? ?*
??? ?* @author terry
??? ?* @version 2008-12-3 下午03:15:27
??? ?*
??? ?* @param binary
??? ?*??????????? 需要格式化的字節。
??? ?* @param toAppendTo
??? ?*??????????? 追加到的Builder。
??? ?*
??? ?* @return 格式化后的StringBuilder。
??? ?*/
??? public static StringBuilder formatBinary(String binary,
??? ??? ??? StringBuilder toAppendTo) {
??? ??? return formatBinary(binary, toAppendTo, EncryptDecrypt.EIGHT_BIT);
??? }
??? /**
??? ?* 格式化二進制,超過則截取,不足則補零。格式:“00000000”,與NumberFormat的pattern:“########”類似。
??? ?*
??? ?* @author terry
??? ?* @version 2008-12-3 下午03:15:31
??? ?*
??? ?* @param binary
??? ?*??????????? 需要格式化的字節。
??? ?* @param toAppendTo
??? ?*??????????? 追加到的Builder。
??? ?* @param bitCount
??? ?*??????????? 追加到的Builder。
??? ?*
??? ?* @return 格式化后的StringBuilder。
??? ?*/
??? public static StringBuilder formatBinary(String binary,
??? ??? ??? StringBuilder toAppendTo, int bitCount) {
??? ??? if (binary == null || binary.length() < 1) {
??? ??? ??? return toAppendTo;
??? ??? }
??? ??? if (toAppendTo == null) {
??? ??? ??? toAppendTo = new StringBuilder();
??? ??? }
??? ??? if (binary.length() == bitCount) {
??? ??? ??? toAppendTo.append(binary);
??? ??? ??? return toAppendTo;
??? ??? }
??? ??? /*
??? ??? ?* 前補0, 如: "100011" to "00100011"
??? ??? ?*/
??? ??? if (binary.length() < bitCount) {
??? ??? ??? StringBuilder formatted = new StringBuilder();
??? ??? ??? formatted.append(binary);
??? ??? ??? do {
??? ??? ??? ??? formatted.insert(0, "0");
??? ??? ??? } while (formatted.length() < bitCount);
??? ??? ??? toAppendTo.append(formatted);
??? ??? ??? return toAppendTo;
??? ??? }
??? ??? /*
??? ??? ?* 截取, 如: "11111111111111111111111110100011" to "10100011"
??? ??? ?*/
??? ??? if (binary.length() > bitCount) {
??? ??? ??? String intercepted = binary.substring(binary.length() - bitCount);
??? ??? ??? toAppendTo.append(intercepted);
??? ??? ??? return toAppendTo;
??? ??? }
??? ??? return toAppendTo;
??? }
}