0

0

Go语言中基于SHA224摘要生成ECDSA私钥并进行数字签名

霞舞

霞舞

发布时间:2025-11-22 17:21:01

|

386人浏览过

|

来源于php中文网

原创

Go语言中基于SHA224摘要生成ECDSA私钥并进行数字签名

本文详细阐述了在go语言中,如何根据用户id和密码短语的sha224摘要正确生成ecdsa私钥,并使用该私钥对消息进行数字签名。核心内容包括私钥d值的正确推导方法,即直接将哈希摘要转换为*big.int,以及ecdsa签名的标准流程,旨在帮助开发者避免常见的私钥生成错误,确保签名的安全性和正确性。

在Go语言中实现椭圆曲线数字签名算法(ECDSA)是常见的加密需求,尤其是在需要对特定消息进行身份验证或确保数据完整性时。一个典型的场景是根据用户ID和密码短语等特定输入,通过哈希算法派生出ECDSA私钥,进而使用该私钥对其他消息进行签名。本教程将详细介绍如何正确地在Go中使用crypto/ecdsa包,结合SHA224哈希算法,安全且准确地完成这一过程。

理解ECDSA私钥结构

ECDSA私钥的核心是一个大整数D。在Go语言的ecdsa.PrivateKey结构中,D字段的类型是*big.Int。这意味着任何用于生成私钥的原始数据(例如哈希摘要)最终都必须被正确地转换为一个*big.Int类型的值。

错误的私钥生成方法解析

一个常见的错误是将哈希函数的字节数组摘要先转换为一个固定大小的整数类型(如int64),然后再将其赋值给big.Int。例如,以下代码片段展示了这种不正确的做法:

// 错误示例:将SHA224摘要转换为int64,再赋值给big.Int
sha := sha256.New224()
// ... 写入数据 ...
sum := sha.Sum(nil) // []byte,SHA224摘要长度为28字节

var in int64
reader := bytes.NewReader(sum)
// 尝试将28字节的摘要读取到8字节的int64中
err := binary.Read(reader, binary.BigEndian, &in) 
if err != nil {
    // 可能会因为摘要长度超过int64而出现EOF错误,或者只读取了部分字节
    // 无论哪种情况,都会导致数据截断
}
prKey.D = big.NewInt(in) // 错误:数据丢失,安全性受损

SHA224哈希算法会产生一个28字节的摘要。将其直接读取到int64(8字节)中会导致严重的数据截断和信息丢失。这不仅使得生成的私钥无法正确反映原始哈希值,更在密码学上造成了不可接受的安全漏洞,因为私钥的熵和随机性被大大降低。

立即学习go语言免费学习笔记(深入)”;

GoEnhance
GoEnhance

全能AI视频制作平台:通过GoEnhance AI让视频创作变得比以往任何时候都更简单。

下载

正确的私钥生成方法

正确的做法是将SHA224生成的28字节摘要直接转换为*big.Int。math/big包提供了SetBytes方法,能够将一个字节切片完整地解析为一个大整数。

以下是根据用户ID和密码短语(经过SHA224哈希)生成ECDSA私钥的正确实现:

package main

import (
    "bytes"
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "crypto/sha256"
    "encoding/binary"
    "fmt"
    "log"
    "math/big"
)

// NewKey 根据用户ID和密码短语的SHA224摘要生成ECDSA私钥
func NewKey(userId int64, pass string) (prKey ecdsa.PrivateKey) {
    // 1. 准备用于哈希的输入数据
    buf := new(bytes.Buffer)
    // 将userId以大端序写入缓冲区,确保字节序列化一致性
    err := binary.Write(buf, binary.BigEndian, userId)
    if err != nil {
        log.Fatalf("Failed to write userId: %v", err)
    }
    passArr := []byte(pass)

    // 2. 使用SHA224哈希算法计算摘要
    sha := sha256.New224()
    sha.Write(buf.Bytes())   // 写入userId的字节表示
    sha.Write(passArr)       // 写入密码短语的字节表示
    sum := sha.Sum(nil)      // 获取28字节的SHA224摘要

    // 3. 将SHA224摘要直接转换为*big.Int作为私钥D值
    // 这是关键步骤,确保不丢失任何信息
    prKey.D = new(big.Int).SetBytes(sum)

    // 4. 设置椭圆曲线。SHA224通常与P224曲线配合使用,因为它能提供足够的安全性。
    prKey.PublicKey.Curve = elliptic.P224()
    // 根据D值计算公钥X和Y坐标
    prKey.PublicKey.X, prKey.PublicKey.Y = prKey.PublicKey.Curve.ScalarBaseMult(prKey.D.Bytes())

    return prKey
}

代码解析:

  • 数据准备: userId是一个int64,需要通过binary.Write将其转换为字节序列,确保哈希输入的一致性。pass字符串直接转换为字节切片。
  • SHA224哈希: sha256.New224()创建一个SHA224哈希器。将userId和pass的字节序列写入哈希器,然后调用sha.Sum(nil)获取28字节的哈希摘要。
  • 私钥D值设置: 关键在于prKey.D = new(big.Int).SetBytes(sum)。这行代码将28字节的sum直接解析为一个大整数,并赋值给私钥的D字段,从而避免了数据截断问题。
  • 椭圆曲线设置: 选择了elliptic.P224()作为椭圆曲线。P224曲线的位数(224位)与SHA224摘要的位数(224位)相匹配,这是一种常见的匹配实践,可以确保密钥和哈希算法的安全强度一致。
  • 公钥计算: prKey.PublicKey.X, prKey.PublicKey.Y = prKey.PublicKey.Curve.ScalarBaseMult(prKey.D.Bytes()) 这行代码根据私钥D和选定的曲线自动计算出对应的公钥X和Y坐标,这是ECDSA规范的一部分。

消息哈希与数字签名

一旦私钥被正确生成,就可以用它来对消息进行签名。签名过程首先需要对消息内容进行哈希,然后使用ecdsa.Sign函数。

// 假设 enc 是一个将 big.Int 转换为字符串的辅助函数,例如 base64 编码
func enc(val string) string {
    // 实际应用中可能需要更复杂的编码,例如 base64 或 hex
    return fmt.Sprintf("encoded(%s)", val)
}

func main() {
    userId := int64(12345)
    pass := "mySecretPassphrase"
    srNonce := "server_nonce_xyz"
    clNonce := "client_nonce_abc"

    // 1. 生成私钥
    key := NewKey(userId, pass)
    fmt.Printf("Generated Private Key D: %s\n", key.D.String())

    // 2. 准备待签名的消息内容并进行SHA224哈希
    // 注意:这里需要确保消息内容的字节序列化方式与接收方一致
    msgBuffer := new(bytes.Buffer)
    binary.Write(msgBuffer, binary.BigEndian, userId) // userId作为int64写入
    msgBuffer.WriteString(srNonce)                    // server nonce作为字符串写入
    msgBuffer.WriteString(clNonce)                    // client nonce作为字符串写入

    // 对消息内容进行SHA224哈希
    msgHasher := sha256.New224()
    msgHasher.Write(msgBuffer.Bytes())
    msgHash := msgHasher.Sum(nil) // 获取消息的SHA224摘要

    // 3. 使用私钥对消息哈希进行签名
    // rand.Reader 提供密码学安全的随机数源

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

360

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1503

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

625

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

676

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

630

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

173

2025.07.29

c++字符串相关教程
c++字符串相关教程

本专题整合了c++字符串相关教程,阅读专题下面的文章了解更多详细内容。

83

2025.08.07

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

54

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.5万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号