RSA数字签名认证

一、RSA数字签名认证

1.数字签名

数字签名是一种用于验证数据完整性和身份认证的加密技术。使用数字签名可以提高数据传输的安全性和可靠性,确保数据在传输过程中不被篡改或伪造,并且可以确定数据的发送者身份。

数字签名可以确保数据的完整性和安全性。

2.步骤

  • 发送方使用私钥对要发送的消息进行签名

    • 如果使用RSA算法,发送方需要对消息先进行哈希处理,然后再用私钥对哈希值进行加密,以生成数字签名
  • 发送方将消息数字签名一起发送给接收方

  • 接收方使用发送方的公钥对数字签名进行解密和验证得到消息摘要A,并与用消息哈希处理后得到的消息摘要比较。

  • 如果数字签名有效(相等),那么接收方就可以确定该消息确实来自于发送方,因为只有发送方拥有与该数字签名相对应的私钥。

  • 如果数字签名无效,接收方则可以拒绝该消息或者尝试使用其他的安全机制来保护其通信安全。

RSA数字签名认证_第1张图片

  • 哈希函数我们可以选择MD5SHA256,这里用MD5
    • MD5是一种常见的哈希函数,可以将任意长度的消息压缩成一个固定长度的摘要(通常是128位),并且具有高度的不可逆性和碰撞防御性。(但已经被证明不再安全)
    • RSA加密算法只能加密有限长度的数据,而哈希算法则可以将任意长度的消息压缩成固定长度的摘要。
  • 数字签名技术并不能保证消息的机密性,只能保证消息的来源和完整性
  • 认证成功后就可以开始通信了,可以通过加密和解密来保证信息的安全。

二、python实现

import hashlib
import random

from sympy import isprime


def modinv(a, m):
    """计算a关于模数m的模反元素"""

    def egcd(a, b):
        """扩展欧几里得算法,用于计算最大公约数和系数"""
        if a == 0:
            return b, 0, 1
        else:
            g, y, x = egcd(b % a, a)
            return g, x - (b // a) * y, y

    g, x, y = egcd(a, m)
    if g != 1:
        # 如果模反元素不存在,则引发异常
        raise ValueError("modular inverse does not exist")
    else:
        # 返回结果,但结果可能是负数,确保最终结果落在[0, m)之间
        return x % m


def generate_prime_number(num_digits):
    """生成指定位数的素数"""
    while True:
        # 生成范围在10^(n-1)到10^n之间的随机数
        num = random.randint(10 ** (num_digits - 1), 10 ** num_digits - 1)
        # 确保num为奇数(提高找到范围内质数的效率)
        num |= 1
        # 是否是素数
        if isprime(num):
            return num


def keys(num):
    """生成密钥"""
    p = generate_prime_number(num)
    # 使得p和q的差距不超过一个数量级,并且p!=q
    q = generate_prime_number(num + 1)
    while p == q:
        q = generate_prime_number(num + 1)
    n = p * q
    # 计算欧拉函数
    pin = (p - 1) * (q - 1)
    # 公钥指数
    e = 65537
    # 求模反元素d
    d = modinv(e, pin)
    # 公钥和私钥
    return (n, e), (n, d)


def digital_signature(message, private_key):
    """生成数字签名"""
    # 哈希函数处理得到消息摘要
    hashobj = hashlib.md5()
    hashobj.update(message)
    digest = hashobj.digest()
    # 发送方使用私钥通过RSA加密消息摘要,得到数字签名
    num = int.from_bytes(digest, byteorder='big')  # 字节转为数字
    digest_num = encrypt(private_key, num)
    return digest_num


def identification(message, digest_num, public_key):
    """数字签名认证"""
    # 对消息进行哈希处理,得到新的消息摘要
    hashobj = hashlib.md5()
    hashobj.update(message)
    digest = hashobj.digest()
    new_message_num = int.from_bytes(digest, byteorder='big')  # 字节转为数字
    # 使用发送方的公钥对收到的数字签名通过RSA解密,得到原始的消息摘要
    message_num = decrypt(public_key, digest_num)
    # 判断新的消息摘要和原始的消息摘要是否相等
    if new_message_num == message_num:
        print("认证成功,可开始通信!")
        return True
    else:
        print("认证失败")
        return False


def encrypt(public_key, plaintext):
    """RSA加密"""
    n, e = public_key
    ciphertext = pow(plaintext, e, n)
    # 返回的是数字,还需要处理
    return ciphertext


def decrypt(private_key, ciphertext):
    """RSA解密"""
    n, d = private_key
    plaintext = pow(ciphertext, d, n)
    # 返回的是数字,还需要处理
    return plaintext


# 测试A对B发送消息

"""
    下方用编码解码的方式实现字符串和整数的互转。
    字符串str需要支持编码格式
"""
# 消息
str = "1100011"
print(f"消息:{str}")
message = str.encode('ascii')  # 用ascii编码为字节

# 生成B的一对密钥(速度较慢,这里位数用小一些演示)
public_key, private_key = keys(20)
print(f"公钥B:{public_key}")
print(f"私钥B:{private_key}")

# 生成数字签名
dig_signal = digital_signature(message, private_key)

# 认证
result = identification(message, dig_signal, public_key)

# 认证成功则开始通信
if result:
    # 加密,A使用B的公钥对明文加密
    message_num = int.from_bytes(message, byteorder='big')  # 字节转整数,大端存储
    ciphertext_num = encrypt(public_key, message_num)  # 得到的密文数字
    print(f"加密-密文数字:{ciphertext_num}")

    # 解密,B使用B的密钥对密文解密
    plaintext_num = decrypt(private_key, ciphertext_num)  # 得到的明文数字
    plaintext = plaintext_num.to_bytes((plaintext_num.bit_length() + 7) // 8, byteorder='big').decode('ascii')  # 整数转字节然后用ascii解码
    print(f"解密-明文:{plaintext}")

三、运行截图

RSA数字签名认证_第2张图片

你可能感兴趣的:(密码学,安全,python)