首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言實現 SHA-1 雜湊算法完整指南:從原理到編譯除錯

     編輯:關於C語言

SHA-1 算法簡介

安全雜湊算法(Secure Hash Algorithm,SHA-1)是數位簽名標準(DSS)中定義的數位簽名算法(DSA)核心組件。對於長度小於 2^64 位的訊息,SHA-1 會產生一個 160 位(20 位元組)的訊息摘要。這個摘要可用於驗證資料完整性:傳輸過程中若資料發生變化,重新計算的摘要將與原值不同。SHA-1 具備兩大核心特性:不可逆性(無法從摘要還原原始訊息)與抗碰撞性(極難找到兩個不同訊息產生相同摘要)。

算法實現與常見編譯問題

網路上流傳著多種 SHA-1 C 語言實現版本。本文採用一個精簡版本(來源:CSDN 下載資源),並記錄在 Visual Studio 2005 環境下編譯、除錯的完整過程,解決常見的型別轉換、標頭檔缺失與函數回傳值等問題。

原始碼架構

程式包含三大核心函數:

  • creat_w():將 64 位元組輸入擴展為 80 個 32 位元字(W 陣列)
  • ms_len():將訊息長度(位元數)填入緩衝區尾端
  • main():主迴圈執行 80 輪壓縮函數運算,輸出最終雜湊值

Visual Studio 2005 編譯錯誤逐步修正

  1. 錯誤 C3861:找不到 `strlen` 識別符 → 右鍵 `strlen` 選擇「Refactor → Add Include」,自動加入 ``
  2. 錯誤 C2664:`ms_len` 參數型別不匹配 → 在呼叫處將 `input` 強制轉型為 `(char*)`
  3. 錯誤 C3861:找不到 `getch` 識別符 → 右鍵 `getch` 加入 ``
  4. 警告 C4996:`scanf` 不安全 → 專案屬性中定義 `_CRT_SECURE_NO_WARNINGS` 或改用 `scanf_s`
  5. 後續錯誤 C2664:`strlen` 不接受 `unsigned char*` → 改用 `(LPSTR)input`,並右鍵 `LPSTR` 加入 ``
  6. 錯誤 C4716:`ms_len` 必須回傳值 → 函數末尾加入 `return '0';`

執行驗證與輸出格式調整

編譯成功後,輸入測試字串 abcd,程式原始輸出包含中間運算過程與逗號分隔的雜湊值。修改步驟:

  1. 註解第 92 行中間過程輸出
  2. 修改第 100 行格式字串:`printf("%lx%lx%lx%lx%lx", H0,H1,H2,H3,H4);` 移除逗號

重新執行,輸出:81fe8bfe87576c3ecb22426f8e57847382917acf,與線上 SHA-1 工具驗證結果完全一致。

修正後完整可編譯程式碼

// SHA1.cpp : 定義控制台應用程式的進入點
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <wtypes.h>

void creat_w(unsigned char input[64], unsigned long w[80]) {
    int i, j; unsigned long temp, temp1;
    for (i = 0; i < 16; i++) {
        j = 4 * i;
        w[i] = ((long)input[j] << 24) | ((long)input[1+j] << 16) | 
               ((long)input[2+j] << 8) | ((long)input[3+j] << 0);
    }
    for (i = 16; i < 80; i++) {
        w[i] = w[i-16] ^ w[i-14] ^ w[i-8] ^ w[i-3];
        temp = w[i] << 1;
        temp1 = w[i] >> 31;
        w[i] = temp | temp1;
    }
}

char ms_len(long a, char intput[64]) {
    unsigned long temp3, p1; int i, j;
    temp3 = 0; p1 = ~(~temp3 << 8);
    for (i = 0; i < 4; i++) {
        j = 8 * i;
        intput[63-i] = (char)((a & (p1 << j)) >> j);
    }
    return '0';
}

int _tmain(int argc, _TCHAR* argv[]) {
    unsigned long H0 = 0x67452301, H1 = 0xefcdab89, H2 = 0x98badcfe,
                  H3 = 0x10325476, H4 = 0xc3d2e1f0;
    unsigned long A, B, C, D, E, temp, temp1, temp2, temp3, k, f;
    int i, flag; unsigned long w[80];
    unsigned char input[64]; long x; int n;

    printf("input message:\n");
    scanf("%s", input);
    n = strlen((LPSTR)input);

    if (n < 57) {
        x = n * 8;
        ms_len(x, (char*)input);
        if (n == 56)
            for (i = n; i < 60; i++) input[i] = 0;
        else {
            input[n] = 128;
            for (i = n+1; i < 60; i++) input[i] = 0;
        }
    }

    creat_w(input, w);
    A = H0; B = H1; C = H2; D = H3; E = H4;

    for (i = 0; i < 80; i++) {
        flag = i / 20;
        switch (flag) {
            case 0: k = 0x5a827999; f = (B & C) | (~B & D); break;
            case 1: k = 0x6ed9eba1; f = B ^ C ^ D; break;
            case 2: k = 0x8f1bbcdc; f = (B & C) | (B & D) | (C & D); break;
            case 3: k = 0xca62c1d6; f = B ^ C ^ D; break;
        }
        temp1 = A << 5; temp2 = A >> 27; temp3 = temp1 | temp2;
        temp = temp3 + f + E + w[i] + k;
        E = D; D = C;
        temp1 = B << 30; temp2 = B >> 2; C = temp1 | temp2;
        B = A; A = temp;
    }

    H0 += A; H1 += B; H2 += C; H3 += D; H4 += E;
    printf("\noutput hash value:\n");
    printf("%lx%lx%lx%lx%lx", H0, H1, H2, H3, H4);
    getch();
    return 0;
}

總結

本文完整呈現了從原始碼獲取、編譯錯誤診斷、型別修正到最終驗證的全過程。關鍵點在於:理解 VS 對 C 標準庫函數的型別檢查嚴格性、善用 IDE 的「Add Include」功能、處理有號/無號字元指標轉換、確保所有函數有正確回傳值。修正後的程式碼可直接在 Visual Studio 2005+ 環境編譯執行,產出標準 SHA-1 雜湊值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved