這個演算法不知道什麼時候出來的,discuz中用它來記錄使用者資訊,存到用戶端瀏覽器的cookie中,每次請求時,服務端解開它,得到使用者資訊,下面這段代碼是java的實現,從網上搜到一些原始代碼,改造了一下。
效能還可以,雙核2G主頻,8線程,可以穩定在13萬tips以上,比從資料庫、cache取資料要高效非常多。
明文、密碼越長加密越慢,相同明文、密碼,每次加密結果不同,解密結果相同。
不知道他的安全性怎樣,discuz應該不會犯這種錯誤吧。如果可靠,用來解決“多伺服器叢集session共用問題”是個好辦法,discuz就是用這種方法。
package com.huawei.core.common.util;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class AzDGCrypt {
/**
* 加密函數
* @param txt string 等待加密的原字串
* @param key string 私人密匙(用於解密和加密)
* @return string 經過私人密匙加密後的結果
*/
public final static String encrypt(String txt, String key){
//使用隨機數發生器產生 0~32000 的值並 MD5()
String encryptKey = Utils.md5(int2Bytes((int)(Math.random() * 32000)));
int ctr = 0;
StringBuilder ciphertext = new StringBuilder();
int len = txt.length();
int ekLen = encryptKey.length();
for(int i = 0; i < len; i++) {
ctr = ctr == ekLen ? 0 : ctr; //如果ctr = encryptKey 的長度,則ctr清零
char a1 = encryptKey.charAt(ctr);
char t1 = txt.charAt(i);
char t2 = encryptKey.charAt(ctr++);
char a2 = (char)(t1 ^ t2);
ciphertext.append(a1).append(a2);
}
return Base64.encode((passport_key(ciphertext.toString(), key)).getBytes());
}
/**
* 解密函數
* @param string 加密後的字串
* @param string 私人密匙(用於解密和加密)
* @return string 字串經過私人密匙解密後的結果
* @throws Base64DecodingException
*/
public final static String decrypt(String ciphertext, String key) throws Base64DecodingException {
String txt = passport_key(new String(Base64.decode(ciphertext)), key);
int len = txt.length();
StringBuilder plaintext = new StringBuilder();
for (int i = 0; i < len; i++) {
//txt的第i位,與 txt的第i+1位取異或
plaintext.append((char)(txt.charAt(i) ^ txt.charAt(++i)));
}
return plaintext.toString();
}
/**
* Passport 密匙處理函數
* @param string 待加密或待解密的字串
* @param string 私人密匙(用於解密和加密)
* @return string 處理後的密匙
*/
private final static String passport_key(String txt, String key){
String encryptKey = Utils.md5(key);
int ctr = 0;
int len = txt.length();
int ekLen = encryptKey.length();
StringBuilder plaintext = new StringBuilder();
for(int i = 0; i < len; i++) {
ctr = ctr == ekLen ? 0 : ctr;
plaintext.append((char)(txt.charAt(i) ^ encryptKey.charAt(ctr++)));
}
return plaintext.toString();
}
private final static byte[] int2Bytes(int x) {
byte[] v = new byte[4];
for(int i = 0; i < 4; i++) { //小端序,因為不需要還原
v[i] = (byte)x;
x >>= 8;
}
return v;
}
public static void main(String[] args) throws Exception {
int threadNum = 8;
final int N = 1000000;
final CountDownLatch counter = new CountDownLatch(threadNum);
ExecutorService exectors = Executors.newFixedThreadPool(threadNum);
final String txt = "dddaa000000000000000aeee";
final String key = "ddd000000000000000000000";
long t1 = System.currentTimeMillis();
for(int j = 0; j < threadNum; j++) {
exectors.execute(new Runnable(){
public void run() {
String s;
System.out.println("start");
try {
for(int i = 0; i < N; i++) {
s = AzDGCrypt.encrypt(txt, key);
//System.out.println("txt:" + txt + " key:" + key + " txt after crypt:" + s);
s = AzDGCrypt.decrypt(s, key);
//System.out.println("txt:" + txt + " key:" + key + " txt after decrypt:" + s);
}
} catch(Exception e) {
e.printStackTrace();
}
counter.countDown();
System.out.println("end");
}
});
}
counter.await();
long t2 = System.currentTimeMillis();
System.out.println("speed=" + (1000 * (threadNum * N / (t2 - t1))));
System.exit(0);
}
}