20.1 OpenSSL 字元BASE64壓縮演算法

lyshark發表於2023-10-28

OpenSSL 是一種開源的加密庫,提供了一組用於加密和解密資料、驗證數字證書以及實現各種安全協議的函式和工具。它可以用於建立和管理公鑰和私鑰、數字證書和其他安全憑據,還支援SSL/TLSSSHS/MIMEPKCS等常見的加密協議和標準。

OpenSSL 的功能非常強大,可以用於構建安全的網路通訊、加密檔案和資料傳輸,還可以用於建立和驗證數字簽名、生成隨機數等安全應用。它被廣泛用於Web伺服器、作業系統、網路應用程式和其他需要安全保護的系統中。

如上所示的連結則是該庫的官方網站,讀者可自行下載對應版本的OpenSSL庫,並執行安裝程式,該庫預設會被安裝在根目錄下,透過點選下一步即可很容易的完成安裝配置。

該庫安裝成功後我們可以開啟OpenSSL-Win32根目錄,在目錄中bin目錄是可執行檔案,OpenSSL的執行需要依賴於這些動態連結庫,在使用時需要自行將本目錄配置到環境變數內,其次include標頭檔案lib靜態庫檔案,在使用時讀者需要自行配置到開發專案中,如下圖所示;

OpenSSL庫其本身就是一種加密與解密演算法庫,運用該庫我們可以實現各類資料的加解密功能,首先我們以簡單的Base64演算法為例對該庫進行使用。

Base64演算法是一種用於將二進位制資料編碼為ASCII字元的演算法。該演算法將三個位元組的二進位制資料轉換成四個字元的ASCII字串,使得資料在傳輸時能夠避免出現非法字元、特殊字元等問題,同時也可以將二進位制資料轉換為文字形式,方便在文字協議中傳輸,但讀者需要注意Base64編碼雖然可以作為一種簡單的加密方式,但是它並不是一種真正的加密演算法,因為它只是將資料轉換為另一種形式,而沒有對資料進行加密處理。

在OpenSSL中,使用Base64加密可以呼叫BIO_f_base64函式實現,該函式是一種BIO過濾器,用於將資料進行Base64編碼和解碼,如下程式碼中筆者分別封裝實現了這兩種加解密方法,其中base64Encode接收一個字串並將該字串壓縮為編碼字串儲存,與之相反base64Decode則用於將壓縮後的字串恢復。

#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/crypto.h>

#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")

// base64 編碼
char* base64Encode(const char* buffer, int length, bool newLine)
{
    BIO* bmem = NULL;
    BIO* b64 = NULL;
    BUF_MEM* bptr;

    b64 = BIO_new(BIO_f_base64());
    if (!newLine)
    {
        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    }
    bmem = BIO_new(BIO_s_mem());
    b64 = BIO_push(b64, bmem);
    BIO_write(b64, buffer, length);
    BIO_flush(b64);
    BIO_get_mem_ptr(b64, &bptr);
    BIO_set_close(b64, BIO_NOCLOSE);

    char* buff = (char*)malloc(bptr->length + 1);
    memcpy(buff, bptr->data, bptr->length);
    buff[bptr->length] = 0;
    BIO_free_all(b64);
    return buff;
}

// base64 解碼
char* base64Decode(char* input, int length, bool newLine)
{
    BIO* b64 = NULL;
    BIO* bmem = NULL;
    char* buffer = (char*)malloc(length);
    memset(buffer, 0, length);
    b64 = BIO_new(BIO_f_base64());
    if (!newLine)
    {
        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    }
    bmem = BIO_new_mem_buf(input, length);
    bmem = BIO_push(b64, bmem);
    BIO_read(bmem, buffer, length);
    BIO_free_all(bmem);

    return buffer;
}

上述程式碼的使用也非常簡單,如下所示我們透過傳入一個input字串,並將該字串壓縮後輸出,接著再把該字串解密後輸出。

int main(int argc, char* argv[])
{
  // flag == false 將編碼資料壓縮為一行,否則原格式輸出
  bool flag = false;
  std::string input = "Hello lyshark!";

  // 輸出編碼內容
  char* encode = base64Encode(input.c_str(), input.length(), flag);
  std::cout << "Base64 編碼後: " << encode << std::endl;

  // 輸出解碼內容
  char* decode = base64Decode(encode, strlen(encode), flag);
  std::cout << "Base64 解碼後: " << decode << std::endl;
  
  system("pause");
  return 0;
}

執行上述程式碼,讀者可看到如下圖所示的輸出效果;