在當(dāng)前h5各種活動漫天轟炸的時(shí)代,大量的訪問量給h5帶來了機(jī)遇,同時(shí)也帶來了一些安全隱患,如何能對數(shù)據(jù)進(jìn)行一些合理的加密成了我們H5必須考慮的問題,今天就先寫下異或
一、 XOR 運(yùn)算
邏輯運(yùn)算之中,除了 AND 和 OR,還有一種 XOR 運(yùn)算,中文稱為"異或運(yùn)算"。
它的定義是:兩個(gè)值相同時(shí),返回false,否則返回true。也就是說,XOR可以用來判斷兩個(gè)值是否不同。
true XOR true // false false XOR false // false true XOR false // true true XOR false // true

JavaScript 語言的二進(jìn)制運(yùn)算,有一個(gè)專門的 XOR 運(yùn)算符,寫作^。
1 ^ 1 // 0 0 ^ 0 // 0 1 ^ 0 // 1 0 ^ 1 // 1
上面代碼中,如果兩個(gè)二進(jìn)制位相同,就返回0,表示false;否則返回1,表示true。
二、 XOR 的應(yīng)用
XOR 運(yùn)算有一個(gè)很奇妙的特點(diǎn):如果對一個(gè)值連續(xù)做兩次 XOR,會返回這個(gè)值本身。
// 第一次 XOR 1010 ^ 1111 // 0101 // 第二次 XOR 0101 ^ 1111 // 1010
上面代碼中,原始值是1010,再任意選擇一個(gè)值(上例是1111),做兩次 XOR,最后總是會得到原始值1010。這在數(shù)學(xué)上是很容易證明的。
三、加密應(yīng)用
XOR 的這個(gè)特點(diǎn),使得它可以用于信息的加密。
message XOR key // cipherText cipherText XOR key // message
上面代碼中,原始信息是message,密鑰是key,第一次 XOR 會得到加密文本cipherText。對方拿到以后,再用key做一次 XOR 運(yùn)算,就會還原得到message。

四、完美保密性
二戰(zhàn)期間,各國為了電報(bào)加密,對密碼學(xué)進(jìn)行了大量的研究和實(shí)踐,其中就包括 XOR 加密。

戰(zhàn)后,美國數(shù)學(xué)家香農(nóng)(Claude Shannon)將他的研究成果公開發(fā)表,證明了只要滿足兩個(gè)條件,XOR 加密是無法破解的。
key的長度大于等于messagekey必須是一次性的,且每次都要隨機(jī)產(chǎn)生
理由很簡單,如果每次的key都是隨機(jī)的,那么產(chǎn)生的CipherText具有所有可能的值,而且是均勻分布,無法從CipherText看出message的任何特征。也就是說,它具有最大的"信息熵",因此完全不可能破解。這被稱為 XOR 的"完美保密性"(perfect secrecy)。
滿足上面兩個(gè)條件的key,叫做 one-time pad(縮寫為OTP),意思是"一次性密碼本",因?yàn)橐郧斑@樣的key都是印刷成密碼本,每次使用的時(shí)候,必須從其中挑選key。
五、實(shí)例:哈希加密
下面的例子使用 XOR,對用戶的登陸密碼進(jìn)行加密。實(shí)際運(yùn)行效果看這里。
第一步,用戶設(shè)置登陸密碼的時(shí)候,算出這個(gè)密碼的哈希,這里使用的是 MD5 算法,也可以采用其他哈希算法。
const message = md5(password);
第二步,生成一個(gè)隨機(jī)的 key。
// 生成一個(gè)隨機(jī)整數(shù),范圍是 [min, max] function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } // 生成一個(gè)隨機(jī)的十六進(jìn)制的值,在 0 ~ f 之間 function getHex() { let n = 0; for (let i = 4; i > 0; i--) { n = (getRandomInt(0, 1) << (i - 1)) + n; } return n.toString(16); } // 生成一個(gè)32位的十六進(jìn)制值,用作一次性 Key function getOTP() { const arr = []; for (let i = 0; i < 32; i++) { arr.push(getHex()); } return arr.join(''); }
上面代碼中,生成的key是32位的十六進(jìn)制值,對應(yīng) MD5 產(chǎn)生的128位的二進(jìn)制哈希。
第三步,進(jìn)行 XOR 運(yùn)算,求出加密后的message。
function getXOR(message, key) { const arr = []; for (let i = 0; i < 32; i++) { const m = parseInt(message.substr(i, 1), 16); const k = parseInt(key.substr(i, 1), 16); arr.push((m ^ k).toString(16)); } return arr.join(''); }
使用這種方法保存用戶的登陸密碼,即使加密文本泄露,只要一次性的密鑰(key)沒有泄露,對方也無法破解。
典型XOR解密及unicode轉(zhuǎn)義漢字
// 異或解密(異或加密相當(dāng)于一個(gè)雙重加密,雙重保障更安全)
export function Restore(str, keyIndex)
{
var crytxt = '';
var k, keylen = keyIndex.length;
for(var i=0; i<str.length; i++) {
k = i % keylen;
crytxt += String.fromCharCode(str.charCodeAt(i) ^ keyIndex.charCodeAt(k));
}
return toChineseWords(crytxt);
}
export function toChineseWords(data){
var str= unescape(data.replace(/\\/g, "%"));
str= JSON.parse(str);
return str
}
