iOS開發(fā)探索-Base64編碼

Base64編碼原理

Base64編碼之所以稱為Base64,是因為其使用64個字符來對任意數(shù)據(jù)進(jìn)行編碼,同理有Base32、Base16編碼。標(biāo)準(zhǔn)Base64編碼使用的64個字符為:

Base64編碼表

這64個字符是各種字符編碼(比如ASCII編碼)所使用字符的子集,基本,并且可打印。唯一有點特殊的是最后兩個字符,因?qū)ψ詈髢蓚€字符的選擇不同,Base64編碼又有很多變種,比如Base64 URL編碼。

Base64編碼本質(zhì)上是一種將二進(jìn)制數(shù)據(jù)轉(zhuǎn)成文本數(shù)據(jù)的方案。對于非二進(jìn)制數(shù)據(jù),是先將其轉(zhuǎn)換成二進(jìn)制形式,然后每連續(xù)6比特(2的6次方=64)計算其十進(jìn)制值,根據(jù)該值在上面的索引表中找到對應(yīng)的字符,最終得到一個文本字符串。

假設(shè)我們要對 Hello! 進(jìn)行Base64編碼,按照ASCII表,其轉(zhuǎn)換過程如下圖所示:

轉(zhuǎn)換過程

可知 Hello! 的Base64編碼結(jié)果為 SGVsbG8h ,原始字符串長度為6個字符,編碼后長度為8個字符,每3個原始字符經(jīng)Base64編碼成4個字符,編碼前后長度比4/3,這個長度比很重要 - 比原始字符串長度短,則需要使用更大的編碼字符集,這并不我們想要的;長度比越大,則需要傳輸越多的字符,傳輸時間越長。Base64應(yīng)用廣泛的原因是在字符集大小與長度比之間取得一個較好的平衡,適用于各種場景。

是不是覺得Base64編碼原理很簡單?

但這里需要注意一個點:Base64編碼是每3個原始字符編碼成4個字符,如果原始字符串長度不能被3整除,那怎么辦?使用0值來補充原始字符串。

以 Hello!! 為例,其轉(zhuǎn)換過程為:


轉(zhuǎn)換過程

注:圖表中藍(lán)色背景的二進(jìn)制0值是額外補充的。

Hello!! Base64編碼的結(jié)果為 SGVsbG8hIQAA 。最后2個零值只是為了Base64編碼而補充的,在原始字符中并沒有對應(yīng)的字符,那么Base64編碼結(jié)果中的最后兩個字符 AA 實際不帶有效信息,所以需要特殊處理,以免解碼錯誤。

標(biāo)準(zhǔn)Base64編碼通常用 = 字符來替換最后的 A,即編碼結(jié)果為 SGVsbG8hIQ==。因為 = 字符并不在Base64編碼索引表中,其意義在于結(jié)束符號,在Base64解碼時遇到 = 時即可知道一個Base64編碼字符串結(jié)束。

如果Base64編碼字符串不會相互拼接再傳輸,那么最后的 = 也可以省略,解碼時如果發(fā)現(xiàn)Base64編碼字符串長度不能被4整除,則先補充 = 字符,再解碼即可。

解碼是對編碼的逆向操作,但注意一點:對于最后的兩個 = 字符,轉(zhuǎn)換成兩個 A 字符,再轉(zhuǎn)成對應(yīng)的兩個6比特二進(jìn)制0值,接著轉(zhuǎn)成原始字符之前,需要將最后的兩個6比特二進(jìn)制0值丟棄,因為它們實際上不攜帶有效信息。

以下為示例代碼

1.通過NSString+Base64分類來實現(xiàn)
#import <Foundation/Foundation.h>
@interface NSString (Base64)
/**
 *  轉(zhuǎn)換為Base64編碼
 */
 - (NSString *)base64EncodedString;
 /**
 *  將Base64編碼還原
 */
 - (NSString *)base64DecodedString;
 @end

`
#import "NSString+Base64.h"
@implementation NSString (Base64)

- (NSString *)base64EncodedString;
{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
return [data base64EncodedStringWithOptions:0];
}

- (NSString *)base64DecodedString
{
NSData *data = [[NSData alloc]initWithBase64EncodedString:self options:0];
return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
}

@end
2. 調(diào)用方法實現(xiàn)
NSString *codeString = @"Hello world";
NSLog(@"原文--%@",codeString);

NSString *base64Str = [codeString base64EncodedString];
NSLog(@"Base64編碼--%@",base64Str);

NSString *decodeStr = [base64Str base64DecodedString];
NSLog(@"Base64解碼--%@",decodeStr);
3.測試結(jié)果
Base64編碼測試結(jié)果
切忌誤用

可能會有人在不理解Base64編碼的情況下,將其誤用于數(shù)據(jù)加密或數(shù)據(jù)校驗。

Base64是一種數(shù)據(jù)編碼方式,目的是讓數(shù)據(jù)符合傳輸協(xié)議的要求。標(biāo)準(zhǔn)Base64編碼解碼無需額外信息即完全可逆,即使你自己自定義字符集設(shè)計一種類Base64的編碼方式用于數(shù)據(jù)加密,在多數(shù)場景下也較容易破解。

對于數(shù)據(jù)加密應(yīng)該使用專門的目前還沒有有效方式快速破解的加密算法。比如:對稱加密算法AES-128-CBC,對稱加密需要密鑰,只要密鑰沒有泄露,通常難以破解;也可以使用非對稱加密算法,如 RSA,利用極大整數(shù)因數(shù)分解的計算量極大這一特點,使得使用公鑰加密的數(shù)據(jù),只有使用私鑰才能快速解密。

對于數(shù)據(jù)校驗,也應(yīng)該使用專門的消息認(rèn)證碼生成算法,如 HMAC - 一種使用單向散列函數(shù)構(gòu)造消息認(rèn)證碼的方法,其過程是不可逆的、唯一確定的,并且使用密鑰來生成認(rèn)證碼,其目的是防止數(shù)據(jù)在傳輸過程中被篡改或偽造。將原始數(shù)據(jù)與認(rèn)證碼一起傳輸,數(shù)據(jù)接收端將原始數(shù)據(jù)使用相同密鑰和相同算法再次生成認(rèn)證碼,與原有認(rèn)證碼進(jìn)行比對,校驗數(shù)據(jù)的合法性。

總結(jié)

Base64兼顧字符集大小和編碼后數(shù)據(jù)長度,并且可以靈活替換字符集的最后兩個字符,以應(yīng)對多樣的需求,使其適用場景非常廣泛。

在此感謝各位讀者的來訪,您的關(guān)注是我寫作分享的最大動力。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Base64編碼原理 Base64編碼之所以稱為Base64,是因為其使用64個字符來對任意數(shù)據(jù)進(jìn)行編碼,同理有B...
    edison0428閱讀 1,731評論 1 1
  • # 簡介 Base64是一種用64個字符來表示任意二進(jìn)制數(shù)據(jù)的方法。是一種編碼方法,有自己的編碼表,所以稱為Bas...
    Tenloy閱讀 4,084評論 0 4
  • 一、介紹 Base64編碼是一種數(shù)據(jù)編碼方式,目的是讓數(shù)據(jù)符合傳輸協(xié)議的要求。能夠?qū)⑷魏味M(jìn)制數(shù)據(jù),轉(zhuǎn)換成只有64...
    MrSYLong閱讀 2,442評論 1 0
  • Base64編碼是一種用64個字符(其實是65個字符,“=”是填充字符)來表示任意二進(jìn)制數(shù)據(jù)的方法,編碼后的數(shù)據(jù)是...
    Snow_L閱讀 772評論 0 0
  • 最近聯(lián)調(diào)后端和客戶端中對二進(jìn)制圖片數(shù)據(jù)進(jìn)行Base64編碼傳輸base64字符串,發(fā)現(xiàn)編碼傳輸過程中,兩邊的編碼解...
    一畝三分甜閱讀 1,549評論 0 3