SHA-3 哈希算法技术解析及应用场景分析(附开源代码实现)

一、引言:哈希算法的重要性与演进背景

在当今高度数字化的世界中,信息安全已成为全球关注的焦点。作为信息安全体系的基石之一,哈希算法发挥着不可替代的作用。从数字签名到数据完整性验证,从密码存储到区块链技术,哈希算法如同一位无声的守护者,默默保障着数字世界的安全秩序。

哈希算法的核心价值在于其能够将任意长度的输入数据转换为固定长度的输出,这个输出通常被称为“哈希值”或“数字指纹”。理想的哈希算法需要满足几个关键特性:一是单向性,即从哈希值无法反推出原始数据;二是抗碰撞性,即难以找到两个不同的输入产生相同的哈希值;三是雪崩效应,即输入的微小变化会导致输出哈希值的巨大差异。

回顾哈希算法的发展历程,我们见证了从MD5、SHA-0、SHA-1到SHA-2系列的演进过程。每种算法都代表了当时密码学研究的最高水平,但随着计算能力的提升和密码分析技术的发展,这些算法相继暴露出安全漏洞。特别是在2017年,谷歌研究团队成功实现了对SHA-1算法的实际碰撞攻击,这一事件震惊了整个信息安全界,也加速了新一代哈希算法的发展进程。

SHA3的诞生正是应对这些安全挑战的必然结果。2007年,美国国家标准与技术研究院(NIST)发起了全球范围的哈希算法竞赛,旨在遴选新一代的密码哈希标准。经过五年的激烈角逐和严格评估,来自比利时的Keccak算法最终胜出,并于2015年正式成为FIPS 202标准,标志着哈希算法发展进入了一个全新阶段。

二、SHA3的核心机制与技术突破

(一)海绵结构的革命性设计

SHA3最大的创新在于其采用了完全不同于传统Merkle-Damgård结构的海绵结构。这种结构的命名形象地反映了其工作方式——如同海绵吸水后再挤出水的过程。海绵结构由两个主要阶段组成:吸收阶段和挤压阶段。

在吸收阶段,输入消息被分割成固定长度的数据块,每个数据块与算法的内部状态进行异或操作。这个过程就像海绵吸收水分一样,将消息数据逐步“吸收”到内部状态中。与传统结构不同的是,海绵结构使用一个大型的内部状态矩阵(5×5×64位),提供了更大的状态空间和更强的安全性。

挤压阶段则负责输出哈希值。算法从内部状态中“挤出”所需长度的哈希值,这个过程可以重复进行以产生更长的输出。这种设计使得SHA3能够支持任意长度的输出,为各种应用场景提供了极大的灵活性。

海绵结构的一个关键参数是比特率(r)和容量(c)。比特率决定了每次处理的数据块大小,而容量则代表了安全冗余的位数。这种分离设计使得算法设计者可以在性能和安全性之间进行灵活的权衡。较大的r值可以提高处理速度,而较大的c值则可以提供更高的安全性。

(二)Keccak-f置换函数的精密设计

Keccak算法的核心是Keccak-f置换函数,这是一个经过精心设计的1600位状态置换函数。该函数通过24轮迭代操作来实现数据的充分混淆和扩散,每轮操作包含五个步骤:θ(Theta)、ρ(Rho)、π(Pi)、χ(Chi)和ι(Iota)。

θ步骤实现列间扩散,通过计算每列的奇偶性并将其扩散到相邻列,确保局部变化能够快速传播到整个状态矩阵。ρ步骤实施位旋转操作,每个位根据其位置进行不同偏移量的循环移位,增加算法的非线性特性。π步骤对状态矩阵的行进行置换,改变位之间的空间关系。

χ步骤是算法中主要的非线性操作来源,它使用AND和NOT操作来创建复杂的布尔函数。这个步骤确保了算法具有足够的非线性,能够抵抗线性密码分析。最后的ι步骤通过添加轮常数来打破对称性,确保每轮操作都是唯一的。

这种多轮迭代结合多种操作方式的设计,使得Keccak-f函数能够实现理想的密码学特性:完全扩散、高度非线性和足够的混淆程度。即使经过简化轮数的版本,也能表现出极强的安全性。

(三)创新的填充方案

SHA3采用独特的Pad10*1填充方案,这种方案比传统哈希算法使用的填充方法更加简单和安全。填充模式的形式为“10*1”,即在消息末尾添加一个“1”位,然后添加若干个“0”位,最后再添加一个“1”位。

这种填充方案的优势在于其能够防止长度扩展攻击。在传统哈希算法中,攻击者如果知道Hash(M)和M的长度,即使不知道M的内容,也能够计算出Hash(M||X)(其中||表示连接操作)。而SHA3的填充方案和海绵结构设计从根本上杜绝了这类攻击的可能性。

三、SHA3的安全性优势

(一)抗碰撞性能力

SHA3提供了从SHA3-224到SHA3-512多个安全级别,分别对应112位到256位的安全强度。即使是其中最短的SHA3-224,其抗碰撞强度也达到2^112次操作,这意味着即使使用目前最强大的计算机,也需要不可行的时间才能找到碰撞。

这种强大的安全性源于几个因素:首先,海绵结构的大容量设计提供了充分的安全余量;其次,Keccak-f置换函数的充分轮数确保了足够的混淆和扩散;最后,算法的整体设计经过了严格的密码学分析,没有发现明显的弱点。

(二)抗量子计算攻击

随着量子计算技术的发展,传统密码算法面临着前所未有的挑战。Grover算法表明,量子计算机能够将哈希算法的搜索攻击复杂度从O(2^n)降低到O(2^(n/2))。这意味着256位安全强度的传统哈希算法在量子计算机面前只相当于128位的安全性。

SHA3在设计时已经考虑了量子计算的威胁。通过使用更大的内部状态和更高的安全余量,SHA3在量子计算环境下仍然保持足够的安全性。例如,SHA3-512在量子计算环境下的安全强度仍然相当于256位,能够抵御未来的量子攻击。

(三)抗侧信道攻击

侧信道攻击通过分析算法的物理实现特征(如功耗、电磁辐射、时间等)来获取密钥信息。SHA3的算法设计使其天然抵抗多种侧信道攻击。

首先,Keccak-f置换函数的操作主要是按位操作和逻辑运算,这些操作在硬件实现时具有相对均匀的功耗特征。其次,算法的常数时间实现相对容易,不容易泄露时序信息。最后,海绵结构的规律性使其适合硬件实现,减少了信息泄露的可能性。

四、SHA3的性能特点

(一)硬件实现优势

SHA3在硬件实现方面表现出显著优势。其海绵结构的规律性使得算法非常适合并行处理和流水线实现。在专用硬件(如ASIC和FPGA)上,SHA3能够实现极高的吞吐量。

Keccak-f置换函数的位级操作特性使其能够充分利用现代处理器的SIMD(单指令多数据)指令集。在支持SIMD的通用处理器上,SHA3能够实现比传统算法更好的性能。特别是在处理大量数据时,这种优势更加明显。

(二)软件实现优化

虽然SHA3在某些软件实现场景下的性能可能不如一些高度优化的传统算法,但通过适当的优化技术,仍然能够获得良好的性能表现。

内存访问模式优化是提升SHA3软件性能的关键。通过合理安排状态矩阵在内存中的布局,可以减少缓存缺失和提高内存访问效率。此外,循环展开、指令级并行等技术也能够显著提升算法性能。

(三)能耗效率

在物联网和移动设备等能耗敏感的应用场景中,SHA3表现出良好的能耗效率。算法的规整结构使得硬件实现时能够优化功耗设计,而软件实现时也能够通过适当的优化减少计算能耗。

研究表明,在相同的安全强度下,SHA3的能耗效率优于许多传统哈希算法。这一特性使其特别适合应用于电池供电的移动设备和嵌入式系统。

五、SHA3的应用场景

(一)区块链和加密货币

在区块链技术中,哈希算法用于生成交易哈希、区块哈希和地址等关键信息。SHA3的高安全性和良好性能使其成为区块链应用的理想选择。

以太坊2.0已经采用SHA3-256作为其核心哈希算法,用于生成账户地址和验证交易完整性。SHA3的抗碰撞特性确保了区块链交易的安全性,而其高性能特性则有助于提高区块链网络的吞吐量。

(二)数字签名和证书验证

在公钥基础设施中,哈希算法用于生成和验证数字签名。SHA3的高安全性使其非常适合用于新一代的数字签名标准。

随着SHA-1算法的淘汰和SHA-2算法面临潜在的量子计算威胁,SHA3正在成为数字签名应用的新选择。许多安全协议和标准已经开始支持SHA3算法。

(三)密码存储和验证

在用户身份认证系统中,哈希算法用于安全地存储密码凭证。SHA3的抗碰撞性和抗预映像攻击能力使其非常适合用于密码存储。

结合适当的盐值和迭代次数,SHA3能够提供强大的密码保护能力,即使用户数据库泄露,攻击者也难以恢复原始密码。

(四)数据完整性验证

在大数据存储和传输场景中,SHA3可用于验证数据的完整性。其可变输出长度特性使其能够适应不同的安全需求。

从文件校验到网络传输验证,从数据库完整性保护到软件更新验证,SHA3都能够提供可靠的数据完整性保障。

(五)随机数生成和密钥派生

SHA3的可扩展输出功能(SHAKE)使其非常适合用于随机数生成和密钥派生应用。在密码学协议中,经常需要从初始种子生成随机数或派生密钥。

SHAKE函数能够根据需要生成任意长度的输出,为各种密码学应用提供了灵活的解决方案。

六、SHA3与传统算法的比较

(一)与SHA-2系列的比较

SHA-2系列算法目前仍然是广泛使用的安全哈希算法,但与SHA3相比存在一些重要差异。在安全性方面,SHA3的海绵结构设计使其天然免疫长度扩展攻击,而SHA-2需要额外的防护措施。

在性能方面,SHA-2在通用处理器上经过高度优化,在某些场景下可能表现更好。但SHA3在硬件实现和并行处理方面具有优势,特别是在未来处理器架构中可能表现更佳。

在灵活性方面,SHA3的可变输出长度特性使其能够适应更多的应用场景,而SHA-2需要不同的算法变体来支持不同的输出长度。

(二)与MD5和SHA-1的比较

MD5和SHA-1算法已经被证明存在严重的安全漏洞,不适合继续在安全敏感的场景中使用。与这些传统算法相比,SHA3提供了根本性的安全改进。

不仅安全性得到显著提升,SHA3还提供了更好的性能特性和更现代化的算法设计。从MD5或SHA-1迁移到SHA3能够显著提高系统的安全性。

七、实施和迁移考虑

(一)系统迁移策略

从现有哈希算法迁移到SHA3需要考虑兼容性和渐进性。双算法支持策略是一个可行的迁移方案,系统同时支持新旧算法,逐步过渡到SHA3。

在API设计层面,应该提供统一的接口,使应用程序能够轻松切换哈希算法。密码学库应该抽象算法细节,提供算法无关的编程接口。

(二)性能优化建议

实施SHA3时需要考虑性能优化。在硬件平台方面,可以充分利用SIMD指令和并行处理能力。在软件实现方面,应该优化内存访问模式和减少函数调用开销。

对于特定应用场景,可以选择适当的参数配置。例如,在性能敏感的场景中可以选择较小的容量参数,而在安全敏感的场景中则应该选择较大的容量参数。

(三)安全最佳实践

使用SHA3时仍然需要遵循密码学安全的最佳实践。包括使用适当的盐值、保证足够的迭代次数、保护密钥材料等。

算法选择应该基于实际的安全需求。对于一般应用,SHA3-256可能已经足够;对于更高安全需求的应用,则应该考虑使用SHA3-384或SHA3-512。

八、未来发展和挑战

(一)量子计算挑战

虽然SHA3相比传统算法具有更好的抗量子计算特性,但量子计算技术的发展仍然带来新的挑战。未来的研究需要继续评估SHA3在量子计算环境下的安全性。

后量子密码学的发展可能会带来新的哈希算法设计理念。SHA3的海绵结构为未来的算法发展提供了良好的基础,可能需要进一步的增强和改进。

(二标准化进程

SHA3的标准化进程仍在继续。随着更多实践经验的积累,可能会产生新的最佳实践和实施指南。国际标准组织正在努力推动SHA3在全球范围内的采用。

不同国家和地区可能有不同的密码算法政策和要求。SHA3的国际标准化有助于促进全球范围内的互操作性和安全性。

(三)新应用场景

随着新技术的发展,SHA3可能会面临新的应用场景和需求。物联网、边缘计算、人工智能等新兴领域都对哈希算法提出了新的要求。

这些新应用场景可能需要特定的优化和改进。算法实现可能需要适应资源受限的环境,或者需要满足特定的实时性要求。

九、结论

SHA3代表了哈希算法发展的最新成果,其海绵结构设计和Keccak-f置换函数展现了现代密码学研究的深度和精密性。与传统算法相比,SHA3提供了更高的安全性、更好的性能特性和更强的灵活性。

虽然SHA3的采用仍然面临一些挑战,包括现有系统的迁移成本和性能优化需求,但其长期优势是明显的。随着计算环境的变化和安全威胁的演进,SHA3的重要性将不断提升。

对于安全敏感的应用场景,迁移到SHA3是一个明智的选择。对于新系统设计,直接采用SHA3能够提供面向未来的安全性。密码学社区应该继续推动SHA3的研究、优化和标准化工作,为数字世界提供更强大的安全基础。

在量子计算时代即将来临的背景下,SHA3为我们提供了重要的安全保证。其良好的抗量子特性使其成为未来安全基础设施的关键组成部分。随着技术的不断发展,SHA3必将在全球信息安全体系中发挥越来越重要的作用。

附:openHiTLS密码库SHA3开源代码示例:

项目地址:GitCode - 全球开发者的开源社区,开源代码托管平台

openHiTLS旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!

/*
 * This file is part of the openHiTLS project.
 *
 * openHiTLS is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "hitls_build.h"
#ifdef HITLS_CRYPTO_SHA3

#include <stdlib.h>
#include "securec.h"
#include "crypt_errno.h"
#include "crypt_utils.h"
#include "bsl_err_internal.h"
#include "bsl_sal.h"
#include "sha3_core.h"
#include "crypt_sha3.h"
#include "crypt_types.h"

struct CryptSha3Ctx {
    uint8_t state[200];     // State array, 200bytes is 1600bits
    uint32_t num;           // Data length in the remaining buffer.
    uint32_t blockSize;     // For example, BlockSize(sha3-224) = ((1600 - 224 * 2) / 8) bytes
    uint32_t mdSize;     // sha3-224 corresponds to 28 bytes, sha3-256: 32 bytes, sha3-384: 48 bytes, sha3-512: 64 bytes
    // Non-integer multiple data cache. 168 = (1600 - 128 * 2) / 8, that is maximum block size used by shake_*
    uint8_t buf[168];
    uint8_t padChr;         // char for padding, sha3_* use 0x06 and shake_* use 0x1f
    bool squeeze;
};

CRYPT_SHA3_Ctx *CRYPT_SHA3_NewCtx(void)
{
    return BSL_SAL_Calloc(1, sizeof(CRYPT_SHA3_Ctx));
}

CRYPT_SHA3_Ctx *CRYPT_SHA3_NewCtxEx(void *libCtx, int32_t algId)
{
    (void)libCtx;
    (void)algId;
    return BSL_SAL_Calloc(1, sizeof(CRYPT_SHA3_Ctx));
}

void CRYPT_SHA3_FreeCtx(CRYPT_SHA3_Ctx *ctx)
{
    BSL_SAL_ClearFree(ctx, sizeof(CRYPT_SHA3_Ctx));
}

static int32_t CRYPT_SHA3_Init(CRYPT_SHA3_Ctx *ctx, uint32_t mdSize, uint32_t blockSize, uint8_t padChr)
{
    if (ctx == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }
    (void)memset_s(ctx, sizeof(CRYPT_SHA3_Ctx), 0, sizeof(CRYPT_SHA3_Ctx));
    ctx->mdSize = mdSize;
    ctx->padChr = padChr;
    ctx->blockSize = blockSize;
    return CRYPT_SUCCESS;
}

int32_t CRYPT_SHA3_Update(CRYPT_SHA3_Ctx *ctx, const uint8_t *in, uint32_t len)
{
    if (ctx == NULL || (in == NULL && len != 0)) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }
    if (len == 0) {
        return CRYPT_SUCCESS;
    }

    const uint8_t *data = in;
    uint32_t left = ctx->blockSize - ctx->num;
    uint32_t dataLen = len;

    if (ctx->num != 0) {
        if (dataLen < left) {
            (void)memcpy_s(ctx->buf + ctx->num, left, data, dataLen);
            ctx->num += dataLen;
            return CRYPT_SUCCESS;
        }

        // When the external input data is greater than the remaining space of the block,
        // copy the data of the remaining space.
        (void)memcpy_s(ctx->buf + ctx->num, left, data, left);
        (void)SHA3_Absorb(ctx->state, ctx->buf, ctx->blockSize, ctx->blockSize);
        dataLen -= left;
        data += left;
        ctx->num = 0;
    }

    data = SHA3_Absorb(ctx->state, data, dataLen, ctx->blockSize);
    dataLen = len - (data - in);
    if (dataLen != 0) {
        // copy the remaining data to the cache array
        (void)memcpy_s(ctx->buf, ctx->blockSize, data, dataLen);
        ctx->num = dataLen;
    }

    return CRYPT_SUCCESS;
}

int32_t CRYPT_SHA3_Final(CRYPT_SHA3_Ctx *ctx, uint8_t *out, uint32_t *len)
{
    if (ctx == NULL || out == NULL || len == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    if (*len < ctx->mdSize) {
        BSL_ERR_PUSH_ERROR(CRYPT_SHA3_OUT_BUFF_LEN_NOT_ENOUGH);
        return CRYPT_SHA3_OUT_BUFF_LEN_NOT_ENOUGH;
    }

    uint32_t left = ctx->blockSize - ctx->num;
    uint32_t outLen = (ctx->mdSize == 0) ? *len : ctx->mdSize;
    (void)memset_s(ctx->buf + ctx->num, left, 0, left);
    ctx->buf[ctx->num] = ctx->padChr;
    ctx->buf[ctx->blockSize - 1] |= 0x80; // 0x80 is the last 1 of pad 10*1 mode

    (void)SHA3_Absorb(ctx->state, ctx->buf, ctx->blockSize, ctx->blockSize);
    SHA3_Squeeze(ctx->state, out, outLen, ctx->blockSize, false);
    *len = outLen;

    return CRYPT_SUCCESS;
}

int32_t CRYPT_SHA3_Squeeze(CRYPT_SHA3_Ctx *ctx, uint8_t *out, uint32_t len)
{
    if (ctx == NULL || out == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    if (!ctx->squeeze) {
        uint32_t left = ctx->blockSize - ctx->num;
        (void)memset_s(ctx->buf + ctx->num, left, 0, left);
        ctx->buf[ctx->num] = ctx->padChr;
        ctx->buf[ctx->blockSize - 1] |= 0x80; // 0x80 is the last 1 of pad 10*1 mode
        (void)SHA3_Absorb(ctx->state, ctx->buf, ctx->blockSize, ctx->blockSize);
        ctx->num = 0;
        ctx->squeeze = true;
    }
    uint32_t tmpLen = len;
    uint8_t *outTmp = out;
    if (ctx->num != 0) {
        uint32_t outLen = (ctx->num > len) ? len : ctx->num;
        (void)memcpy_s(outTmp, outLen, ctx->buf + ctx->blockSize - ctx->num, outLen);
        ctx->num -= outLen;
        tmpLen -= outLen;
        outTmp += outLen;
    }
    if (tmpLen > ctx->blockSize) {
        uint32_t comLen = tmpLen / ctx->blockSize * ctx->blockSize;
        SHA3_Squeeze(ctx->state, outTmp, comLen, ctx->blockSize, true);
        outTmp += comLen;
        tmpLen -= comLen;
    }
    if (tmpLen != 0) {
        SHA3_Squeeze(ctx->state, ctx->buf, ctx->blockSize, ctx->blockSize, true);
        (void)memcpy_s(outTmp, tmpLen, ctx->buf, tmpLen);
        ctx->num = ctx->blockSize - tmpLen;
    }
    return CRYPT_SUCCESS;
}

int32_t CRYPT_SHA3_Deinit(CRYPT_SHA3_Ctx *ctx)
{
    if (ctx == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }
    BSL_SAL_CleanseData(ctx, sizeof(CRYPT_SHA3_Ctx));
    return CRYPT_SUCCESS;
}

int32_t CRYPT_SHA3_CopyCtx(CRYPT_SHA3_Ctx *dst, const CRYPT_SHA3_Ctx *src)
{
    if (dst == NULL || src == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    (void)memcpy_s(dst, sizeof(CRYPT_SHA3_Ctx), src, sizeof(CRYPT_SHA3_Ctx));
    return CRYPT_SUCCESS;
}

CRYPT_SHA3_Ctx *CRYPT_SHA3_DupCtx(const CRYPT_SHA3_Ctx *src)
{
    if (src == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return NULL;
    }
    CRYPT_SHA3_Ctx *newCtx = CRYPT_SHA3_NewCtx();
    if (newCtx == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return NULL;
    }
    (void)memcpy_s(newCtx, sizeof(CRYPT_SHA3_Ctx), src, sizeof(CRYPT_SHA3_Ctx));
    return newCtx;
}

int32_t CRYPT_SHA3_224_Init(CRYPT_SHA3_224_Ctx *ctx, BSL_Param *param)
{
    (void) param;
    // 0x06 is SHA3 padding character, see https://keccak.team/keccak_specs_summary.html
    return CRYPT_SHA3_Init(ctx, CRYPT_SHA3_224_DIGESTSIZE, CRYPT_SHA3_224_BLOCKSIZE, 0x06);
}

int32_t CRYPT_SHA3_256_Init(CRYPT_SHA3_256_Ctx *ctx, BSL_Param *param)
{
    (void) param;
    // 0x06 is SHA3 padding character, see https://keccak.team/keccak_specs_summary.html
    return CRYPT_SHA3_Init(ctx, CRYPT_SHA3_256_DIGESTSIZE, CRYPT_SHA3_256_BLOCKSIZE, 0x06);
}

int32_t CRYPT_SHA3_384_Init(CRYPT_SHA3_384_Ctx *ctx, BSL_Param *param)
{
    (void) param;
    // 0x06 is SHA3 padding character, see https://keccak.team/keccak_specs_summary.html
    return CRYPT_SHA3_Init(ctx, CRYPT_SHA3_384_DIGESTSIZE, CRYPT_SHA3_384_BLOCKSIZE, 0x06);
}

int32_t CRYPT_SHA3_512_Init(CRYPT_SHA3_512_Ctx *ctx, BSL_Param *param)
{
    (void) param;
    // 0x06 is SHA3 padding character, see https://keccak.team/keccak_specs_summary.html
    return CRYPT_SHA3_Init(ctx, CRYPT_SHA3_512_DIGESTSIZE, CRYPT_SHA3_512_BLOCKSIZE, 0x06);
}

int32_t CRYPT_SHAKE128_Init(CRYPT_SHAKE128_Ctx *ctx, BSL_Param *param)
{
    (void) param;
    // 0x1f is SHA3 padding character, see https://keccak.team/keccak_specs_summary.html
    return CRYPT_SHA3_Init(ctx, 0, CRYPT_SHAKE128_BLOCKSIZE, 0x1F);
}

int32_t CRYPT_SHAKE256_Init(CRYPT_SHAKE256_Ctx *ctx, BSL_Param *param)
{
    (void) param;
    // 0x1f is SHA3 padding character, see https://keccak.team/keccak_specs_summary.html
    return CRYPT_SHA3_Init(ctx, 0, CRYPT_SHAKE256_BLOCKSIZE, 0x1F);
}

#ifdef HITLS_CRYPTO_PROVIDER
int32_t CRYPT_SHA3_224_GetParam(CRYPT_SHA3_224_Ctx *ctx, BSL_Param *param)
{
    (void)ctx;
    return CRYPT_MdCommonGetParam(CRYPT_SHA3_224_DIGESTSIZE, CRYPT_SHA3_224_BLOCKSIZE, param);
}

int32_t CRYPT_SHA3_256_GetParam(CRYPT_SHA3_256_Ctx *ctx, BSL_Param *param)
{
    (void)ctx;
    return CRYPT_MdCommonGetParam(CRYPT_SHA3_256_DIGESTSIZE, CRYPT_SHA3_256_BLOCKSIZE, param);
}

int32_t CRYPT_SHA3_384_GetParam(CRYPT_SHA3_384_Ctx *ctx, BSL_Param *param)
{
    (void)ctx;
    return CRYPT_MdCommonGetParam(CRYPT_SHA3_384_DIGESTSIZE, CRYPT_SHA3_384_BLOCKSIZE, param);
}

int32_t CRYPT_SHA3_512_GetParam(CRYPT_SHA3_512_Ctx *ctx, BSL_Param *param)
{
    (void)ctx;
    return CRYPT_MdCommonGetParam(CRYPT_SHA3_512_DIGESTSIZE, CRYPT_SHA3_512_BLOCKSIZE, param);
}

int32_t CRYPT_SHAKE128_GetParam(CRYPT_SHAKE128_Ctx *ctx, BSL_Param *param)
{
    (void)ctx;
    return CRYPT_MdCommonGetParam(CRYPT_SHAKE128_DIGESTSIZE, CRYPT_SHAKE128_BLOCKSIZE, param);
}

int32_t CRYPT_SHAKE256_GetParam(CRYPT_SHAKE256_Ctx *ctx, BSL_Param *param)
{
    (void)ctx;
    return CRYPT_MdCommonGetParam(CRYPT_SHAKE128_DIGESTSIZE, CRYPT_SHAKE256_BLOCKSIZE, param);
}
#endif // HITLS_CRYPTO_PROVIDER
#endif // HITLS_CRYPTO_SHA3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值