準備一些需要的工具,友善後面的虛拟場景
密碼本A的字元坐标規則:假設一個字元的密文由三部分組成,順序分别是"U+5600的56"+"表格最上方的坐标"+"表格最左邊的坐标",舉例"570B"是"國","56E7"是"囧",如下第一個和第二個密碼表,這些密文是16進制的格式,下同

密碼本B的字元坐标規則:假設一個字元的密文由三部分組成,順序分别是"表格左上角的字元串"+"表格最左邊的坐标"+"表格最上方的坐标",舉例"87E5"是"囧","87F8"是"國",如下第一個密碼表,這些密文也是16進制的格式,下同
即我們可能還需要對我們拿到的密文進行再一次的加密,比如”囧”的密文是” "56E7”按照開頭假設的密文規則,這是16進制的數,那我們還需要把這個16進制的56E7通過一定的規則,再次加密,針對這兩個密碼本的加密規則假設如下:
密碼本A密文再次加密規則:
16進制密文轉換為10進制後對應的範圍
16進制數轉換為2進制後對應的加密格式
0至127
0xxxxxxx
128至2047
110xxxxx 10xxxxxx
2048至65535
1110xxxx 10xxxxxx 10xxxxxx
65536至2097151
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
比如56E7這個密文再次加密,他轉換成10進制是22247,22247在”2048-65535”的範圍内,那他的加密格式就是1110xxxx10xxxxxx10xxxxxx,暫且稱它為466格式,如何加密呢?如下:
先把56E7轉換成二進制為:0101011011100111
按照1110xxxx 10xxxxxx 10xxxxxx的格式,對56E7轉換成的二進制0101011011100111進行拆分:
首先,0101011011100111--------按照4 6 6的格式拆分後--------->0101 011011 100111
然後,對0101 011011 100111按照466格式進行轉換------->11100101 10011011 10100111
把轉換後的111001011001101110100111轉換為16進制就是e59ba7,e59ba7就是56E7再次加密的最終密文,這樣就由原來的"56E7"是"囧"變成" E59BA7"是"囧",甚至可以根據這個加密方式,生成一個新的密碼本C
密碼本B的再次加密規則:
密碼本B的16進制密文不再進行二次加密,直接使用獲得的16進制密文,例如56E7不會與密碼本A一樣再次加密,直接使用56E7
模拟一個虛構的場景,場景裡的元素是:
遠在外地的小明
與小明同部門的小麗
安全部門的同學
與小明同部門的小紅
一個資訊安全非常嚴格的公司
加密的檔案管理
今天,小明需要将一個很重要的資料,告訴公司的小麗把這個資料存到小明自己的檔案裡:
、
小明發現,他擷取到的資料是“闃塊噷”,而不是3天前存儲的”阿裡”,如果小明意識到自己的錯誤,把小紅寄給他的資料先轉換成密碼本B的密文,再用轉換的密文對照密碼本A查找呢?
字元集:
unicode gbk
字元編碼規則:
utf8:隻針對unicode,相當于第一章情景中的二次加密
gbk:不對gbk再編碼
參數與情景對應:
程式字元集:小明加密資料時使用的密碼本A
character_set_client:小明在寄信時,寫錯了資料加密方式,寫的是密碼本B,而不是A
character_set_connection:安全規則,需要轉換的加密格式
character_set_results:寄信時需要使用的加密格式
表或者庫字元集:小明的檔案的加密格式
Server端處理:小麗/小紅
參數設定:
程式字元集:utf8
character_set_client:utf8
character_set_connection:utf8
character_set_results:utf8
表或者庫字元集:utf8
Server端處理:mysql program
測試結果:無亂碼
character_set_client:gbk
測試結果:隻設定set character_set_client=gbk後,查詢亂碼
結合第一章的場景,為什麼亂碼呢?
程式将"阿裡"以utf8編碼進行轉換發送(unicode轉utf8與情景中的規則一緻),但是不小心在session中設定了character_set_client=gbk,character_set_connection =utf8,character_set_results=utf8,類似如下現象:
形狀:阿裡
Utf8方式下的16進制編碼值:E998BF E9878C
二進制:11101001 10011000 10111111 11101001 10000111 10001100(utf8将2個漢字轉換後6個位元組)
到達server端,server通過character_set_client=gbk知道用戶端發過來的資料是gbk編碼的(實際是utf8編碼的,用戶端不小心寫錯了),那server端就按照gbk來解碼了,解碼後如下:
二進制:11101001 10011000 10111111 11101001 10000111 10001100(程式端的兩個漢字經過utf8轉換後的二進制資料,一共6位元組,但是server端不知道,因為server通過character_set_client=gbk得知,這不是utf8,這是gbk的,我要按照gbk來解碼)
gbk轉換後的16進制編碼值:E998 BFE9 878C(通過這個編碼,查找gbk的碼表,擷取他的形狀為:闃塊噷)
Servre還需要檢查character_set_connection參數,發現character_set_connection=utf8,而之前是gbk,那就需要将gbk的這三個位元組轉換為utf8,怎麼轉換呢?按照第一章的情景,先轉unicode(密碼本A),再将得到的unicode再次編碼為utf8:
“闃塊噷“三個字元的unicode編碼是 95c3 5757 5677
轉換成二進制:10010101 11000011 01010111 01010111 01010110 01110111(這三個漢字是6個位元組)
通過unicode,再轉換為utf8的實作方式,實作方式如下:
首先轉換95c3( 1001010111000011),他的範圍在第三行(3位元組)
1001 010111 000011,根據第三行的格式,從低位往高位的順序,按照格式分成4 6 6 的格式
按照格式填充,填充後:11101001 10010111 10000011,填充後轉換成16進制是e99783,則”闃”在utf8中就是”e99783”,同樣,”塊”在utf8中就是” e59d97”,” 噷”在utf8中就是” e599b7”, 于是轉換後的結果就是:
編碼:E99783 E59D97 E599B7
二進制:111010011001011110000011111001011001110110010111111010000000000000000000
server端處理好之後,繼續向下走,準備存儲資料了,檢查了存儲的表是utf8的,不需要轉換了,直接存儲
程式插入完成後,想查詢下之前插入的資料,于是用戶端在目前session下執行了select操作,server端收到請求後,去表裡找資料,找到了之前寫入的資料
111010011001011110000011111001011001110110010111111010000000000000000000
server檢查character_set_results=utf8,與表的字元編碼是一緻的,那就不需要轉換了,直接把111010011001011110000011111001011001110110010111111010000000000000000000給程式了,程式收到後,就解碼111010011001011110000011111001011001110110010111111010000000000000000000,因為程式本身也是utf8的,不需要轉換,于是按照utf8來解碼資料,111010011001011110000011111001011001110110010111111010000000000000000000的16進制是E99783E59D97E599B7(符号是闃塊噷,亂碼了)