BlowFish對稱加密算法


前言:BlowFish對稱算法學習筆記

參考文章:https://bbs.pediy.com/thread-256209.htm

什么是BlowFish對稱加密算法

BlowFish算法是一個64位分組及可變密鑰長度的對稱密鑰分組密碼算法,可用來加密64比特長度的字符串。32位處理器誕生后,BlowFish算法因其在加密速度上超越了DES而引起人們的關注。Blowfish算法具有加密速度快、緊湊、密鑰長度可變、可免費使用等特點,已被廣泛使用於眾多加密軟件。

BlowFish對稱加密算法是一個要求的密鑰長度需要為32-448位,其分組長度:64位,16輪循環的Feistel結構

對於BlowFish對稱加密算法由兩部分組成,分別是密鑰拓展部分和數據加密部分。密鑰拓展部分將最長為448位的密鑰轉換為4168字節的子密鑰數組,每一輪由一個密鑰相關置換和一個密鑰與數據相關的替換組成。

這兩個部分跟IDEA對稱算法加密有點相像,因為在IDEA對稱算法加密中也是有這兩個部分組成,一個是子密鑰的生成(密鑰拓展部分),一部分是進行加密過程(數據加密部分)。

BlowFish的圖解過程如下所示

BlowFish的結構體

首先要代碼中對於BlowFish結構體都定義為如下,其中有s-box和p-box成員

關於s-box和p-box的描述是ORIG_P(p-box)與ORIG_S(s-box)取自圓周率的小數位,每4個字節賦值給其中的一個元素。

typedef struct {
  unsigned long P[16 + 2];
  unsigned long S[4][256];
} BLOWFISH_CTX;

對BLOWFISH_CTX* ctx中S-Box進行初始化,直接將ORIG_S中的每個元素逐一賦值給S-Box

這里的ORIG_S定義如下圖所示

BlowFish密鑰拓展部分

初始化可以稱作為Blowfish_Init函數,該函數用來初始化S-Box與P-Box,傳遞參數中的key即密鑰,keyLen是密鑰長度。

第一步:對BLOWFISH_CTX *ctx中S-Box進行初始化,直接將ORIG_S中的每個元素逐一賦值給S-Box,也就是上面中的圖所示,直接將ORIG_S[4][256]賦值給s-box中

第二步:對BLOWFISH_CTX *ctx中P-Box進行初始化,具體過程如下:

  • data=0x00000000;

  • 如果參數中的字符數組key長度不足4,則循環使用key中字符(當使用到key中最后一個字符時,下一個字符是key中第一個字符)與data << 8進行或運算

注意:上面的過程總結起來就是將參數中的字符數組key轉換為ASCII碼形式(e.g.:key[3]="abc"---->>0x61626361並存儲於data中)

  • 將ORIG_P中的每個元素與data作異或運算后逐一賦值給P-Box

第三步:初始化兩個變量detal和datar

datal=0x00000000;
datar=0x00000000;

第四步:將上面經過變換后的ctx,datal與datar傳遞給Blowfish_Encrypt

第五步:將加密后的datal與datar賦值給P-Box中的元素
重復9次步驟4-5

與步驟4類似,不過這次傳遞的是上面過程中已經加密后的datal與datar
將加密后的datal與datar賦值給S-Box中的元素
重復512次步驟7-8

步驟5、8中提到的賦值過程是這樣的(以步驟5來舉例):
第一次 P[0]=datal,P[1]=datar
第二次 P[2]=datal,P[3]=datar
......

其代碼定義如下所示

// BlowFish進行初始化操作
void Blowfish_Init(BLOWFISH_CTX *ctx, unsigned char *key, int keyLen) {
  int i, j, k;
  unsigned long data, datal, datar;

  for (i = 0; i < 4; i++) {
    for (j = 0; j < 256; j++)
      ctx->S[i][j] = ORIG_S[i][j];
  }

  j = 0;
  for (i = 0; i < N + 2; ++i) {
    data = 0x00000000;
    for (k = 0; k < 4; ++k) {
      data = (data << 8) | key[j];
      j = j + 1;
      if (j >= keyLen)
        j = 0;
    }
    ctx->P[i] = ORIG_P[i] ^ data;
  }

  datal = 0x00000000;
  datar = 0x00000000;

  for (i = 0; i < N + 2; i += 2) {
    Blowfish_Encrypt(ctx, &datal, &datar);
    ctx->P[i] = datal;
    ctx->P[i + 1] = datar;
  }

  for (i = 0; i < 4; ++i) {
    for (j = 0; j < 256; j += 2) {
      Blowfish_Encrypt(ctx, &datal, &datar);
      ctx->S[i][j] = datal;
      ctx->S[i][j + 1] = datar;
    }
  }
}

BlowFish數據加密部分

加密過程如下圖所示

下面說的這4個步驟是一輪循環的工作過程,Feistel Structure是進行了16輪循環才完成一次加密。

1、將原數據分成左右兩部分

2、原數據的右側不變,直接變成下次循環的左側

3、將原數據的右側與子密鑰傳遞給輪函數F

4、輪函數F的返回值與原數據左側進行異或運算,變成下次循環的右側

具體的函數F為如下定義,其中傳入的x變量

static unsigned long F(BLOWFISH_CTX *ctx, unsigned long x) {
   unsigned short a, b, c, d;
   unsigned long  y;

   d = (unsigned short)(x & 0xFF);
   x >>= 8;
   c = (unsigned short)(x & 0xFF);
   x >>= 8;
   b = (unsigned short)(x & 0xFF);
   x >>= 8;
   a = (unsigned short)(x & 0xFF);
  // 將原數據的右側與子密鑰傳遞給輪函數F
   y = ctx->S[0][a] + ctx->S[1][b];
   y = y ^ ctx->S[2][c];
   y = y + ctx->S[3][d];

   return y; // 輪函數F的返回值與原數據左側進行異或運算,變成下次循環的右側
}

需要說明一點,在最后一輪循環中左右數據不對調。解密過程是加密過程的反向。

解密代碼如下所示

void Blowfish_Decrypt(BLOWFISH_CTX *ctx, unsigned long *xl, unsigned long *xr){
  unsigned long  Xl;
  unsigned long  Xr;
  unsigned long  temp;
  short       i;

  Xl = *xl;
  Xr = *xr;

  for (i = N + 1; i > 1; --i) {
    Xl = Xl ^ ctx->P[i];
    Xr = F(ctx, Xl) ^ Xr;

    /* Exchange Xl and Xr */
    temp = Xl;
    Xl = Xr;
    Xr = temp;
  }

  /* Exchange Xl and Xr */
  temp = Xl;
  Xl = Xr;
  Xr = temp;

  Xr = Xr ^ ctx->P[1];
  Xl = Xl ^ ctx->P[0];

  *xl = Xl;
  *xr = Xr;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM