【加解密与C】HASH系列(四)SHA-3

SHA-3 概述

SHA-3(Secure Hash Algorithm 3)是由美国国家标准与技术研究院(NIST)于2015年发布的加密哈希函数标准,基于Keccak算法。它是SHA-2的替代方案,设计上采用了海绵结构(Sponge Construction),具有更强的抗碰撞性和灵活性。

SHA-3 核心特点

  • 海绵结构:通过吸收(absorb)和挤压(squeeze)两个阶段处理数据,支持可变输出长度。
  • 安全性:提供224、256、384、512位四种输出长度,安全性分别对应112、128、192、256位抗碰撞性。
  • 灵活性:可配置为哈希函数、消息认证码(MAC)或伪随机数生成器(PRNG)。

SHA-3 算法步骤

输入处理

  1. 消息填充:采用"10*1"规则(即1后接任意个0,最后以1结尾),确保消息长度为块大小的整数倍。
  2. 初始化状态:1600位的内部状态(b=1600)初始化为全0。

海绵结构阶段

  • 吸收阶段:将填充后的消息分块(每块大小为r位)与状态进行异或,并通过Keccak-f[1600]置换函数处理。
  • 挤压阶段:从状态中提取哈希值,若输出长度不足,重复应用置换函数。

Keccak-f[1600]置换

由24轮循环组成,每轮包含以下步骤(θ、ρ、π、χ、ι):

  • θ:基于列奇偶校验的扩散操作。
  • ρ:位循环移位,增加非线性。
  • π:重排列状态位。
  • χ:非线性混淆层。
  • ι:轮常量异或,破坏对称性。

应用场景

  • 数据完整性验证:如文件校验、数字签名。
  • 密码学协议:用于密钥派生(HKDF)、区块链(如以太坊使用Keccak-256)。
  • 抗量子计算:相较于SHA-2,SHA-3的结构对量子攻击更具抵抗力。

与SHA-2的区别

  • 结构差异:SHA-2使用Merkle-Damgård结构,SHA-3使用海绵结构。
  • 性能:SHA-3硬件实现效率更高,但软件中可能略慢于SHA-2。
  • 设计目标:SHA-3更注重灵活性,支持除哈希外的其他密码学功能。
cpp 复制代码
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// SHA3常量定义
#define KECCAK_ROUNDS 24
#define SHA3_STATE_SIZE 200
#define SHA3_MAX_DIGEST_SIZE 64

// 旋转操作宏
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))

// SHA3上下文结构
typedef struct {
    uint64_t state[25];  // 5x5状态矩阵
    unsigned char buffer[144];  // 输入缓冲区
    unsigned int bufferIndex;   // 缓冲区索引
    unsigned int rate;          // 速率(字节)
    unsigned int digestSize;    // 输出长度(字节)
} sha3_ctx;

// Keccak-f[1600]轮常量
static const uint64_t round_constants[KECCAK_ROUNDS] = {
    0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
    0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
    0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
    0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
    0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
    0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
    0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
    0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
};

// 旋转偏移量表
static const unsigned int rotation_offsets[25] = {
     0,  1, 62, 28, 27,
    36, 44,  6, 55, 20,
     3, 10, 43, 25, 39,
    41, 45, 15, 21,  8,
    18,  2, 61, 56, 14
};

// Keccak-f[1600]置换函数
static void keccak_f(sha3_ctx *ctx) {
    uint64_t C[5], D[5];
    
    for (int round = 0; round < KECCAK_ROUNDS; round++) {
        // Theta步骤
        for (int i = 0; i < 5; i++) {
            C[i] = ctx->state[i] ^ ctx->state[i + 5] ^ 
                   ctx->state[i + 10] ^ ctx->state[i + 15] ^ 
                   ctx->state[i + 20];
        }
        
        for (int i = 0; i < 5; i++) {
            D[i] = C[(i + 4) % 5] ^ ROTL64(C[(i + 1) % 5], 1);
            for (int j = 0; j < 5; j++) {
                ctx->state[i + 5 * j] ^= D[i];
            }
        }
        
        // Rho和Pi步骤
        uint64_t temp = ctx->state[1];
        for (int i = 0; i < 24; i++) {
            unsigned int index = rotation_offsets[i];
            uint64_t t = ctx->state[index];
            ctx->state[index] = ROTL64(temp, rotation_offsets[(i + 1) % 25]);
            temp = t;
        }
        
        // Chi步骤
        for (int j = 0; j < 5; j++) {
            for (int i = 0; i < 5; i++) {
                C[i] = ctx->state[i + 5 * j];
            }
            for (int i = 0; i < 5; i++) {
                ctx->state[i + 5 * j] = C[i] ^ ((~C[(i + 1) % 5]) & C[(i + 2) % 5]);
            }
        }
        
        // Iota步骤
        ctx->state[0] ^= round_constants[round];
    }
}

// SHA3初始化
void sha3_init(sha3_ctx *ctx, unsigned int digest_size) {
    memset(ctx, 0, sizeof(sha3_ctx));
    ctx->digestSize = digest_size;
    
    // 设置速率 (1600 - 2*digest_size*8) / 8
    switch (digest_size) {
        case 28:  // 224位
            ctx->rate = 144; break;
        case 32:  // 256位
            ctx->rate = 136; break;
        case 48:  // 384位
            ctx->rate = 104; break;
        case 64:  // 512位
            ctx->rate = 72; break;
        default:
            // 默认256位
            ctx->rate = 136;
            ctx->digestSize = 32;
    }
}

// 更新SHA3状态
void sha3_update(sha3_ctx *ctx, const uint8_t *data, size_t len) {
    size_t block_size = ctx->rate;
    
    while (len > 0) {
        size_t to_copy = block_size - ctx->bufferIndex;
        if (to_copy > len) to_copy = len;
        
        memcpy(ctx->buffer + ctx->bufferIndex, data, to_copy);
        ctx->bufferIndex += to_copy;
        data += to_copy;
        len -= to_copy;
        
        if (ctx->bufferIndex == block_size) {
            // 处理完整块
            for (int i = 0; i < block_size / 8; i++) {
                ctx->state[i] ^= ((uint64_t*)ctx->buffer)[i];
            }
            keccak_f(ctx);
            ctx->bufferIndex = 0;
        }
    }
}

// 生成最终哈希值
void sha3_final(sha3_ctx *ctx, uint8_t *digest) {
    // 填充: 0x06 + 0x80... + 0x01
    ctx->buffer[ctx->bufferIndex++] = 0x06;
    memset(ctx->buffer + ctx->bufferIndex, 0, ctx->rate - ctx->bufferIndex);
    ctx->buffer[ctx->rate - 1] |= 0x80;
    
    // 处理最后一个块
    for (int i = 0; i < ctx->rate / 8; i++) {
        ctx->state[i] ^= ((uint64_t*)ctx->buffer)[i];
    }
    
    keccak_f(ctx);
    
    // 输出哈希值
    for (unsigned int i = 0; i < ctx->digestSize; i++) {
        digest[i] = (ctx->state[i / 8] >> (8 * (i % 8))) & 0xFF;
    }
}

// 包装函数:计算SHA3哈希
void sha3_hash(const uint8_t *input, size_t len, uint8_t *digest, unsigned int digest_size) {
    sha3_ctx ctx;
    sha3_init(&ctx, digest_size);
    sha3_update(&ctx, input, len);
    sha3_final(&ctx, digest);
}

// 测试函数
int main() {
    const char *test_str = "Hello, SHA3!";
    uint8_t digest[SHA3_MAX_DIGEST_SIZE];
    
    // 测试不同长度
    printf("SHA3-224: ");
    sha3_hash((uint8_t*)test_str, strlen(test_str), digest, 28);
    for (int i = 0; i < 28; i++) printf("%02x", digest[i]);
    printf("\n");
    
    printf("SHA3-256: ");
    sha3_hash((uint8_t*)test_str, strlen(test_str), digest, 32);
    for (int i = 0; i < 32; i++) printf("%02x", digest[i]);
    printf("\n");
    
    printf("SHA3-384: ");
    sha3_hash((uint8_t*)test_str, strlen(test_str), digest, 48);
    for (int i = 0; i < 48; i++) printf("%02x", digest[i]);
    printf("\n");
    
    printf("SHA3-512: ");
    sha3_hash((uint8_t*)test_str, strlen(test_str), digest, 64);
    for (int i = 0; i < 64; i++) printf("%02x", digest[i]);
    printf("\n");
    
    return 0;
}

※说明:代码仅从原理上实现了SHA-3,功能并未充分测试,仅供自学习时参考。若应用于生产环境,请使用openssl等第三方库。

相关推荐
银河码1 小时前
嵌入式linux驱动开发:什么是Linux驱动?深度解析与实战入门
linux·c语言·驱动开发·驱动入门
爱吃KFC的大肥羊1 小时前
C/C++常用字符串函数
c语言·数据结构·c++·算法
阿捏利2 小时前
C Primer Plus 第6版 编程练习——第15章
c语言·c primer plus
C++ 老炮儿的技术栈4 小时前
在vscode 如何运行a.nut 程序(Squirrel语言)
c语言·开发语言·c++·ide·vscode·算法·编辑器
一川月白7095 小时前
数据结构---概念、数据与数据之间的关系(逻辑结构、物理结构)、基本功能、数据结构内容、单向链表(该奶奶、对象、应用)
c语言·数据结构·算法·哈希算法·单向链表·数据关系
能工智人小辰5 小时前
Educational Codeforces Round 181 (Rated for Div. 2) A-C
c语言·开发语言
饮浊酒6 小时前
初始C语言---第四讲(数组)
c语言·学习
酷飞飞8 小时前
C语言的复合类型、内存管理、综合案例
java·c语言·前端
海上Bruce9 小时前
C primer plus (第六版)第十章 编程练习第7,8,9,10,11题
c语言