Chapter 18.自制可逆等位字符串加密解密(編碼解碼)

歡迎來到「我是真的狗雜談世界」娶桦,關(guān)注不迷路

背景

最近做的項目多次遇到了分享邀請的需求點,即需要在接受邀請時能識別到邀請者的信息,又需要考慮信息敏感性啦逆,沒找到成熟的三方實現(xiàn),于是自己思考實現(xiàn)了兩套齐媒。

思路方案

不能直接將邀請信息用于傳遞巷帝,需要對信息(一般是字符串,不是字符串也可以轉(zhuǎn)換為字符串)進(jìn)行加密處理研侣,或者說編碼處理谱邪。但同時需要滿足一下要求:

要求

  • 可逆:加密(編碼)后的密文應(yīng)當(dāng)能通過解密(解碼)獲得原文,否則就無法獲得邀請者信息了庶诡;
  • 長度:加密(編碼)后的密文應(yīng)該盡可能與原文長度相當(dāng)惦银,可以略多(如果能更少也好,不過那需要涉及壓縮了末誓,不是今天的重點)扯俱;
  • 內(nèi)容:加密(編碼)后的密文應(yīng)當(dāng)是可預(yù)知的字符集合雄坪,如果可設(shè)置更好湖笨;
  • 算法可公開(意味著存在額外依賴):不單單依靠一個固定算法,即便算法公開仍舊能保證安全性张漂,否則算法一旦被破解也就沒什么了晴玖;
  • 復(fù)雜度適當(dāng):太復(fù)雜的一般對計算要求很高读存,對開發(fā)(本人)成本也高,能滿足目前的項目需求即可(我絕對不會說我懶)呕屎;

常見算法

常見的一些加密解密让簿、編碼解碼算法:

  • 單向:md系列、sha1榨惰;
  • 對稱:des拜英、aes;
  • 非對稱:rsa琅催、dsa居凶;
  • 簡單編碼:base64虫给;

移位法

本質(zhì)

  • 維護(hù)全量字符可能的順序,對給定字符串的每個字符按照其位置進(jìn)行移位轉(zhuǎn)換侠碧,得到結(jié)果抹估;
  • 位置到字符移位偏移量通過一套外部輸入的規(guī)則來指定;
  • 上述兩步相當(dāng)于將字符枚舉弄兜、順序药蜻、偏移量規(guī)則三套作為算法變量交由用戶控制,在不能完全知道三個信息的情況下替饿,即便知道算法语泽,也能保障密文安全性;

防篡改

  • 雖然用移位法可以保障用戶無法通過密文還原原文视卢,但用戶可以用大量無序密文來攻擊踱卵,造成大量垃圾數(shù)據(jù)或暴力猜測到一些信息,因此還需要支持能校驗密文是否合法的功能据过,也就是防篡改惋砂。
  • 通用的思路是額外加一點校驗數(shù)據(jù),由原文構(gòu)造而成加入到密文中绳锅,解密(解碼)時校驗一遍作為驗證即可西饵,比如網(wǎng)絡(luò)IP和TCP層的累加和就是這種思路。

實現(xiàn)

    public function encrypt(string $value): string
    {
        if (0 == $this->sortCount) {
            throw new EncrypterException('未設(shè)置字符排布陣列');
        }
        if (0 == $this->shiftingCount) {
            throw new EncrypterException('未設(shè)置編碼密鑰');
        }
        $encrypted = '';
        for ($i = 0; $i < strlen($value); $i++) {
            if (!key_exists($value[$i], $this->sortList)) {
                throw new EncrypterException('發(fā)現(xiàn)不期待的字符');
            }
            $index = $this->sortList[$value[$i]];
            $index += $this->shiftingList[$i % $this->shiftingCount];
            $index %= $this->sortCount;
            $encrypted .= $this->sort[$index];
        }

        // 添加校驗位
        if ($this->checkSum) {
            $sum = 0;
            for ($i = 0; $i < strlen($value); $i++) {
                $sum += ord($value[$i]);
            }
            $sum %= $this->sortCount;
            $start = $this->sort[$sum];
            $end = $this->sort[$this->sortCount - $sum - 1];
            $encrypted = $start . $encrypted . $end;
        }

        return $encrypted;
    }
    public function decrypt(string $value): string
    {
        if (0 == $this->sortCount) {
            throw new EncrypterException('未設(shè)置字符排布陣列');
        }
        if (0 == $this->shiftingCount) {
            throw new EncrypterException('未設(shè)置編碼密鑰');
        }

        // 拿出校驗位
        if ($this->checkSum) {
            if (strlen($value) < 2) {
                throw new EncrypterException('解密校驗失敗');
            }
            $start = $value[0];
            $end = $value[strlen($value) - 1];
            $value = substr($value, 1, -1);
        }

        $decrypted = '';
        for ($i = 0; $i < strlen($value); $i++) {
            if (!key_exists($value[$i], $this->sortList)) {
                throw new EncrypterException('發(fā)現(xiàn)不期待的字符');
            }
            $index = $this->sortList[$value[$i]];
            $index -= $this->shiftingList[$i % $this->shiftingCount];
            while ($index < 0) {
                $index += $this->sortCount;
            }
            $decrypted .= $this->sort[$index];
        }

        // 校驗校驗位
        if ($this->checkSum) {
            $sum = 0;
            for ($i = 0; $i < strlen($decrypted); $i++) {
                $sum += ord($decrypted[$i]);
            }
            $sum %= $this->sortCount;
            if ($start != $this->sort[$sum] || $end != $this->sort[$this->sortCount - $sum - 1]) {
                throw new EncrypterException('解密校驗失敗');
            }
        }

        return $decrypted;
    }

特點分析

  • 需要知道原文全部字符構(gòu)成可能鳞芙;
  • 原文和密文的字符構(gòu)成是同一個集合眷柔;
  • 密文與原文長度相等,即使加入校驗位也僅多2位积蜻;
  • 適用于前端闯割、用戶可見可感知的傳遞場景;

異或法

本質(zhì)

  • 利用abb=a竿拆,也就是兩次異或復(fù)位的特性(字符可轉(zhuǎn)換成一個數(shù)值也就是一個多位的二進(jìn)制宙拉,單位異或的特性在多位場景下同樣成立)
  • 同樣與原文、密文每個字符進(jìn)行異或操作的字符應(yīng)該與其位置規(guī)則有關(guān)丙笋,同移位法相關(guān)規(guī)則

可讀性

由于異或后的值可能超過輸入原值谢澈,字符轉(zhuǎn)換時可能轉(zhuǎn)換為非常用字符影響閱讀,因此可以選擇嵌套一層base64加解密方便閱讀御板。

實現(xiàn)

    public function encrypt(string $value): string
    {
        $value = $this->handle($value);
        if ($this->base64) {
            $value = base64_encode($value);
        }
        return $value;
    }
    public function decrypt(string $value): string
    {
        if ($this->base64) {
            $value = base64_decode($value);
        }
        return $this->handle($value);
    }
    protected function handle(string $string): string
    {
        $result = '';
        for ($i = 0; $i < strlen($string); $i++) {
            $t = $this->secret[$i % $this->secretCount];
            $result .= chr(ord($string[$i]) ^ ord($t));
        }
        return $result;
    }

分析

  • 即便不知道原文字符全部可能也可以使用這套算法锥忿;
  • 但原文和密文的字符構(gòu)成不是同一個集合;
  • base64后密文一般較原文長怠肋,具體見base64編碼算法規(guī)則敬鬓;
  • 適用于接口間、服務(wù)間數(shù)據(jù)傳輸場景;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钉答,一起剝皮案震驚了整個濱河市础芍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌数尿,老刑警劉巖仑性,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異右蹦,居然都是意外死亡诊杆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門何陆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晨汹,“玉大人,你說我怎么就攤上這事甲献≡诅停” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵晃洒,是天一觀的道長。 經(jīng)常有香客問我朦乏,道長球及,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任呻疹,我火速辦了婚禮吃引,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刽锤。我一直安慰自己镊尺,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布并思。 她就那樣靜靜地躺著庐氮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宋彼。 梳的紋絲不亂的頭發(fā)上弄砍,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機與錄音输涕,去河邊找鬼音婶。 笑死,一個胖子當(dāng)著我的面吹牛莱坎,可吹牛的內(nèi)容都是我干的衣式。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碴卧!你這毒婦竟也來了弱卡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤螟深,失蹤者是張志新(化名)和其女友劉穎谐宙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體界弧,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡凡蜻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了垢箕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片划栓。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖条获,靈堂內(nèi)的尸體忽然破棺而出忠荞,到底是詐尸還是另有隱情,我是刑警寧澤帅掘,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布委煤,位于F島的核電站,受9級特大地震影響修档,放射性物質(zhì)發(fā)生泄漏碧绞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一吱窝、第九天 我趴在偏房一處隱蔽的房頂上張望讥邻。 院中可真熱鬧,春花似錦院峡、人聲如沸兴使。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽发魄。三九已至,卻和暖如春实抡,著一層夾襖步出監(jiān)牢的瞬間欠母,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工吆寨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赏淌,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓啄清,卻偏偏與公主長得像六水,于是被迫代替她去往敵國和親俺孙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容

  • [toc] 常見編碼 1.ASCII編碼 ASCII編碼大致可以分作三部分組成: 第一部分是:ASCII非打印控制...
    William92閱讀 4,010評論 0 1
  • 簡介 本文總結(jié)了在爬蟲中常見的各種加密算法掷贾、編碼算法的原理睛榄、在 JavaScript 中和 Python 中的基本...
    K哥爬蟲閱讀 564評論 0 0
  • 軟件的加密與解密是一個迷人的研究領(lǐng)域场靴,它幾乎可以與任意一種計算機技術(shù)緊密結(jié)合——密碼學(xué)、程序設(shè)計語言港准、操作系統(tǒng)旨剥、數(shù)...
    架構(gòu)通天之路閱讀 664評論 0 0
  • 前言:很多人認(rèn)為MD5是一種加密算法,其實嚴(yán)格來說MD5是為計算機安全領(lǐng)域廣泛使用的一種散列函數(shù)浅缸,用以提供消息的完...
    Orz013閱讀 1,942評論 0 0
  • IOS應(yīng)用安全-加解密算法簡述 導(dǎo)讀客戶端經(jīng)常遇到需要對數(shù)據(jù)進(jìn)行加密的情況轨帜,那應(yīng)該如何加密,選用什么樣的加密算法衩椒,...
    蘿卜_7fad閱讀 649評論 0 0