從編碼開始
在計算機中,所有的數據都是1或者0。因而密鑰也好,數據也好,在計算機中,都是1或0
在UI開發中,經常會有 #000000(黑色)、#FFFFFF(白色)這樣的色值表示。這些設置,就是將三個字節的1、0(24位)用 hex (16進制) 編碼的形式,簡化成了6位數,方便顯示;
文字,在計算機中也是1、0,采用的編碼形式有多種,但本質上也一樣是將一定字節的1、0 和 固定的字符匹配起來。常用的文字編碼有 UTF-8(三字節表示一個中文,一字節表示英文;除中文外還兼容日、韓、英等其他文字)、GBK(兩字節表示一個中文,兼容英語,英語也用2字節表示)等
UTF-8 的編碼形式為 String 默認編碼。在 java 中,調用默認的 String.toByteArray()
方法,默認的就是用UTF-8編碼。
對稱加密中 SM4 或者 AES 的密鑰,128位,16字節。若是用1、0表示,則太長了。因而,需要采用編碼的形式,將冗長的字節數組簡潔化(雖然依舊看不懂記不住。。。)
密鑰常見編碼形式
密鑰一般以 hex(二進制)或者Base64 進行編碼。
因為這兩種編碼之后,沒有特殊字符。hex 只有數字和英文字符 a - f; base64 只有數字、英文、符號 +、/、=
如果采用 UTF - 8 之類的編碼,可能在json中出現一個雙引號,導致整個 json 解析失敗;又或是根本找不到編碼對應的文字,出現亂碼
hex 編碼的實質
hex 為 16 進制,超出10 部分無法用數字表達,則用 英文 a-f 依次遞增,大小寫不限
Base64 編碼的實質
Base64 編碼,會對原始 byte 數組進行重新劃分。在編碼時,以每三個字節為一組,一個字節八位,會拆成 4 份 6 位,然后在高位補兩個0,形成 4 個字節。如果 byte 數組長度非 3 倍數,則在后續補 0。
步驟 | 第一字節 | 第二字節 | 第三字節 | 第四字節 |
---|---|---|---|---|
原始三個字節: | 11111111 | 11111111 | 11111111 | |
拆分四組: | 111111 | 111111 | 111111 | 111111 |
高位補零: | 00111111 | 00111111 | 00111111 | 00111111 |
Base64 編碼中,全 0 為大寫 A,為了在解碼中不造成誤解,最后補齊的字符串用 = 號表示。這也是為什么Base64編碼后的字符串,后面經常以一個或者兩個 = 號結尾。且一字節有效位數 64 位(僅第六位有效),而 Base64 包含的字符包括 A-Z、a-z、0-9、+、/、=,共 26 * 2 + 10 + 3 = 65 種字符,= 號不在編碼范圍內,只用做補齊標記
Base64 編碼的幾種標準
DEFAUTL:正常編碼,編碼完成后,每隔76字符輸出一個換行符
NO_PADDING:末尾沒有填充字符 =
NO_WRAP:正常編碼,沒有換行符輸出(一般簽名都使用該標準)
CRLF:自動換行的換行符指定為 win 風格,設置為 NO_WRAP 后,沒有換行,即此設置無效
URL_SAFE:字符 “+” 和 “/” 會被 “-” 和 ”_“ 替代,以避免url 和文件名歧義
NO_CLOSE:通常與Base64OutputStream
一起使用,是傳遞給Base64OutputStream
的標志指示它不應關閉正在包裝的輸出流編碼后再解碼,需采用同等編解碼方式
如,一個字節的0(0x00),hex編碼后,字符串顯示 "00",若再對字符串進行 UTF-8解碼,byte數組則會變成 0x3030