欢迎光临
我们一直在努力

现代密码学 第六章——数字签名

一、数字签名的基本概念

1、数字签名的特点

(1)数字签名是一种类似写在纸上的传统的物理签名,它使用公钥加密技术实现,用于鉴别数字信息或者签名者身份的方法。

(2)数字签名必须保障:

①接收者能够核实发送者对文档的签名。

②发送者事后不能否认对文档的签名。

③不能伪造对文档的签名。

(3)一个签名有消息和载体两个部分,即签名所表示的意义和签名的物理表现形式。

①传统手写签名中签名与文件是一个物理整体。具有共同的物理载体;物理上的不可分割、不可复制的特性;签名与文件的不可分割和不能重复使用。

②数字签名中,签名与文件是电子形式。没有固定的物理载体,即签名及文件的物理形式和消息已经分开;电子载体是可以任意分割、复制的;数字签名有可能与文件分割,被重复使用。

(4)传统签名和数字签名的特点:

①传统签名的验证是通过与存档手迹对照来确定真伪的,它是主观的、模糊的、容易伪造的,从而也是不安全的。

②数字签名则是用密码,通过公开算法可以检验的,是客观的、精确的,在计算上是安全的。

2、数字签名的构成及需求

(1)一个数字签名方案包括如下3个算法:

①密钥生成:产生用户的公私钥。

②签名算法:产生消息的签名。

③验证算法:验收消息的签名是否是合法。

(2)数字签名方案为了实现安全认证,需要满足如下条件:

①必须相对容易生成该数字签名。

②必须相对容易识别和验证该数字签名。

③伪造该数字签名在计算上不可行,既包括对一个已有的数字签名构造新的消息,也包括对一个消息伪造一个数字签名。

二、RSA签名算法

1、RSA数字签名机制

(1)密钥生成(生成公私钥对):

(2)用私钥对消息签名:

(3)用公钥验证签名:

2、RSA数字签名的C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmp.h>
#include <time.h>
#include <openssl/sha.h> // 用于SHA-256哈希,也可自己实现

// ———- 随机生成一个指定位数的素数 ———-
void generate_prime(mpz_t p, unsigned int bits, gmp_randstate_t state) {
mpz_t tmp;
mpz_init(tmp);
do {
mpz_urandomb(p, state, bits);
mpz_setbit(p, bits – 1); // 确保最高位为1
mpz_nextprime(p, p);
} while (mpz_sizeinbase(p, 2) < bits);
mpz_clear(tmp);
}

// ———- 生成RSA密钥对 ———-
// bits: n的位数(例如2048),p和q各约 bits/2 位
// 输出:n, e, d
void rsa_gen_keys(unsigned int bits, mpz_t n, mpz_t e, mpz_t d, gmp_randstate_t state) {
mpz_t p, q, phi;
mpz_init(p); mpz_init(q); mpz_init(phi);
unsigned int pbits = bits / 2;
unsigned int qbits = bits – pbits; // 保证乘积位数足够
generate_prime(p, pbits, state);
generate_prime(q, qbits, state);
mpz_mul(n, p, q); // n = p * q
mpz_sub_ui(p, p, 1);
mpz_sub_ui(q, q, 1);
mpz_mul(phi, p, q); // phi = (p-1)(q-1)

// 常用公钥指数 65537
mpz_set_ui(e, 65537);
// 确保 gcd(e, phi) == 1
while (mpz_gcd_ui(NULL, phi, 65537) != 1) {
mpz_add_ui(e, e, 2);
}
// 计算 d = e^{-1} mod phi
mpz_invert(d, e, phi);

mpz_clear(p); mpz_clear(q); mpz_clear(phi);
}

// ———- 签名(对消息哈希值进行私钥加密) ———-
// 输入:msg 消息字符串,私钥 d,模数 n
// 输出:signature 签名(大整数)
void rsa_sign(const unsigned char *msg, size_t msg_len,
const mpz_t d, const mpz_t n,
mpz_t signature) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(msg, msg_len, hash); // 计算 SHA-256 哈希值

// 将哈希值转换为大整数 m(大端序)
mpz_t m;
mpz_init(m);
mpz_import(m, SHA256_DIGEST_LENGTH, 1, 1, 0, 0, hash);

// 签名: s = m^d mod n
mpz_powm(signature, m, d, n);
mpz_clear(m);
}

// ———- 验证签名 ———-
// 返回 1 表示有效,0 表示无效
int rsa_verify(const unsigned char *msg, size_t msg_len,
const mpz_t signature, const mpz_t e, const mpz_t n) {
// 计算消息的哈希值
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(msg, msg_len, hash);

// 用公钥解密签名得到 m' = s^e mod n
mpz_t m_prime;
mpz_init(m_prime);
mpz_powm(m_prime, signature, e, n);

// 将 m_prime 转换为字节数组(大端序)
unsigned char recovered_hash[SHA256_DIGEST_LENGTH];
size_t count;
mpz_export(recovered_hash, &count, 1, 1, 0, 0, m_prime);
if (count < SHA256_DIGEST_LENGTH) {
// 前置零填充
memmove(recovered_hash + (SHA256_DIGEST_LENGTH – count),
recovered_hash, count);
memset(recovered_hash, 0, SHA256_DIGEST_LENGTH – count);
}
else if (count > SHA256_DIGEST_LENGTH) {
// 哈希值大于模数时,取低位(实际应使用完整填充方案)
// 此处简单处理,仅比较最后 SHA256_DIGEST_LENGTH 字节
}

int result = (memcmp(hash, recovered_hash, SHA256_DIGEST_LENGTH) == 0);
mpz_clear(m_prime);
return result;
}

// ———- 辅助:打印大整数(十六进制) ———-
void print_mpz(const char *label, const mpz_t num) {
gmp_printf("%s: %ZX\\n", label, num);
}

// ———- 测试 ———-
int main() {
// 初始化随机状态
gmp_randstate_t state;
gmp_randinit_default(state);
gmp_randseed_ui(state, time(NULL));

unsigned int bits = 2048; // 安全级别建议至少2048位
mpz_t n, e, d;
mpz_init(n); mpz_init(e); mpz_init(d);

printf("生成 %u 位 RSA 密钥对…\\n", bits);
rsa_gen_keys(bits, n, e, d, state);
printf("密钥生成完成。\\n");
print_mpz("n", n);
print_mpz("e", e);
print_mpz("d", d);

// 要签名的消息
const char *message = "Hello, RSA digital signature!";
size_t msg_len = strlen(message);
printf("\\n原始消息: %s\\n", message);

// 签名
mpz_t signature;
mpz_init(signature);
rsa_sign((const unsigned char*)message, msg_len, d, n, signature);
print_mpz("\\n签名值 (s)", signature);

// 验证
int valid = rsa_verify((const unsigned char*)message, msg_len,
signature, e, n);
if (valid)
printf("\\n签名验证成功!\\n");
else
printf("\\n签名验证失败!\\n");

// 篡改测试:修改消息
const char *tampered = "Hello, RSA digital signature! (tampered)";
printf("\\n— 篡改测试 —\\n");
printf("篡改后消息: %s\\n", tampered);
valid = rsa_verify((const unsigned char*)tampered, strlen(tampered),
signature, e, n);
if (valid)
printf("错误:篡改消息验证通过\\n");
else
printf("正确:篡改消息被拒绝\\n");

// 清理
mpz_clear(n); mpz_clear(e); mpz_clear(d); mpz_clear(signature);
gmp_randclear(state);
return 0;
}

三、ElGamal签名算法

1、ElGamal数字签名机制

(1)密钥生成(生成公私钥对):

(2)用私钥对消息签名:

(3)用公钥验证签名:

2、ElGamal数字签名的C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <time.h>

// ———- 生成指定比特长度的大素数 ———-
void generate_prime(mpz_t p, unsigned int bits, gmp_randstate_t state) {
do {
mpz_urandomb(p, state, bits);
mpz_setbit(p, bits – 1); // 最高位置1,保证位数
mpz_nextprime(p, p);
} while (mpz_sizeinbase(p, 2) < bits);
}

// ———- 寻找模 p 的原根 g(简单方法,适用于 p 为安全素数)———-
void find_primitive_root(mpz_t g, const mpz_t p, gmp_randstate_t state) {
mpz_t phi, temp, factor;
mpz_init(phi);
mpz_init(temp);
mpz_init(factor);

mpz_sub_ui(phi, p, 1); // φ(p) = p-1

// 获取 p-1 的所有不同素因子(简单试除,最多10个因子)
mpz_t n, i, sq;
mpz_init(n);
mpz_init(i);
mpz_init(sq);
mpz_set(n, phi);

mpz_t factors[10];
for (int idx = 0; idx < 10; idx++) mpz_init(factors[idx]);
int cnt = 0;

// 因子2
if (mpz_even_p(n)) {
mpz_set_ui(factors[cnt], 2);
cnt++;
while (mpz_even_p(n)) mpz_div_ui(n, n, 2);
}
// 奇数因子
mpz_set_ui(i, 3);
mpz_sqrt(sq, n);
while (mpz_cmp(i, sq) <= 0) {
if (mpz_divisible_p(n, i)) {
mpz_set(factors[cnt], i);
cnt++;
while (mpz_divisible_p(n, i)) mpz_div(n, n, i);
mpz_sqrt(sq, n);
}
mpz_add_ui(i, i, 2);
}
if (mpz_cmp_ui(n, 1) > 0) {
mpz_set(factors[cnt], n);
cnt++;
}

// 从 g=2 开始尝试
mpz_set_ui(g, 2);
int ok;
while (1) {
ok = 1;
for (int idx = 0; idx < cnt; idx++) {
mpz_divexact(temp, phi, factors[idx]);
mpz_powm(temp, g, temp, p);
if (mpz_cmp_ui(temp, 1) == 0) {
ok = 0;
break;
}
}
if (ok) break;
mpz_add_ui(g, g, 1);
}

mpz_clear(n); mpz_clear(i); mpz_clear(sq);
for (int idx = 0; idx < 10; idx++) mpz_clear(factors[idx]);
mpz_clear(phi); mpz_clear(temp); mpz_clear(factor);
}

// ———- 密钥生成 ———-
// bits: 素数 p 的比特长度(建议 >= 2048)
// 输出:p, g, y(公钥),x(私钥)
void elgamal_sig_keygen(unsigned int bits, mpz_t p, mpz_t g, mpz_t y, mpz_t x, gmp_randstate_t state) {
generate_prime(p, bits, state);
find_primitive_root(g, p, state);
// 私钥 x:2 <= x <= p-2
mpz_urandomm(x, state, p);
if (mpz_cmp_ui(x, 2) < 0) mpz_set_ui(x, 2);
// 公钥 y = g^x mod p
mpz_powm(y, g, x, p);
}

// ———- 签名生成 ———-
// 输入:消息哈希值 m(整数,0 < m < p-1),私钥 x,素数 p,原根 g,随机数 k(1 < k < p-1 且 gcd(k, p-1)=1)
// 输出:签名对 (r, s)
void elgamal_sign(mpz_t r, mpz_t s, const mpz_t m, const mpz_t p,
const mpz_t g, const mpz_t x, mpz_t k, gmp_randstate_t state) {
mpz_t p1, inv_k, tmp;
mpz_init(p1); mpz_init(inv_k); mpz_init(tmp);

mpz_sub_ui(p1, p, 1); // p1 = p-1

// 选择与 p-1 互质的随机数 k
do {
mpz_urandomm(k, state, p1);
if (mpz_cmp_ui(k, 1) < 0) mpz_set_ui(k, 2);
mpz_gcd(tmp, k, p1);
} while (mpz_cmp_ui(tmp, 1) != 0);

// r = g^k mod p
mpz_powm(r, g, k, p);

// inv_k = k^{-1} mod (p-1)
mpz_invert(inv_k, k, p1);

// s = (m – x*r) * inv_k mod (p-1)
mpz_mul(tmp, x, r); // x*r
mpz_sub(tmp, m, tmp); // m – x*r
mpz_mod(tmp, tmp, p1); // 确保非负
mpz_mul(s, tmp, inv_k);
mpz_mod(s, s, p1);

mpz_clear(p1); mpz_clear(inv_k); mpz_clear(tmp);
}

// ———- 签名验证 ———-
// 输入:消息哈希值 m,签名 (r, s),公钥 (p, g, y)
// 返回:1 验证通过,0 失败
int elgamal_verify(const mpz_t m, const mpz_t r, const mpz_t s,
const mpz_t p, const mpz_t g, const mpz_t y) {
if (mpz_cmp_ui(r, 1) < 0 || mpz_cmp(r, p) >= 0) return 0;
if (mpz_cmp_ui(s, 1) < 0 || mpz_cmp(s, p) >= 0) return 0;

mpz_t v1, v2, tmp;
mpz_init(v1); mpz_init(v2); mpz_init(tmp);

// v1 = y^r * r^s mod p
mpz_powm(v1, y, r, p);
mpz_powm(tmp, r, s, p);
mpz_mul(v1, v1, tmp);
mpz_mod(v1, v1, p);

// v2 = g^m mod p
mpz_powm(v2, g, m, p);

int result = (mpz_cmp(v1, v2) == 0);
mpz_clear(v1); mpz_clear(v2); mpz_clear(tmp);
return result;
}

// ———- 主函数演示 ———-
int main() {
// 随机状态初始化
gmp_randstate_t state;
gmp_randinit_default(state);
gmp_randseed_ui(state, time(NULL));

unsigned int bits = 256; // 演示使用256位,实际应>=2048
mpz_t p, g, y, x;
mpz_init(p); mpz_init(g); mpz_init(y); mpz_init(x);
elgamal_sig_keygen(bits, p, g, y, x, state);

gmp_printf("素数 p: %Zd\\n", p);
gmp_printf("原根 g: %Zd\\n", g);
gmp_printf("公钥 y: %Zd\\n", y);
gmp_printf("私钥 x: %Zd\\n", x);

// 消息哈希值(模拟),需满足 0 < m < p-1
mpz_t m, r, s;
mpz_init(m); mpz_init(r); mpz_init(s);
mpz_set_str(m, "1234567890", 10);
gmp_printf("\\n消息哈希值 m: %Zd\\n", m);

// 签名:随机数 k 在函数内部生成
mpz_t k;
mpz_init(k);
elgamal_sign(r, s, m, p, g, x, k, state);
gmp_printf("签名 r: %Zd\\n", r);
gmp_printf("签名 s: %Zd\\n", s);

// 验证
int valid = elgamal_verify(m, r, s, p, g, y);
if (valid)
printf("\\n签名验证成功!\\n");
else
printf("\\n签名验证失败!\\n");

// 篡改测试:修改消息
printf("\\n— 篡改测试 —\\n");
mpz_t m_bad;
mpz_init(m_bad);
mpz_add_ui(m_bad, m, 1);
gmp_printf("篡改后的消息 m': %Zd\\n", m_bad);
int valid_bad = elgamal_verify(m_bad, r, s, p, g, y);
if (valid_bad)
printf("验证错误:篡改消息被接受\\n");
else
printf("正确:篡改消息被拒绝\\n");

// 清理
mpz_clear(p); mpz_clear(g); mpz_clear(y); mpz_clear(x);
mpz_clear(m); mpz_clear(r); mpz_clear(s); mpz_clear(k); mpz_clear(m_bad);
gmp_randclear(state);
return 0;
}

3、ElGamal的安全性

四、DSS签名算法

1、DSS数字签名机制

(1)密钥生成(生成公私钥对):

(2)用私钥对消息签名:

(3)用公钥验证签名:

2、DSS数字签名的C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/sha.h>

/**
* 1. 生成DSA密钥对(使用OpenSSL)
* 参数: dsa – 指向未初始化的DSA对象的指针
* 返回值: 成功返回1,失败返回0
*/
static int generate_dsa_key(DSA **dsa) {
*dsa = DSA_new();
if (*dsa == NULL) {
fprintf(stderr, "无法创建DSA对象\\n");
return 0;
}
// 生成2048位DSA密钥对,q为224位(符合FIPS 186-4标准)
if (!DSA_generate_parameters_ex(*dsa, 2048, NULL, 0, NULL, NULL, NULL)) {
fprintf(stderr, "参数生成失败\\n");
DSA_free(*dsa);
*dsa = NULL;
return 0;
}
if (!DSA_generate_key(*dsa)) {
fprintf(stderr, "密钥生成失败\\n");
DSA_free(*dsa);
*dsa = NULL;
return 0;
}
return 1;
}

/**
* 2. 签名函数(基于EVP接口)
* 参数: dsa – DSA私钥
* message – 待签名的消息
* sign_len – 签名数据长度(输出)
* 返回值: 成功返回指向签名数据的指针,失败返回NULL
*/
static unsigned char* sign_message(DSA *dsa, const unsigned char *message, size_t *sign_len) {
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) return NULL;

// 创建EVP_PKEY结构,整合密钥
EVP_PKEY *pkey = EVP_PKEY_new();
if (!pkey || !EVP_PKEY_assign_DSA(pkey, dsa)) {
EVP_MD_CTX_free(ctx);
return NULL;
}

unsigned char *sig = NULL;
*sign_len = 0;

if (EVP_SignInit_ex(ctx, EVP_sha256(), NULL) &&
EVP_SignUpdate(ctx, message, strlen((char*)message)) &&
EVP_SignFinal(ctx, NULL, sign_len, pkey)) {
sig = (unsigned char*)OPENSSL_malloc(*sign_len);
if (sig) {
if (!EVP_SignFinal(ctx, sig, sign_len, pkey)) {
OPENSSL_free(sig);
sig = NULL;
}
}
}

EVP_PKEY_free(pkey);
EVP_MD_CTX_free(ctx);
return sig;
}

/**
* 3. 验证函数(基于EVP接口)
* 参数: dsa – DSA公钥
* message – 原始消息
* signature – 签名数据
* sign_len – 签名长度
* 返回值: 成功返回1,失败返回0
*/
static int verify_signature(DSA *dsa, const unsigned char *message,
const unsigned char *signature, size_t sign_len) {
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) return 0;

EVP_PKEY *pkey = EVP_PKEY_new();
if (!pkey || !EVP_PKEY_assign_DSA(pkey, dsa)) {
EVP_MD_CTX_free(ctx);
return 0;
}

int result = (EVP_VerifyInit_ex(ctx, EVP_sha256(), NULL) &&
EVP_VerifyUpdate(ctx, message, strlen((char*)message)) &&
EVP_VerifyFinal(ctx, signature, sign_len, pkey));

EVP_PKEY_free(pkey);
EVP_MD_CTX_free(ctx);
return result;
}

/**
* 辅助函数:打印DSA密钥信息
*/
static void print_key_info(DSA *dsa) {
if (!dsa) return;
printf("DSA密钥参数: p, q, g, 公钥, 私钥\\n");
BN_print_fp(stdout, dsa->p);
printf("\\n");
BN_print_fp(stdout, dsa->q);
printf("\\n");
BN_print_fp(stdout, dsa->g);
printf("\\n");
BN_print_fp(stdout, dsa->pub_key);
printf("\\n");
if (dsa->priv_key) {
BN_print_fp(stdout, dsa->priv_key);
printf("\\n");
}
}

/**
* 主函数:演示完整的签名与验证流程
*/
int main() {
// 1. 初始化OpenSSL
OpenSSL_add_all_algorithms();

// 2. 生成密钥对
DSA *dsa = NULL;
if (!generate_dsa_key(&dsa)) {
fprintf(stderr, "密钥生成失败\\n");
return -1;
}
printf("密钥生成成功\\n");
// print_key_info(dsa); // 可选:打印详细信息

// 3. 定义待签名消息
const char *message = "This message will be digitally signed using DSA.";
printf("\\n待签名消息: %s\\n", message);

// 4. 签名消息
size_t sig_len = 0;
unsigned char *signature = sign_message(dsa, (const unsigned char*)message, &sig_len);
if (!signature || sig_len == 0) {
fprintf(stderr, "签名失败\\n");
DSA_free(dsa);
return -1;
}
printf("\\n签名成功,签名大小: %zu 字节\\n", sig_len);

// 5. 验证签名
int is_valid = verify_signature(dsa, (const unsigned char*)message, signature, sig_len);
if (is_valid) {
printf("\\n✓ 签名验证成功:签名有效!\\n");
}
else {
printf("\\n✗ 签名验证失败:签名无效!\\n");
}

// 6. 篡改测试:验证修改后的消息
const char *tampered_msg = "This message has been tampered with.";
printf("\\n— 篡改测试 —\\n");
printf("篡改后消息: %s\\n", tampered_msg);
int tampered_valid = verify_signature(dsa, (const unsigned char*)tampered_msg,
signature, sig_len);
if (tampered_valid) {
printf("错误:篡改消息被错误识别为有效!\\n");
}
else {
printf("正确:篡改消息被成功识别并拒绝。\\n");
}

// 7. 清理内存
OPENSSL_free(signature);
DSA_free(dsa);
EVP_cleanup();
return 0;
}

五、ElGamal类签名算法

1、ElGamal类数字签名机制

(1)密钥生成(生成公私钥对):

(2)用私钥对消息签名:

(3)用公钥验证签名:

2、ElGamal类数字签名的C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

/*************************
* 宏配置:a b c 可自由修改
* 这是 ElGamal 类签名的通用形式
* a*k ≡ b + c*x (mod q)
*************************/
#define a 1 // 你可以改成任意 1~q-1
#define b Hm // b = 哈希值
#define c r // c = r

// 简易哈希函数(演示用)
uint32_t hash(uint32_t m) {
return m ^ 0x12345678;
}

// 快速幂取模:base^exponent mod mod
uint32_t pow_mod(uint32_t base, uint32_t exponent, uint32_t mod) {
uint32_t result = 1;
base = base % mod;
while (exponent > 0) {
if (exponent % 2 == 1)
result = (result * base) % mod;
base = (base * base) % mod;
exponent /= 2;
}
return result;
}

// 求逆元(费马小定理,mod 是素数)
uint32_t inv_mod(uint32_t x, uint32_t mod) {
return pow_mod(x, mod – 2, mod);
}

/*************************
* ElGamal 类签名
* 输入:p, q, g, x, k, Hm
* 输出:r, s
*************************/
void elgamal_sign(
uint32_t p, uint32_t q, uint32_t g,
uint32_t x, uint32_t k, uint32_t Hm,
uint32_t *r, uint32_t *s
) {
*r = pow_mod(g, k, p);

// 公式:a*k ≡ b + c*x (mod q)
// => s = (b + c*x – a*k ) * inv(k) mod q
uint32_t ak = (a * k) % q;
uint32_t bx_plus_cx = (b + c * x) % q;

int32_t numerator = bx_plus_cx – ak;
if (numerator < 0) numerator += q;

uint32_t k_inv = inv_mod(k, q);
*s = (numerator * k_inv) % q;
}

/*************************
* ElGamal 类验证
* 验证:g^b * y^c ≡ r^a (mod p)
*************************/
int elgamal_verify(
uint32_t p, uint32_t q, uint32_t g, uint32_t y,
uint32_t Hm, uint32_t r, uint32_t s
) {
uint32_t left = (pow_mod(g, b, p) * pow_mod(y, c, p)) % p;
uint32_t right = pow_mod(r, a, p);
return left == right;
}

int main() {
// 安全参数(小素数,仅演示)
uint32_t p = 23;
uint32_t q = 11;
uint32_t g = 11;

// 私钥 x,公钥 y = g^x mod p
uint32_t x = 7;
uint32_t y = pow_mod(g, x, p);

// 消息与哈希
uint32_t msg = 123;
uint32_t Hm = hash(msg);

// 随机数 k
uint32_t k = 3;

// 签名
uint32_t r, s;
elgamal_sign(p, q, g, x, k, Hm, &r, &s);

printf("签名结果:r=%u, s=%u\\n", r, s);

// 验证
int ok = elgamal_verify(p, q, g, y, Hm, r, s);
printf("验证结果:%s\\n", ok ? "通过 ✅" : "失败 ❌");

return 0;
}

六、特殊性质的签名算法

1、盲签名

(1)盲签名是在发送者A和签名者B之间的双方协议,其基本思想如下:

①A发送给B一段信息,B对它签名并送回A。从这个签名,A能够计算B关于A预先所选消息m的签名。

②协议完成时,B既不知道消息m也不知道消息的签名。

(2)盲签名的目的是防止B看到消息和签名,从而使B以后不能将所签消息和发送者A联系起来。

(3)盲签名的应用:

(4)盲签名协议需要下列组件:

(5)Chaum盲签名协议:

2、不可否认签名

(1)不可否认签名没有签名者的合作,接收者无法验证签名。

(2)不可否认签名的应用:

①实体A(客户)希望访问被实体B(银行)控制的某个安全区域,比如该安全区域可能是存放保险箱的房间,在许可访问之前,B要求A签署一份时间和日期的文件,如果A采用了不可否认签名,那么在验证过程中没有A的直接参与,(在以后的日期)B就不能向任何人证明A使用过安全区域中的设施。

②假定某大公司A制作了一个软件包,A对软件包签名并将它卖给实体B,而B决定将其拷贝再卖给第三方C,那么没有A的合作C就无法验证该软件是否正版,当然,这种措施并不能阻止B用它自己的签名重新签署软件包,但因此B也就无法利用与A名气相关的市场利益,而且追踪B的欺诈行为也将很容易。

(3)一个不可否认签名方案由三部分组成——签名算法、验证协议、否认协议。

(4)签名者可以声称一个签名是伪造的,在这种情况下,如果签名者拒绝参加验证,就可认为签名者有欺骗行为,如果签名者参加验证,由否认协议就可推断出签名的真伪。

(5)否认协议需要做到以下两点:

①B能使A相信一个不合法的签名是伪造的。

②B以很小的概率使A相信一个合法签名是伪造的。

(6)不可否认签名的一个不足之处是签名者有可能不在场或者拒绝合作,而导致签名无法被接收者验证。

3、群签名

(1)群签名允许群里的某个成员以群的名义匿名地签发消息,满足下述三个条件:

①只有群中的成员才能代表群进行签名。

②签名的接收者能验证签名是哪一个群的一个合法签名,但不能分辨具体的签名者。

③一旦出现争端,可借助群成员或一个可信的机构能识别出签名者。

(2)群签名的应用:

        一个公司有几台计算机,每台都联在局域网上

        公司的每个部门有其自己的打印机(也连在局域网上),并且只有本部门的人员才能允许使用其部门的打印机,因此,打印前必须确认用户在哪个部门工作,同时公司为了保密,不可以暴露用户的身份,然而,如果有人滥用打印机,主管者必须能找出是谁在滥用打印机

(3)一个群签名方案由以下几个部分组成:

①建立(setup):一个用以产生群公钥和私钥的多项式概率算法。

②加入(join):一个用户和群管理员之间的交互式协议。执行该协议可以使用户成为群成员,群管理员得到群成员的秘密的成员管理密钥,并产生群成员的私钥和成员证书。

③签名(sign):一个概率算法,当输入一个消息、一个群成员的私钥和一个群公钥后,输出对该消息的签名。

④验证(verify):给定一个消息的签名和一个群公钥后,判断该签名相对于该群公钥是否有效。

⑤打开(open):给定一个签名、群公钥和群私钥的条件下确定签名者的身份。

4、代理签名

        一个代理签名方案由以下几个部分组成:

        ①系统建立:选定代理签名方案的系统参数,用户的密钥等

        ②签名权力的委托:原始签名者将自己的签名权力委托给代理签名者

        ③代理签名的产生:代理签名者代表原始签名者产生代理签名

        ④代理签名的验证:验证人验证代理签名的有效性

赞(0)
未经允许不得转载:171主机测评 » 现代密码学 第六章——数字签名
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址