ECDSA与EDDSA签名验证问题解决方案
项目描述
本项目针对Wycheproof项目中发现的ECDSA(椭圆曲线数字签名算法)和EDDSA(爱德华兹曲线数字签名算法)签名验证问题提供了专业修复方案。在原有的签名解码阶段,缺少必要的校验步骤,导致攻击者可能通过添加或删除零字节来操纵签名,进而影响依赖签名验证的电子邮件发送等关键功能的安全性。
本解决方案通过对signature.js文件的更新,实现了严格的签名长度验证机制,从根本上杜绝了因签名格式异常而导致的安全漏洞,为使用椭圆曲线密码学的应用提供了可靠的签名验证保障。
功能特性
- 签名长度校验增强:在签名解码阶段实施严格的长度检测,防止零字节的非法添加或删除
- EDDSA签名验证:完整支持Ed25519曲线的EdDSA签名生成与验证流程
- ECDSA签名验证:基于secp256k1曲线的ECDSA签名验证,集成SHA-256哈希算法
- 十六进制数据解析:便捷的十六进制密钥和消息处理接口
- 轻量级依赖:基于成熟的elliptic加密库,确保实现的规范性和安全性
安装指南
系统要求
- Node.js 10.0.0 或更高版本
- npm 6.0.0 或更高版本
安装步骤
-
克隆代码仓库:
git clone https://github.com/tu_usuario/tu_repositorio.git -
进入项目目录:
cd tu_repositorio -
安装项目依赖:
npm install
核心依赖项
elliptic:提供ECDSA和EdDSA签名算法的JavaScript实现hash.js:用于SHA-256等哈希函数的计算
使用说明
基础使用示例
// 1. 引入所需库
var elliptic = require('elliptic');
var eddsa = elliptic.eddsa;
var ec = new elliptic.ec('secp256k1');
// 2. EDDSA签名验证流程
var ed25519 = new eddsa('ed25519');
var publicKeyEd25519 = '7d4d0e7f6153a69b6242b522abbee685fda4420f8834b108c3bdae369ef549fa';
var key = ed25519.keyFromPublic(publicKeyEd25519, 'hex');
var message = '54657374'; // 十六进制格式消息
var signature = '7c38e026f29e14aabd059a0f2db8b0cd783040609a8be684db12f82a27774ab07a9155711ecfaf7f99f277bad0c6ae7e39d4eef676573336a5c51eb6f946b30d00';
console.log('EDDSA签名验证结果:', key.verify(message, signature));
// 3. ECDSA签名验证流程
var hash = require('hash.js');
var toArray = elliptic.utils.toArray;
var hashMsg = hash.sha256().update(toArray(message, 'hex')).digest();
var publicKeySecp256k1 = '04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9';
var pubKey = ec.keyFromPublic(publicKeySecp256k1, 'hex');
console.log('ECDSA签名验证结果:', pubKey.verify(hashMsg, signature));
典型使用场景
- 安全电子邮件系统:确保邮件来源的真实性和完整性
- 数字身份验证:验证用户身份凭证的合法性
- 区块链交易验证:在链下签名验证场景中增强安全性
- API请求认证:防止请求参数被篡改
API概览
| 方法 | 描述 |
|---|---|
eddsa.keyFromPublic(key, encoding) | 从十六进制或字节数组创建EDDSA公钥对象 |
key.verify(message, signature) | 验证消息签名是否有效,返回布尔值 |
ec.keyFromPublic(key, encoding) | 从十六进制或字节数组创建ECDSA公钥对象 |
pubKey.verify(hash, signature) | 验证消息哈希的ECDSA签名 |
核心代码
签名长度验证核心逻辑
// signature.js - 签名长度验证增强模块
/**
* 验证ECDSA/EDDSA签名的长度是否符合标准
* @param {Uint8Array} signature - 待验证的签名数据
* @param {string} algorithm - 签名算法类型 ('ed25519' 或 'secp256k1')
* @returns {boolean} - 签名长度是否有效
* @throws {Error} - 当签名长度不符合标准时抛出异常
*/
function validateSignatureLength(signature, algorithm) {
const LENGTHS = {
'ed25519': 64, // Ed25519签名固定为64字节
'secp256k1': 64 // secp256k1 ECDSA签名通常为64字节(R+S)
};
const expectedLength = LENGTHS[algorithm];
if (!expectedLength) {
throw new Error(`Unsupported algorithm: ${algorithm}`);
}
if (signature.length !== expectedLength) {
throw new Error(
`Invalid signature length: expected ${expectedLength} bytes, ` +
`got ${signature.length} bytes. Possible zero-byte manipulation detected.`
);
}
return true;
}
// EDDSA解码过程中的长度检查增强
function decodeEdDSASignature(signatureHex) {
const signatureBytes = toArray(signatureHex, 'hex');
validateSignatureLength(signatureBytes, 'ed25519');
// 继续原有的解码逻辑...
return signatureBytes;
}
// ECDSA解码过程中的长度检查增强
function decodeECDSASignature(signatureHex) {
const signatureBytes = toArray(signatureHex, 'hex');
validateSignatureLength(signatureBytes, 'secp256k1');
// 继续原有的解码逻辑...
return signatureBytes;
}
完整的EDDSA签名验证实现
// eddsa-verifier.js
var elliptic = require('elliptic');
var eddsa = elliptic.eddsa;
/**
* Ed25519签名验证器类
* 封装了Ed25519曲线的签名验证逻辑,包含长度预检机制
*/
class Ed25519Verifier {
constructor(publicKeyHex) {
this.ed25519 = new eddsa('ed25519');
this.publicKey = this.ed25519.keyFromPublic(publicKeyHex, 'hex');
}
/**
* 验证消息签名的有效性
* @param {string} messageHex - 十六进制格式的消息
* @param {string} signatureHex - 十六进制格式的签名
* @returns {boolean} - 签名是否有效
*/
verify(messageHex, signatureHex) {
// 签名长度预检 - 防止字节操纵攻击
const signatureBytes = elliptic.utils.toArray(signatureHex, 'hex');
if (signatureBytes.length !== 64) {
console.error(`Rejected: signature length ${signatureBytes.length} != 64`);
return false;
}
// 执行实际的签名验证
return this.publicKey.verify(messageHex, signatureHex);
}
/**
* 批量验证多个签名
* @param {Array<{message: string, signature: string}>} items - 验证项数组
* @returns {Array<boolean>} - 各签名的验证结果
*/
verifyBatch(items) {
return items.map(item => this.verify(item.message, item.signature));
}
}
// 使用示例
var verifier = new Ed25519Verifier('7d4d0e7f6153a69b6242b522abbee685fda4420f8834b108c3bdae369ef549fa');
var isValid = verifier.verify('54657374', '7c38e026f29e14aabd059a0f2db8b0cd783040609a8be684db12f82a27774ab07a9155711ecfaf7f99f277bad0c6ae7e39d4eef676573336a5c51eb6f946b30d00');
console.log('验证结果:', isValid);
完整的ECDSA签名验证实现
// ecdsa-verifier.js
var elliptic = require('elliptic');
var hash = require('hash.js');
/**
* secp256k1 ECDSA签名验证器类
* 包含SHA-256哈希计算和严格的签名长度验证
*/
class Secp256k1Verifier {
constructor(publicKeyHex) {
this.ec = new elliptic.ec('secp256k1');
this.publicKey = this.ec.keyFromPublic(publicKeyHex, 'hex');
}
/**
* 计算消息的SHA-256哈希值
* @param {string} messageHex - 十六进制格式的消息
* @returns {Uint8Array} - 哈希值字节数组
*/
hashMessage(messageHex) {
var toArray = elliptic.utils.toArray;
return hash.sha256().update(toArray(messageHex, 'hex')).digest();
}
/**
* 验证消息的ECDSA签名
* @param {string} messageHex - 十六进制格式的原始消息
* @param {string} signatureHex - 十六进制格式的签名
* @returns {boolean} - 签名是否有效
*/
verify(messageHex, signatureHex) {
// 签名长度预检 - 防止字节操纵攻击
const signatureBytes = elliptic.utils.toArray(signatureHex, 'hex');
if (signatureBytes.length !== 64) {
console.error(`Rejected: signature length ${signatureBytes.length} != 64`);
return false;
}
// 计算消息哈希
const messageHash = this.hashMessage(messageHex);
// 执行签名验证
return this.publicKey.verify(messageHash, signatureHex);
}
/**
* 验证预计算哈希的签名(用于性能优化场景)
* @param {Uint8Array} hashBytes - 消息哈希字节数组
* @param {string} signatureHex - 十六进制格式的签名
* @returns {boolean} - 签名是否有效
*/
verifyHash(hashBytes, signatureHex) {
const signatureBytes = elliptic.utils.toArray(signatureHex, 'hex');
if (signatureBytes.length !== 64) {
console.error(`Rejected: signature length ${signatureBytes.length} != 64`);
return false;
}
return this.publicKey.verify(hashBytes, signatureHex);
}
}
// 使用示例
var verifier = new Secp256k1Verifier('04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9');
var isValid = verifier.verify('54657374', '7c38e026f29e14aabd059a0f2db8b0cd783040609a8be684db12f82a27774ab07a9155711ecfaf7f99f277bad0c6ae7e39d4eef676573336a5c51eb6f946b30d00');
console.log('ECDSA验证结果:', isValid);
6HFtX5dABrKlqXeO5PUv/7l2KSkP9qkI/HFxsju0RdE=