精华内容
下载资源
问答
  • 基于rsa的数字签名实验
    千次阅读
    2021-12-28 20:05:57

    利用Python实现RSA数字签名的产生和验证过程。

    任务1:准备一个私钥文件,一个公钥文件,一个数据文件;
      任务2:定义一个函数,能够使用指定的私钥对数据文件进行签 名,并将签名结果输出到文件返回;
      任务3:定义一个函数,能够使用指定的公钥对任务2中的签名    文件进行验证,返回验证结果;
      任务4:利用任务1中的文件对任务2和3中的函数进行测试。

    标准库Hashlib

    实现了SHA1,SHA224以及MD5等多个安全哈希算法,

    pycryptodome的使用

    • Python扩展库pycryptodome和cryptography,提供了SHA系列算法和其他哈希算法,以及DES,AES,RSA等多个加密算法和签名算法的实现
    • pycryptodome是加密库
    • pycryptodome模块不是Python的内置模块,pycryptodome模块实现了各种算法和协议的加密模块的结合,结合了各种加密方式对应的多种加密算法的实现,包括单向加密、对称加密以及公钥加密和随机数操作。
      区别:
      crypto是GPG加解密库,该库已于2016年停更,且pythongnupg库才是最主流的GPG加解密库。
      PyCrypto是Python前主流加解密库,但已停更。
      PyCryptodome是当前最主流的Python加解密库,如果遇到代码中import Crypto等字样,就需要安装这个库。
      安装pycryptodome: pip install pycryptodome

    1、公钥加密

    Crypto.PubicKey.RSA生成私公密钥对

    • 在该模块下的RSA.py源代码中提供了直接生成原始密钥的函数,所以要使用Crypto.Random模块生成
    from Crypto.PublicKey import RSA
    
    key = RSA.generate(2048)
    private_key = key.export_key()
    public_key = key.publickey().export_key()
    
    print(key)
    # print(private_key)
    # print(public_key)
    

    输出:

    Private RSA key at 0x1A81094DF70
    

    用generate函数生成的密钥是一个私钥对象,通过export_key()函数返回这个密钥:

    2、RSA.import_key获得公私密钥

    • 上文已经可以输出一对公私密钥,还要用import_key函数
    • 因为publicKey是一个公钥的实例化对象,即public_key的实例化对象,在使用PKCS1_OAEP实例化加密套件时传入的参数必须是这个对象,查阅PKCS1_OAEP.py的源代码也发现传入的参数key应该是一个对象

    3、RSA加密

    from Crypto.PublicKey import RSA
    
    key = RSA.generate(2048)
    private_key = key.export_key()
    public_key = key.publickey().export_key()
    
    # print(key)
    # print(private_key)
    # print(public_key)
    
    from Crypto.Cipher import PKCS1_OAEP
    
    data = b"123456"
    
    publicKey = RSA.import_key(public_key)
    # print(publicKey)
    # 加密
    cipher = PKCS1_OAEP.new(publicKey)
    encrypted_data = cipher.encrypt(data)
    print(encrypted_data)
    
    

    输出

    b'"9\x8fW+b\x83\xbf\xc7y\xfc3\xb5R@`\xf4\xad}\x9a\x11\x81\xf2\x0f\xf1\xc6_\xf0K\xb7\xf7t\xcb\xaevK\x08\x8cg\xa1\x8ai\x94\xdf8\xc6\\\xb5\xb8\x98\xfd}A\xb3\\\xf7\x91J\x88\x84/\xdc\xd8\xe7<\xe4\xfa[\n`X\xf5\xf6K\xd9`s\x17\x11F\x80~\xcdt$>$R\x86b\x11*m\xeb\xe0\x87,):&g\x98\'\x90\xbf\x8cK\xef\xbb-\xfc\xecF\x93G!\xf7\xff&\x91\xdc\xdcY\xff\xf76\x91\xcb\n\x1a\xb4\xf3\xcep6\xde5\xf0^\xe1\'\xf7\t\xc5\xdbU6\x83\xc7\xf5\xe2\xeb\xf7\xe3;J\xd1\x9b\xd0\x925!\x98s\x189\xdd\xa8=\xbfw^\xe8R\xdc\xce\xb8\xdb`\x96 f\x85\xd7\x10>\xea\x97\x05p\x8c\x00\xd5\xf0\xae\xea\x0c\xf9\x03\xd98N\xbc\xd8RD]\x97Y\x8a/\n\xec\xb5\xe5\xe9\x8ea\x87\xaeE\x9fM\xc7\\\x0c\xefE*}\xea\xcd*\x1f\xacR\xd7X\x85\xea\xbfl\xcc\xa5\xed\x91\x90\x07\x13\xdd\x97\x8c\xfcl\xf2y'
    
    

    加密完成

    4、RSA解密

    # 解密
    privateKey = RSA.import_key(private_key)
    cipher = PKCS1_OAEP.new(privateKey)
    data = cipher.decrypt(encrypted_data)
    print(data)
    
    

    输出

    b'123456'
    

    三、数字签名与验签

    • 数字签名与验签,简单来说步骤为:A使用自己的私钥对消息进行签名,将签名后的信息和公钥发送给B,B使用公钥验证签名是否属于A。
    • 使用Crypto.Publickey,Crypto.Hash,Crypto.Signature三个库,即公钥加密、摘要算法、数字签名三个库
    • 1、Crypto.Hash获取消息的HASH值

    • 这里会用到摘要算法,常用的摘要算法有:MD2,MD4,MD5,SHA-1,SHA-256,RIPEMD128,RIPEMD160等等,用什么摘要算法不重要,只要在验证时有相同的摘要算法即可。这里选择MD5.
    • 2、Crypho.Signature对HASH值使用私钥进行签名

    • 本质上是使用私钥对HASH值进行加密,将公钥私钥以及消息分别放在public_key.pem、private_key.pem、data.txt三个文件中,
    • 有两个注意:获得公私钥要用import_key函数;从data.txt中读取信息后要使用相应的编码格式,digest=MD5.new(data.encode(‘utf-8’))
    • 在Crypto.Signature中随便选择一个模式,选择pkcs1_15模式对消息进行签名
    • 3、签名验证

    • 签名验证部分需要传入三个信息:消息原文(data)、摘要算法(MD5)、HASH值签名结果(signature)

    实验总代码

    from Crypto.PublicKey import RSA
    
    key = RSA.generate(2048)
    
    # 任务1:准备一个私钥文件,一个公钥文件,一个数据文件
    private_key = key.export_key()
    public_key = key.publickey().export_key()
    data = "I love you"
    with open("private_key.pem", "wb") as prifile,\
        open("public_key.pem", "wb") as pubfile,\
        open("data.txt","a") as datafile:
        prifile.write(private_key)
        pubfile.write(public_key)
        datafile.write(data)
    
    from Crypto.Signature import pkcs1_15
    from Crypto.Hash import MD5
    from Crypto.PublicKey import RSA
    
    # 签名
    with open("data.txt", "r") as datafile:
        data = datafile.read()
    
    
    # print(data)
    
    # 任务2:定义签名函数,能够使用指定的私钥对数据文件进行签名,并将签名结果输出到文件返回
    def signaturer(private_key, data):
        # 获取消息的HASH值,摘要算法MD5,验证时也必须用MD5
        digest = MD5.new(data.encode('utf-8'))
        # 使用私钥对HASH值进行签名
        signature = pkcs1_15.new(private_key).sign(digest)
        # 将签名结果写入文件
        sig_results = open("sig_results.txt", "wb")
        sig_results.write(signature)
        sig_results.close()
        return sig_results
    
    
    # 任务3:定义签名验证函数,能够使用指定的公钥对任务2中的签名文件进行验证,返回验证结果
    def verifier(public_key, data, signature):
        digest = MD5.new(data.encode('utf-8'))
        try:
            pkcs1_15.new(public_key).verify(digest, signature)
            print("验证成功!!!")
        except:
            print("签名无效!!!")
    
    
    # 任务4:利用任务1中的文件对任务2和3中的函数进行测试。
    with open('private_key.pem') as prifile, \
            open('data.txt') as datafile:
        private_key = RSA.import_key(prifile.read())
        data = datafile.read()
    
        signaturer(private_key, data)
    
    with open('public_key.pem') as pubfile, \
            open('data.txt') as datafile, \
            open('sig_results.txt', 'rb') as sigfile:
        public_key = RSA.import_key(pubfile.read())
        data = datafile.read()
        signature = sigfile.read()
    
        verifier(public_key, data, signature)
    
    
    
    更多相关内容
  • 编程实现RSA数字签名

    2022-06-14 21:54:47
    一、实验目的:理解RSA数字签名,并运用编程实现RSA数字签名。二、实验过程:1.学习RSA算法及RSA数字签名算法流程。2. RSA数字签名原理:当发送方想要给接收方发送数据,并想进行数字签名的时候,发送方只需要利用...

    一、实验目的:

    理解RSA数字签名,并运用编程实现RSA数字签名。

    二、实验过程:

    1.学习RSA算法及RSA数字签名算法流程。

    2. RSA数字签名原理:当发送方想要给接收方发送数据,并想进行数字签名的时候,发送方只需要利用自己的私钥,对数据进行数字签名算法,就可以得到一个新的签名数据,这时发送方需要把自己原来的数据,以及新得到的签名数据都发送给接收方,接收方接受到签名数据之后,用发送方的公钥对签名数据进行验证算法,看得出来的数据与发送方发送过来的数据是不是完全一样的即可。

    三、实验代码及结果:

    (1)实验代码:

    import random

    import math

    #快速幂取模

    def power(a, b, n):  #计算a**b mod n

        if b == 0:

            return 1      #如果b值为0则返回1

        elif b % 2 == 0:  # 如果二进制b最后一位为0

            p = power(a, b / 2, n)      #递归实现

            return (p * p) % n    #取模运算

        else:

            return (a * power(a, b - 1, n)) % n       #返回结果

    # 欧几里得算法求最大公约数

    def gcd(a, b):

        if a < b:

            return gcd(b, a)        #如果a小于b,交换两个数

        elif a % b == 0:

            return b      #如果a整除于b则返回b

        else:

            return gcd(b, a % b)        #递归实现欧几里得算法

    #确定是否是素数

    def isPrime(num):

        if (num < 2):

            return False              #如果num的值小于2返回false

        else:

            i = 2

            flag=True

            while i < num:  # 如果num能被i整除,说明num不是质数

                if num % i == 0:

                    flag = False     # 只要num不是质数,将flag的值修改为 False

                i += 1

            return  flag      #最后返回flag的值

    #生成大素数函数

    def randPrime(n):

        Start = 10 ** (n-1)   #n的值为5,计算开始值10**4

        End = (10 ** n) - 1  #计算结束10**5-1

        while True:

            num = random.randint(Start, End)  #返回从start到end之间任意一个数表示大素数

            if isPrime(num):      #判断是否是质数,如果是则生成

                return num       #返回大素数的值num

    # 扩展的欧几里得算法,即ab=1 (mod n), 得到a在模n下的乘法逆元b

    def Extended_Eulid(a, n):

        x1, x2, x3 = 1, 0, n

        y1, y2, y3 = 0, 1, a

        while y3 != 1 and y3 != 0 and y3 > 0:

            Q = math.floor(x3 / y3)

            t1, t2, t3 = x1 - Q * y1, x2 - Q * y2, x3 - Q * y3

            x1, x2, x3 = y1, y2, y3

            y1, y2, y3 = t1, t2, t3

        if y3 == 0:

            return 0

        if y3 == 1:

            if y2 >0:

                return y2

            else:

                return n+y2

    # 生成公钥和私钥

    def KeyGen(p, q):      #分别计算n,e,d的值

        n = p * q

        e = random.randint(1, (p - 1) * (q - 1))

        while gcd(e, (p - 1) * (q - 1)) != 1:       #运用欧几里得算法判断

            e = random.randint(1, (p - 1) * (q - 1))

        d = Extended_Eulid(e, (p - 1) * (q - 1))

        return n, e, d

    #利用快速幂取模计算签名

    def Sign(x, d, n):

        s = power(x, d, n)

        return s

    #利用快速幂取模判断是否有效签名

    def Verify(s, e, n):

        x_ = power(s, e, n)

        return x_

    #主函数

    if __name__ == '__main__':

        key_size = 5

        p = randPrime(key_size)        #p与q分别为随机生成的大素数

        q = randPrime(key_size)

        n, e, d = KeyGen(p, q)            #用p与q生成公钥和私钥

        # 输入消息

        x = int(input("请输入加密信息(必须为整数): "))

       

        # 计算签名

        s = Sign(x, d, n)

        # 验证签名

        x_ = Verify(s, e, n)

        Valid = (x_ == x)

        # 伪造数据攻击

        s_ = random.randint(1, (p - 1) * (q - 1))

        m_ = random.randint(1, (p - 1) * (q - 1))

        # 输出

        print("私钥: ")

        print("N: ", n)

        print("d: ", d)

        print("公钥: ")

        print("N: ", n)

        print("e: ", e)

        print("签名: ")

        print("s: ", s)

        print("验证m的签名: ")

        if Valid:

            print("签名有效")

        else:

            print("签名无效")

        print("m'(伪): ", m_)

        if Verify(m_, s, n) == x:

            print("签名有效")

        else:

            print("签名无效")

        print("s' (伪): ", s_)

        if Verify(x_, s_, n) == x:

            print("签名有效")

        else:

            print("签名无效")

    import random
    
    import math
    
    
    
    #快速幂取模
    
    def power(a, b, n):  #计算a**b mod n
    
        if b == 0:
    
            return 1      #如果b值为0则返回1
    
        elif b % 2 == 0:  # 如果二进制b最后一位为0
    
            p = power(a, b / 2, n)      #递归实现
    
            return (p * p) % n    #取模运算
    
        else:
    
            return (a * power(a, b - 1, n)) % n       #返回结果
    
    
    
    # 欧几里得算法求最大公约数
    
    def gcd(a, b):
    
        if a < b:
    
            return gcd(b, a)        #如果a小于b,交换两个数
    
        elif a % b == 0:
    
            return b      #如果a整除于b则返回b
    
        else:
    
            return gcd(b, a % b)        #递归实现欧几里得算法
    
    
    
    #确定是否是素数
    
    def isPrime(num):
    
        if (num < 2):
    
            return False              #如果num的值小于2返回false
    
        else:
    
            i = 2
    
            flag=True
    
            while i < num:  # 如果num能被i整除,说明num不是质数
    
                if num % i == 0:
    
                    flag = False     # 只要num不是质数,将flag的值修改为 False
    
                i += 1
    
            return  flag      #最后返回flag的值
    
    
    
    #生成大素数函数
    
    def randPrime(n):
    
        Start = 10 ** (n-1)   #n的值为5,计算开始值10**4
    
        End = (10 ** n) - 1  #计算结束10**5-1
    
        while True:
    
            num = random.randint(Start, End)  #返回从start到end之间任意一个数表示大素数
    
            if isPrime(num):      #判断是否是质数,如果是则生成
    
                return num       #返回大素数的值num
    
    
    
    # 扩展的欧几里得算法,即ab=1 (mod n), 得到a在模n下的乘法逆元b
    
    def Extended_Eulid(a, n):
    
        x1, x2, x3 = 1, 0, n
    
        y1, y2, y3 = 0, 1, a
    
        while y3 != 1 and y3 != 0 and y3 > 0:
    
            Q = math.floor(x3 / y3)
    
            t1, t2, t3 = x1 - Q * y1, x2 - Q * y2, x3 - Q * y3
    
            x1, x2, x3 = y1, y2, y3
    
            y1, y2, y3 = t1, t2, t3
    
        if y3 == 0:
    
            return 0
    
        if y3 == 1:
    
            if y2 >0:
    
                return y2
    
            else:
    
                return n+y2
    
    # 生成公钥和私钥
    
    def KeyGen(p, q):      #分别计算n,e,d的值
    
        n = p * q
    
        e = random.randint(1, (p - 1) * (q - 1))
    
        while gcd(e, (p - 1) * (q - 1)) != 1:       #运用欧几里得算法判断
    
            e = random.randint(1, (p - 1) * (q - 1))
    
        d = Extended_Eulid(e, (p - 1) * (q - 1))
    
        return n, e, d
    
    #利用快速幂取模计算签名
    
    def Sign(x, d, n):
    
        s = power(x, d, n)
    
        return s
    
    #利用快速幂取模判断是否有效签名
    
    def Verify(s, e, n):
    
        x_ = power(s, e, n)
    
        return x_
    
    #主函数
    
    if __name__ == '__main__':
    
        key_size = 5
    
        p = randPrime(key_size)        #p与q分别为随机生成的大素数
    
        q = randPrime(key_size)
    
        n, e, d = KeyGen(p, q)            #用p与q生成公钥和私钥
    
    
    
        # 输入消息
    
        x = int(input("请输入加密信息(必须为整数): "))
    
       
    
        # 计算签名
    
        s = Sign(x, d, n)
    
        # 验证签名
    
        x_ = Verify(s, e, n)
    
        Valid = (x_ == x)
    
    
    
        # 伪造数据攻击
    
        s_ = random.randint(1, (p - 1) * (q - 1))
    
        m_ = random.randint(1, (p - 1) * (q - 1))
    
    
    
        # 输出
    
        print("私钥: ")
    
        print("N: ", n)
    
        print("d: ", d)
    
        print("公钥: ")
    
        print("N: ", n)
    
        print("e: ", e)
    
        print("签名: ")
    
        print("s: ", s)
    
        print("验证m的签名: ")
    
        if Valid:
    
            print("签名有效")
    
        else:
    
            print("签名无效")
    
    
    
        print("m'(伪): ", m_)
    
        if Verify(m_, s, n) == x:
    
            print("签名有效")
    
        else:
    
            print("签名无效")
    
        print("s' (伪): ", s_)
    
        if Verify(x_, s_, n) == x:
    
            print("签名有效")
    
        else:
    
            print("签名无效")

    (2)实验结果:

    展开全文
  • rsa数字签名

    2013-06-03 15:35:17
    一个基于RSA数字签名程序源代码,简单实现了数字签名功能
  • 数字签名算法,c++实现,RSA的算法

    热门讨论 2010-12-23 10:10:56
    包涵三个RSA算法,c++是实现,数字签名的合集,三个独自的程序,可以独自编译运行,VC6.0下编译
  • RSA数字签名源程序

    2012-08-01 14:13:25
    RSA数字签名源程序,可直接使用,调试方法请看readme文件。适合课程实验所用。
  • mbedtls系列文章 mbedtls | 01 - 移植mbedtls库到STM32的两种方法 mbedtls | 02 - 伪随机数生成器(ctr_drbg)的配置与使用 mbedtls | 03 - 单向散列算法...mbedtls | 06 - 非对称加密算法的配置与使用(RSA算法) mbe

    mbedtls系列文章

    Demo工程源码

    本工程基于STM32L41RCT6开发板,包含了本系列文章中所编写的所有Demo,持续更新……



    一、数字签名算法

    1. 什么是数字签名

    数字签名类似于盖章和签字,数字签名可以检查消息是否被篡改、并验证消息的可靠性,因为私钥只有签名者持有,所以还可以防止否认。

    2. 数字签名算法

    RSA数字签名

    RSA数字签名算法基于RSA非对称加密算法,在用于数字签名时公钥和私钥的用法刚好相反:

    • 发送方使用私钥对消息执行加密操作 = 对消息进行签名;
    • 接收方使用公钥对签名进行解密 = 对签名进行认证;

    RSA签名算法还需要包括填充方法,有两种:PKCS1-V1.5和PSS(使用随机数填充,推荐使用)。

    DSA算法

    ECDSA算法

    在相同的安全等级下,ECDSA算法具有秘钥短、执行效率高的特点,更适合物联网应用。

    二、RSA数字签名功能模块的配置与使用

    1. 配置宏

    使用RSA功能需要提前开启伪随机数生成器(依赖AES算法、SHA256算法、MD通用接口),其中伪随机数生成器的硬件适配移植实现已经讲述,请参考对应的第二篇博客,不再赘述。

    综合上述,本实验中需要开启的宏如下表:

    宏定义功能
    MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES不使用默认熵源(如果已有、要屏蔽该宏)
    MBEDTLS_NO_PLATFORM_ENTROPY不使用系统内置熵源
    MBEDTLS_AES_C使用AES算法
    MBEDTLS_ENTROPY_C使能熵源模块
    MBEDTLS_CTR_DRBG_C使能随机数模块
    MBEDTLS_SHA256_C使能SHA256算法
    MBEDTLS_MD_C开启MD通用接口
    MBEDTLS_AES_ROM_TABLES使能预定义S盒(节约内存空间)
    MBEDTLS_BIGNUM_C开启大数运算
    MBEDTLS_GENPRIME开启生成素数
    MBEDTLS_OID_C开启OID数据结构模块
    MBEDTLS_RSA_C开启RSA算法
    MBEDTLS_PKCS1_V21开启PKCS#1 v2.1填充方案(OAEP)

    新建配置文件mbedtls_config_rsa_sign.h,编写以下内容:

    /**
     * @brief   Minimal configuration for RSA Sign Function
     * @author  mculover666
     * @date    2020/10/03
    */
    
    #ifndef _MBEDTLS_CONFIG_RSA_SIGN_H_
    #define _MBEDTLS_CONFIG_RSA_SIGN_H_
    
    /* System support */
    #define MBEDTLS_HAVE_ASM
    //#define MBEDTLS_HAVE_TIME
    
    /* mbed feature support */
    #define MBEDTLS_ENTROPY_HARDWARE_ALT
    //#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
    #define MBEDTLS_NO_PLATFORM_ENTROPY
    
    /* mbed modules */
    #define MBEDTLS_AES_C
    #define MBEDTLS_AES_ROM_TABLES
    #define MBEDTLS_CTR_DRBG_C
    #define MBEDTLS_ENTROPY_C
    #define MBEDTLS_SHA256_C
    #define MBEDTLS_MD_C
    #define MBEDTLS_BIGNUM_C
    #define MBEDTLS_GENPRIME
    #define MBEDTLS_OID_C
    #define MBEDTLS_RSA_C
    #define MBEDTLS_PKCS1_V21
    
    #include "mbedtls/check_config.h"
    
    #endif /* _MBEDTLS_CONFIG_RSA_SIGN_H_ */
    
    

    在MDK中设置使用该配置文件:

    2. RSA数字签名功能模块API说明

    使用该功能模块需要包含头文件:

    #include "mbedtls/rsa.h"
    

    ① RSA签名接口

    /**
     * \brief          This function performs a private RSA operation to sign
     *                 a message digest using PKCS#1.
     *
     *                 It is the generic wrapper for performing a PKCS#1
     *                 signature using the \p mode from the context.
     *
     * \note           The \p sig buffer must be as large as the size
     *                 of \p ctx->N. For example, 128 Bytes if RSA-1024 is used.
     *
     * \note           For PKCS#1 v2.1 encoding, see comments on
     *                 mbedtls_rsa_rsassa_pss_sign() for details on
     *                 \p md_alg and \p hash_id.
     *
     * \deprecated     It is deprecated and discouraged to call this function
     *                 in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library
     *                 are likely to remove the \p mode argument and have it
     *                 implicitly set to #MBEDTLS_RSA_PRIVATE.
     *
     * \note           Alternative implementations of RSA need not support
     *                 mode being set to #MBEDTLS_RSA_PUBLIC and might instead
     *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
     *
     * \param ctx      The initialized RSA context to use.
     * \param f_rng    The RNG function to use. If the padding mode is PKCS#1 v2.1,
     *                 this must be provided. If the padding mode is PKCS#1 v1.5 and
     *                 \p mode is #MBEDTLS_RSA_PRIVATE, it is used for blinding
     *                 and should be provided; see mbedtls_rsa_private() for more
     *                 more. It is ignored otherwise.
     * \param p_rng    The RNG context to be passed to \p f_rng. This may be \c NULL
     *                 if \p f_rng is \c NULL or doesn't need a context argument.
     * \param mode     The mode of operation. This must be either
     *                 #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated).
     * \param md_alg   The message-digest algorithm used to hash the original data.
     *                 Use #MBEDTLS_MD_NONE for signing raw data.
     * \param hashlen  The length of the message digest.
     *                 Ths is only used if \p md_alg is #MBEDTLS_MD_NONE.
     * \param hash     The buffer holding the message digest or raw data.
     *                 If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable
     *                 buffer of length \p hashlen Bytes. If \p md_alg is not
     *                 #MBEDTLS_MD_NONE, it must be a readable buffer of length
     *                 the size of the hash corresponding to \p md_alg.
     * \param sig      The buffer to hold the signature. This must be a writable
     *                 buffer of length \c ctx->len Bytes. For example, \c 256 Bytes
     *                 for an 2048-bit RSA modulus. A buffer length of
     *                 #MBEDTLS_MPI_MAX_SIZE is always safe.
     *
     * \return         \c 0 if the signing operation was successful.
     * \return         An \c MBEDTLS_ERR_RSA_XXX error code on failure.
     */
    int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx,
                        int (*f_rng)(void *, unsigned char *, size_t),
                        void *p_rng,
                        int mode,
                        mbedtls_md_type_t md_alg,
                        unsigned int hashlen,
                        const unsigned char *hash,
                        unsigned char *sig );
    

    ② RSA验证签名接口

    /**
     * \brief          This function performs a public RSA operation and checks
     *                 the message digest.
     *
     *                 This is the generic wrapper for performing a PKCS#1
     *                 verification using the mode from the context.
     *
     * \note           For PKCS#1 v2.1 encoding, see comments on
     *                 mbedtls_rsa_rsassa_pss_verify() about \p md_alg and
     *                 \p hash_id.
     *
     * \deprecated     It is deprecated and discouraged to call this function
     *                 in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library
     *                 are likely to remove the \p mode argument and have it
     *                 set to #MBEDTLS_RSA_PUBLIC.
     *
     * \note           Alternative implementations of RSA need not support
     *                 mode being set to #MBEDTLS_RSA_PRIVATE and might instead
     *                 return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED.
     *
     * \param ctx      The initialized RSA public key context to use.
     * \param f_rng    The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE,
     *                 this is used for blinding and should be provided; see
     *                 mbedtls_rsa_private() for more. Otherwise, it is ignored.
     * \param p_rng    The RNG context to be passed to \p f_rng. This may be
     *                 \c NULL if \p f_rng is \c NULL or doesn't need a context.
     * \param mode     The mode of operation. This must be either
     *                 #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated).
     * \param md_alg   The message-digest algorithm used to hash the original data.
     *                 Use #MBEDTLS_MD_NONE for signing raw data.
     * \param hashlen  The length of the message digest.
     *                 This is only used if \p md_alg is #MBEDTLS_MD_NONE.
     * \param hash     The buffer holding the message digest or raw data.
     *                 If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable
     *                 buffer of length \p hashlen Bytes. If \p md_alg is not
     *                 #MBEDTLS_MD_NONE, it must be a readable buffer of length
     *                 the size of the hash corresponding to \p md_alg.
     * \param sig      The buffer holding the signature. This must be a readable
     *                 buffer of length \c ctx->len Bytes. For example, \c 256 Bytes
     *                 for an 2048-bit RSA modulus.
     *
     * \return         \c 0 if the verify operation was successful.
     * \return         An \c MBEDTLS_ERR_RSA_XXX error code on failure.
     */
    int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx,
                          int (*f_rng)(void *, unsigned char *, size_t),
                          void *p_rng,
                          int mode,
                          mbedtls_md_type_t md_alg,
                          unsigned int hashlen,
                          const unsigned char *hash,
                          const unsigned char *sig );
    

    3. 编写测试函数

    新建文件mbedtls_rsa_sign_test.c,编写以下测试内容:

    /**
     * @brief   RSA Sign Function demo
     * @author  mculover666
     * @date    2020/10/03
    */
    
    #if !defined(MBEDTLS_CONFIG_FILE)
    #include "mbedtls/config.h"
    #else
    #include MBEDTLS_CONFIG_FILE
    #endif
    
    #if defined(MBEDTLS_RSA_C)
    
    #include <stdio.h>
    #include "string.h"
    #include "mbedtls/entropy.h"
    #include "mbedtls/ctr_drbg.h"
    #include "mbedtls/rsa.h"
    
    static char buf[516];
    
    static void dump_rsa_key(mbedtls_rsa_context *ctx)
    {
        size_t olen;
        
        printf("\n  +++++++++++++++++ rsa keypair +++++++++++++++++\n\n");
        mbedtls_mpi_write_string(&ctx->N , 16, buf, sizeof(buf), &olen);
        printf("N: %s\n", buf); 
    
        mbedtls_mpi_write_string(&ctx->E , 16, buf, sizeof(buf), &olen);
        printf("E: %s\n", buf);
    
        mbedtls_mpi_write_string(&ctx->D , 16, buf, sizeof(buf), &olen);
        printf("D: %s\n", buf);
    
        mbedtls_mpi_write_string(&ctx->P , 16, buf, sizeof(buf), &olen);
        printf("P: %s\n", buf);
    
        mbedtls_mpi_write_string(&ctx->Q , 16, buf, sizeof(buf), &olen);
        printf("Q: %s\n", buf);
    
        mbedtls_mpi_write_string(&ctx->DP, 16, buf, sizeof(buf), &olen);
        printf("DP: %s\n", buf);
    
        mbedtls_mpi_write_string(&ctx->DQ, 16, buf, sizeof(buf), &olen);
        printf("DQ: %s\n", buf);
    
        mbedtls_mpi_write_string(&ctx->QP, 16, buf, sizeof(buf), &olen);
        printf("QP: %s\n", buf);
        printf("\n  +++++++++++++++++ rsa keypair +++++++++++++++++\n\n");
    }
    
    static void dump_buf(uint8_t *buf, uint32_t len)
    {
        int i;
        
        for (i = 0; i < len; i++) {
            printf("%s%02X%s", i % 16 == 0 ? "\r\n\t" : " ", 
                               buf[i], 
                               i == len - 1 ? "\r\n" : "");
        }
    }
    
    static uint8_t output_buf[2048/8];
    
    int mbedtls_rsa_sign_test(void)
    {
        int ret;
        const char* msg = "HelloWorld";
       
        const char *pers = "rsa_sign_test";
        mbedtls_entropy_context entropy;
        mbedtls_ctr_drbg_context ctr_drbg;
        mbedtls_rsa_context ctx;
    
        /* 1. init structure */
        mbedtls_entropy_init(&entropy);
        mbedtls_ctr_drbg_init(&ctr_drbg);
        mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
        
        /* 2. update seed with we own interface ported */
        printf( "\n  . Seeding the random number generator..." );
        
        ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
                                   (const unsigned char *) pers,
                                   strlen(pers));
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_ctr_drbg_seed returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
    
        /* 3. generate an RSA keypair */
        printf( "\n  . Generate RSA keypair..." );
        
        ret = mbedtls_rsa_gen_key(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537);
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_rsa_gen_key returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
        
        /* shwo RSA keypair */
        dump_rsa_key(&ctx);
        
        /* 4. sign */
        printf( "\n  . RSA pkcs1 sign..." );
        
        ret = mbedtls_rsa_pkcs1_sign(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256, strlen(msg), (uint8_t *)msg, output_buf);
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_rsa_pkcs1_sign returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
        
        /* show sign result */
        dump_buf(output_buf, sizeof(output_buf));
        
        /* 5. verify sign*/
        printf( "\n  . RSA pkcs1 verify..." );
        
        ret = mbedtls_rsa_pkcs1_verify(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, strlen(msg), (uint8_t *)msg, output_buf);
        
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_rsa_pkcs1_encrypt returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
        
        exit:
        
        /* 5. release structure */
        mbedtls_ctr_drbg_free(&ctr_drbg);
        mbedtls_entropy_free(&entropy);
        mbedtls_rsa_free(&ctx);
        
        return ret;
    }
    
    #endif /* MBEDTLS_RSA_C */
    
    

    4. 测试结果

    在main.c中声明该测试函数:

    extern int mbedtls_rsa_sign_test(void);
    

    在main函数中调用该测试函数:

    /* 8. rsa sign test */
    mbedtls_rsa_sign_test();
    

    编译、下载,在串口助手中查看测试结果:

    ① 生成秘钥对成功(需要几min的时间):

    ② 生成签名和验证签名成功:

    三、ECDSA数字签名功能模块的配置与使用

    1. 配置宏

    使用ECDSA秘钥协商功能需要提前开启伪随机数生成器(依赖AES算法、SHA256算法、MD通用接口),其中伪随机数生成器的硬件适配移植实现已经讲述,请参考对应的第二篇博客,不再赘述。

    综合上述,本实验中需要开启的宏如下表:

    宏定义功能
    MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES不使用默认熵源(如果已有、要屏蔽该宏)
    MBEDTLS_NO_PLATFORM_ENTROPY不使用系统内置熵源
    MBEDTLS_AES_C使用AES算法
    MBEDTLS_ENTROPY_C使能熵源模块
    MBEDTLS_CTR_DRBG_C使能随机数模块
    MBEDTLS_SHA256_C使能SHA256算法
    MBEDTLS_MD_C开启MD通用接口
    MBEDTLS_AES_ROM_TABLES使能预定义S盒(节约内存空间)
    MBEDTLS_BIGNUM_C开启大数运算
    MBEDTLS_ECP_C开启椭圆曲线基础运算
    MBEDTLS_ECP_DP_SECP256R1_ENABLED选择secp256r1曲线参数
    MBEDTLS_ECDSA_C开启ECDSA算法
    MBEDTLS_ASN1_WRITE_C开启ASN1格式写入
    MBEDTLS_ASN1_PARSE_C开启ASN1结构解析

    下面补充几个一个第一次出现宏的定义。

    MBEDTLS_ECDSA_C

    /**
     * \def MBEDTLS_ECDSA_C
     *
     * Enable the elliptic curve DSA library.
     *
     * Module:  library/ecdsa.c
     * Caller:
     *
     * This module is used by the following key exchanges:
     *      ECDHE-ECDSA
     *
     * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C
     */
    #define MBEDTLS_ECDSA_C
    

    MBEDTLS_ASN1_WRITE_C

    /**
     * \def MBEDTLS_ASN1_WRITE_C
     *
     * Enable the generic ASN1 writer.
     *
     * Module:  library/asn1write.c
     * Caller:  library/ecdsa.c
     *          library/pkwrite.c
     *          library/x509_create.c
     *          library/x509write_crt.c
     *          library/x509write_csr.c
     */
    #define MBEDTLS_ASN1_WRITE_C
    

    MBEDTLS_ASN1_PARSE_C

    /**
     * \def MBEDTLS_ASN1_PARSE_C
     *
     * Enable the generic ASN1 parser.
     *
     * Module:  library/asn1.c
     * Caller:  library/x509.c
     *          library/dhm.c
     *          library/pkcs12.c
     *          library/pkcs5.c
     *          library/pkparse.c
     */
    #define MBEDTLS_ASN1_PARSE_C
    

    新建配置文件mbedtls_config_ecdsa.h,编写以下内容:

    /**
     * @brief   Minimal configuration for ECDSA Function
     * @author  mculover666
     * @date    2020/10/03
    */
    
    #ifndef _MBEDTLS_CONFIG_ECDSA_H_
    #define _MBEDTLS_CONFIG_ECDSA_H_
    
    /* System support */
    #define MBEDTLS_HAVE_ASM
    //#define MBEDTLS_HAVE_TIME
    
    /* mbed feature support */
    #define MBEDTLS_ENTROPY_HARDWARE_ALT
    //#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
    #define MBEDTLS_NO_PLATFORM_ENTROPY
    
    /* mbed modules */
    #define MBEDTLS_AES_C
    #define MBEDTLS_AES_ROM_TABLES
    #define MBEDTLS_CTR_DRBG_C
    #define MBEDTLS_ENTROPY_C
    #define MBEDTLS_SHA256_C
    #define MBEDTLS_MD_C
    #define MBEDTLS_BIGNUM_C
    #define MBEDTLS_ECP_C
    #define MBEDTLS_ECP_DP_SECP256R1_ENABLED
    #define MBEDTLS_ECDSA_C
    #define MBEDTLS_ASN1_WRITE_C
    #define MBEDTLS_ASN1_PARSE_C
    
    #include "mbedtls/check_config.h"
    
    #endif /* _MBEDTLS_CONFIG_ECDSA_H_ */
    
    

    在MDK中配置使用该配置文件:

    2. ECDSA签名功能API说明

    ① 初始化ECDSA结构体:

    /**
     * \brief           This function initializes an ECDSA context.
     *
     * \param ctx       The ECDSA context to initialize.
     *                  This must not be \c NULL.
     */
    void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx );
    

    ② ECDSA生成秘钥接口:

    /**
     * \brief          This function generates an ECDSA keypair on the given curve.
     *
     * \see            ecp.h
     *
     * \param ctx      The ECDSA context to store the keypair in.
     *                 This must be initialized.
     * \param gid      The elliptic curve to use. One of the various
     *                 \c MBEDTLS_ECP_DP_XXX macros depending on configuration.
     * \param f_rng    The RNG function to use. This must not be \c NULL.
     * \param p_rng    The RNG context to be passed to \p f_rng. This may be
     *                 \c NULL if \p f_rng doesn't need a context argument.
     *
     * \return         \c 0 on success.
     * \return         An \c MBEDTLS_ERR_ECP_XXX code on failure.
     */
    int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid,
                      int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
    

    ③ ECDSA签名接口:

    /**
     * \brief           This function computes the ECDSA signature of a
     *                  previously-hashed message.
     *
     * \note            The deterministic version implemented in
     *                  mbedtls_ecdsa_sign_det() is usually preferred.
     *
     * \note            If the bitlength of the message hash is larger than the
     *                  bitlength of the group order, then the hash is truncated
     *                  as defined in <em>Standards for Efficient Cryptography Group
     *                  (SECG): SEC1 Elliptic Curve Cryptography</em>, section
     *                  4.1.3, step 5.
     *
     * \see             ecp.h
     *
     * \param grp       The context for the elliptic curve to use.
     *                  This must be initialized and have group parameters
     *                  set, for example through mbedtls_ecp_group_load().
     * \param r         The MPI context in which to store the first part
     *                  the signature. This must be initialized.
     * \param s         The MPI context in which to store the second part
     *                  the signature. This must be initialized.
     * \param d         The private signing key. This must be initialized.
     * \param buf       The content to be signed. This is usually the hash of
     *                  the original data to be signed. This must be a readable
     *                  buffer of length \p blen Bytes. It may be \c NULL if
     *                  \p blen is zero.
     * \param blen      The length of \p buf in Bytes.
     * \param f_rng     The RNG function. This must not be \c NULL.
     * \param p_rng     The RNG context to be passed to \p f_rng. This may be
     *                  \c NULL if \p f_rng doesn't need a context parameter.
     *
     * \return          \c 0 on success.
     * \return          An \c MBEDTLS_ERR_ECP_XXX
     *                  or \c MBEDTLS_MPI_XXX error code on failure.
     */
    int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
                    const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
                    int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
    

    ④ ECDSA验证签名接口

    /**
     * \brief           This function verifies the ECDSA signature of a
     *                  previously-hashed message.
     *
     * \note            If the bitlength of the message hash is larger than the
     *                  bitlength of the group order, then the hash is truncated as
     *                  defined in <em>Standards for Efficient Cryptography Group
     *                  (SECG): SEC1 Elliptic Curve Cryptography</em>, section
     *                  4.1.4, step 3.
     *
     * \see             ecp.h
     *
     * \param grp       The ECP group to use.
     *                  This must be initialized and have group parameters
     *                  set, for example through mbedtls_ecp_group_load().
     * \param buf       The hashed content that was signed. This must be a readable
     *                  buffer of length \p blen Bytes. It may be \c NULL if
     *                  \p blen is zero.
     * \param blen      The length of \p buf in Bytes.
     * \param Q         The public key to use for verification. This must be
     *                  initialized and setup.
     * \param r         The first integer of the signature.
     *                  This must be initialized.
     * \param s         The second integer of the signature.
     *                  This must be initialized.
     *
     * \return          \c 0 on success.
     * \return          #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the signature
     *                  is invalid.
     * \return          An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX
     *                  error code on failure for any other reason.
     */
    int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
                              const unsigned char *buf, size_t blen,
                              const mbedtls_ecp_point *Q, const mbedtls_mpi *r,
                              const mbedtls_mpi *s);
    

    ⑤ 释放ECDSA结构体:

    /**
     * \brief           This function frees an ECDSA context.
     *
     * \param ctx       The ECDSA context to free. This may be \c NULL,
     *                  in which case this function does nothing. If it
     *                  is not \c NULL, it must be initialized.
     */
    void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx );
    

    3. 编写测试函数

    新建文件mbedtls_ecdsa_test,编写以下测试函数:

    /**
     * @brief   ECDSA Function demo
     * @author  mculover666
     * @date    2020/10/03
    */
    
    #if !defined(MBEDTLS_CONFIG_FILE)
    #include "mbedtls/config.h"
    #else
    #include MBEDTLS_CONFIG_FILE
    #endif
    
    #if defined(MBEDTLS_ECDSA_C)
    
    #include <stdio.h>
    #include "string.h"
    #include "mbedtls/entropy.h"
    #include "mbedtls/ctr_drbg.h"
    #include "mbedtls/ecdsa.h"
    
    uint8_t buf[97];
    
    static void dump_buf(uint8_t *buf, uint32_t len)
    {
        int i;
        
        for (i = 0; i < len; i++) {
            printf("%s%02X%s", i % 16 == 0 ? "\r\n\t" : " ", 
                               buf[i], 
                               i == len - 1 ? "\r\n" : "");
        }
    }
    
    int mbedtls_ecdsa_test(void)
    {
        int ret;
        size_t qlen, dlen;
        size_t rlen, slen;
        uint8_t hash[32];
       
        const char *msg  = "HelloWorld";
        const char *pers = "ecdsa_test";
        mbedtls_entropy_context entropy;
        mbedtls_ctr_drbg_context ctr_drbg;
        mbedtls_mpi r, s;
        mbedtls_ecdsa_context ctx;
        mbedtls_md_context_t md_ctx;
            
        /* 1. init structure */
        mbedtls_md_init(&md_ctx);
        mbedtls_entropy_init(&entropy);
        mbedtls_ctr_drbg_init(&ctr_drbg);
        mbedtls_mpi_init(&r);
        mbedtls_mpi_init(&s);
        
        /* 2. update seed with we own interface ported */
        printf( "\n  . Seeding the random number generator..." );
        
        ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
                                   (const unsigned char *) pers,
                                   strlen(pers));
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_ctr_drbg_seed returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
        
        /* 3. hash message */
        printf( "\n  . Hash message..." );
        
        ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), (uint8_t *)msg, strlen(msg), hash);
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_md returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
        
        /* show hash */
        dump_buf(hash, sizeof(hash));
        
        /* 4. generate keypair */
        printf( "\n  . Generate ecdsa keypair..." );
        
        ret = mbedtls_ecdsa_genkey(&ctx, MBEDTLS_ECP_DP_SECP256R1, mbedtls_ctr_drbg_random, &ctr_drbg);
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_ecdsa_genkey returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
        
        /* show keypair */
        mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &qlen, buf, sizeof(buf));
        dlen = mbedtls_mpi_size(&ctx.d);
        mbedtls_mpi_write_binary(&ctx.d, buf + qlen, dlen);
        dump_buf(buf, qlen + dlen);
        
        /* 5. ecdsa sign */
        printf( "\n  . ECDSA sign..." );
        
        ret = mbedtls_ecdsa_sign(&ctx.grp, &r, &s, &ctx.d, hash, sizeof(hash), mbedtls_ctr_drbg_random, &ctr_drbg);
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_ecdsa_sign returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
        
        /* show sign */
        rlen = mbedtls_mpi_size(&r);
        slen = mbedtls_mpi_size(&s);
        mbedtls_mpi_write_binary(&r, buf, rlen);
        mbedtls_mpi_write_binary(&s, buf + rlen, slen);
        dump_buf(buf, rlen + slen);
        
        /* 6. ecdsa verify */
        printf( "\n  . ECDSA verify..." );
        
        ret = mbedtls_ecdsa_verify(&ctx.grp, hash, sizeof(hash), &ctx.Q, &r, &s);
        if(ret != 0) {
            printf( " failed\n  ! mbedtls_ecdsa_verify returned %d(-0x%04x)\n", ret, -ret);
            goto exit;
        }
        printf( " ok\n" );
    
        exit:
        
        /* 7. release structure */
        mbedtls_ctr_drbg_free(&ctr_drbg);
        mbedtls_entropy_free(&entropy);
        mbedtls_mpi_free(&r);
        mbedtls_mpi_free(&s);
        mbedtls_md_free(&md_ctx);
        mbedtls_ecdsa_free(&ctx);
        
        return ret;
    }
    
    #endif /* MBEDTLS_DHM_C */
    
    

    4. 测试结果

    在main.c中声明该函数:

    extern int mbedtls_ecdsa_test(void);
    

    在main函数中调用该函数:

    /* 9. ecdsa sign test */
    mbedtls_ecdsa_test();
    

    编译、下载,在串口助手中查看结果:

    接收精彩文章及资源推送,请订阅我的微信公众号:『mculover666』

    展开全文
  • 这里写自定义目录标题利用PBC库实现盲签名 利用PBC库实现盲签名 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法...

    1. 利用PBC库实现基于BLS的盲签名

    BLS(Boneh-Lynn-Shacham) 签名算法是一种可以实现签名聚合和密钥聚合的算法(即可以将多个密钥聚合成一把密钥,将多个签名聚合成一个签名)。可以通过这篇(理解BLS签名算法)CSDN来理解BLS签名。
    PBC库(The Pairing-Based Cryptography Library)可以实现基于双线性对的密码编程,关于PBC库的细节可以参考我的PBC Library专栏。
    盲签名算法如下图所示,其中 H ˉ ( ) \bar H() Hˉ()表示BLS哈希, r i r_i ri是从Zp群随机选择的元素。
    基于BLS的盲签名算法
    在单个程序(不区分客户端和服务器端,不进行消息传递)中实现盲签名代码:
    代码中多了一步操作,将文件块按照1KB大小进行了分块。

    #include <iostream>
    #include <fstream>
    // for pbc library
    #include "/usr/local/include/pbc/pbc.h"
    // for encrypt
    #include <openssl/md5.h>
    #include <openssl/sha.h>
    // for gmp library
    #include <gmp.h>
    
    using namespace std;
    
    // 全局参数
    char source[] = "sourceFiles/";
    #define PARAM "a.param"
    
    pairing_t pairing;
    element_t public_key;  // 密钥服务器的公钥
    element_t secret_key;  // 密钥服务器的私玥
    element_t g;           // 系统参数g,生成元
    
    int initPairing(){
    	// 读param参数文件
    	string s = PARAM;
    	ifstream in(s.c_str());
    	istreambuf_iterator<char> beg(in), end;
    	string strdata(beg, end);
    	in.close();
    //	cout <<strdata<<endl;
    	if(pairing_init_set_str(pairing, strdata.c_str())){  // 初始化pairing
    		cout<<"failed"<<endl;
    	}
    	element_init_G2(g, pairing);
    	element_init_G2(public_key, pairing);
    	element_init_Zr(secret_key, pairing);
    
    	// 生成系统参数g
    	element_random(g);
    //	element_printf("system parameter g = %B\n", g);
    	// 生成私玥
    	element_random(secret_key);
    //	element_printf("private key = %B\n", secret_key);
    	// compute corresponding public key
    	element_pow_zn(public_key, g, secret_key);
    //	element_printf("public key = %B\n", public_key);
    
    	return 0;
    }
    
    /*
     * 将文件块的hash值映射到群上
     */
    int BLSHash(element_t h, char *behindHash, int hashLen){
    	element_init_G1(h, pairing);
    	element_from_hash(h, behindHash, hashLen);
    	return 0;
    }
    
    int sigAndCheck256(char *databuf, long size){
    
    	int hash_length = SHA256_DIGEST_LENGTH;
    	unsigned char digest[hash_length];
    	SHA256((unsigned char*)databuf, size, (unsigned char*)&digest);
    	element_t h;
    	BLSHash(h, (char*)digest, hash_length);
    	element_t r;
    	element_init_Zr(r, pairing);
    	element_random(r);
    
    	// h*g^r盲化
    	element_t h_blind;
    	element_init_G1(h_blind, pairing);
    	element_t blindFactor;
    	element_init_G2(blindFactor, pairing);
    	element_pow_zn(blindFactor, g, r);
    	element_mul(h_blind, h, blindFactor);
    
    	element_t h_blind_sig;
    	element_init_G1(h_blind_sig, pairing);
    
    	element_pow_zn(h_blind_sig, h_blind, secret_key);
    
    	// 去盲化
    	element_t h_sig;  // 去盲化后
    	element_init_G1(h_sig, pairing);
    
    	element_t neg_r;
    	element_t KSpk_negr;
    	element_init_Zr(neg_r, pairing);
    	element_init_G2(KSpk_negr, pairing);
    	element_neg(neg_r, r);
    
    	element_pow_zn(KSpk_negr, public_key, neg_r); // y^-r
    	element_mul(h_sig, h_blind_sig, KSpk_negr); // 去盲化过程
    
    	// 验证
    	element_t temp1, temp2;
    	element_init_GT(temp1, pairing);
    	element_init_GT(temp2, pairing);
    	element_pairing(temp1, h_sig, g);
    	element_pairing(temp2, h, public_key);
    	if(!element_cmp(temp1, temp2)){
    		printf("success\n");
    		return 1;
    	}else{
    		printf("failed\n");
    		return 0;
    	}
    }
    
    int readFile(string filename, long size){
    	string fullPath = source +filename;
    	fstream in;
    
    	in.open(fullPath.c_str(), ios::in|ios::binary);
    	if(!in){
    		cout<<"error!"<<endl;
    	}
    	int temp = in.tellg();
    	in.seekg(0, ios_base::end);
    	long filelen = in.tellg();
    	in.seekg(temp);
    	int n;
    	int lastLen;
    	if((filelen % size) == 0){  // 整数倍时
    		n = filelen / size;
    		lastLen = size;
    	}else{
    		n = filelen / size;
    		lastLen = filelen % size + size;
    	}
    
    	char *databuf = new char[size];
    
    
    	for(int i=0;i<n-1;i++){ // 前n-1个块
    		in.read(databuf,size*sizeof(char));
    		sigAndCheck256(databuf, size);
    	}
    	char *databufLast = new char[lastLen];
    	in.read(databufLast,lastLen*sizeof(char));
    	sigAndCheck256(databufLast, lastLen);
    
    	return 0;
    }
    int main() {
    	initPairing();
    	readFile("4k.txt", 1024);
    	return 0;
    }
    

    2. 利用Openssl库实现基于RSA的盲签名

    基于RSA的盲签名思想与上面的思想类似,假设Alice想让Bob给她的文件m进行盲签名。
    (1)Bob作为服务器有自己的公私钥,公钥为 ( n , e ) (n, e) (n,e),私钥为 ( n , d ) (n, d) (n,d)
    (2)Alice首先使用Hash函数对自己的消息m进行哈希得 h ( m ) h(m) h(m)
    (3)盲化处理。Alice选择一个随机数 k k k,生成盲化后的消息 m ′ = h ( m ) k e m o d   n m' = h(m) k^e mod\ n m=h(m)kemod n,然后将 m ′ m' m发送给Bob。
    (4)Bob收到后直接在收到的消息上进行签名, S ′ = S i g n ( m ′ ) S' = Sign(m') S=Sign(m),然后将签名 S ′ S' S返回给Alice。
    (5)去盲化。将(3)中的式子带入(4)中得, S ′ = h d ( m )   k   m o d   n S'=h^d(m)\ k \ mod\ n S=hd(m) k mod n,只需要再把k去掉即可,即 S = S ′   k − 1 S=S' \ k^{-1} S=S k1,其中 k − 1 k^{-1} k1表示k在模n意义下的逆。
    (6)签名验证。验证 S e S^e Se是否与 h ( m ) h(m) h(m)相等。

    #include <iostream>
    #include <string.h>
    #include <fstream>
    #include <openssl/bn.h>
    #include <openssl/evp.h>
    #include <openssl/rsa.h>
    #include <openssl/sha.h>
    
    using namespace std;
    
    // 全局变量
    char source[] = "sourceFiles/";
    RSA *r;
    BIGNUM *bne;
    unsigned long e = RSA_F4; //  RSA公钥指数
    int bits = 2048;  // RSA密钥长度
    
    
    int KeyGen(){
    	int ret;
    	bne = BN_new();
    	ret = BN_set_word(bne, e);
    	r = RSA_new();
    	ret = RSA_generate_key_ex(r, bits, bne, NULL);  // 生成RSA密钥
    	if (ret != 1) {
    		printf("RSA_generate_key_ex err!\n");
    		return -1;
    	} else {
    //		printf("生成了RSA密钥。\n");
    	}
    	return 0;
    }
    
    int blindSig(char *databuf, long size){
    	// 对消息message进行sha256 hash,得到hm
    	unsigned char hm[SHA256_DIGEST_LENGTH + 1];
    	SHA256((unsigned char*)databuf, size, (unsigned char*) hm);
    //	for (int i = 0; i < 32; i++) {
    //		printf("%02X", hm[i]);
    //	}
    //	printf("\n");
    
    	BIGNUM *nn;  // 模数
    	nn = r->n;
    	// 生成随机数k
    	BIGNUM *k;  // 随机数k
    	k = BN_new();
    	BN_rand_range(k, nn);  // 选取小于模数的随机数k
    
    	BN_CTX*ctx;
    	ctx = BN_CTX_new();
    
    	// 盲化因子blindF = k ^ bne (mod nn)
    	// 相当于使用公钥加密k
    	BIGNUM *blind;
    	blind = BN_new();
    	BN_mod_exp(blind, k, bne, nn, ctx);
    
    	// 将hm转为BN bn_hm
    	BIGNUM *bn_hm;
    	bn_hm = BN_new();
    	BN_bin2bn(hm, SHA256_DIGEST_LENGTH, bn_hm);
    //	BN_print_fp(stdout, bn_hm);
    //	printf("\n");
    
    	// 对bn_hm进行盲化 m_blind = bn_hm * blind  (mod nn)
    	BIGNUM *m_blind;
    	m_blind = BN_new();
    	BN_mod_mul(m_blind, bn_hm, blind, nn, ctx);
    
    	// 服务器使用私钥对m_blind进行签名为signed_blind_bn
    	BIGNUM *signed_blind_bn;
    	signed_blind_bn = BN_new();
    	BN_mod_exp(signed_blind_bn, m_blind, r->d, nn, ctx);
    
    	// 盲签名后结果发回客户端
    	// 求得k模nn下的逆
    	BIGNUM *k_inverse;
    	k_inverse = BN_new();
    	BN_mod_inverse(k_inverse, k, nn, ctx);
    
    	// 去盲化得signed_bn
    	BIGNUM *signed_bn;
    	signed_bn = BN_new();
    	BN_mod_mul(signed_bn, signed_blind_bn, k_inverse, nn, ctx);
    
    	// 公钥验证签名
    	BIGNUM *hm2_bn;
    	hm2_bn = BN_new();
    	BN_mod_exp(hm2_bn, signed_bn, bne, nn, ctx);
    
    //	BN_print_fp(stdout, hm2_bn);
    //	printf("\n");
    	if(!BN_cmp(bn_hm, hm2_bn)){
    		printf("success!\n");
    	}else{
    		printf("Failed!\n");
    	}
    	return 0;
    }
    
    int readFile(string filename, long size){
    	string fullPath = source +filename;
    	fstream in;
    
    	in.open(fullPath.c_str(), ios::in|ios::binary);
    	if(!in){
    		cout<<"error!"<<endl;
    	}
    	int temp = in.tellg();
    	in.seekg(0, ios_base::end);
    	long filelen = in.tellg();
    	in.seekg(temp);
    	int n;
    	int lastLen;
    	if((filelen % size) == 0){  // 整数倍时
    		n = filelen / size;
    		lastLen = size;
    	}else{
    		n = filelen / size;
    		lastLen = filelen % size + size;
    	}
    
    	char *databuf = new char[size];
    
    	for(int i=0;i<n-1;i++){ // 前n-1个块
    		in.read(databuf,size*sizeof(char));
    		blindSig(databuf, size);
    	}
    	char *databufLast = new char[lastLen];
    	in.read(databufLast,lastLen*sizeof(char));
    	blindSig(databufLast, lastLen);
    
    	return 0;
    }
    
    int main() {
    	KeyGen();
    	readFile("4k.txt", 1024);
    	return 0;
    }
    

    3.比较

    首先比较时间,虽然说基于椭圆曲线的公钥密码体制的速度要比RSA安全的多且同安全程度下速度更快,160位的ECC就可以达到1024位RSA的安全,就像NITS给出的比较结果。

    RSA key size (bits)ECC key size (bits)
    1024160
    2048224
    3072256
    7680384

    但是双线性对的运算我也不是很懂,不多作说明,只能进行简单的时间测试。
    分别测试了基于1024位、2048位RSA和BLS的盲签名算法,随着文件大小的增大时间花费(文件大小主要影响的是签名次数)。
    在这里插入图片描述

    从图中可以看出,基于BLS的盲签名算法效率远不如RSA(据PBC Library给出的安全性,A曲线大体与1024位RSA差不多)(注意需要时重新查证)。但是BLS签名的优点远不是在这里,其可以进行签名聚合、密钥聚合等,多用户时会节省很多时间和空间。

    注:

    数据都是自己通过实验自己测出来的,具体理论目前只是稍微了解,参考时请注意求证,如有大神发现问题请及时提出,不想误导他人。

    展开全文
  • RSA算法原理及数字签名技术

    千次阅读 2021-12-24 23:22:25
    1.前言: 非对称加密算法的经典算法———RSA算法的应用...RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。但是对于量
  • 针对普通XML数字签名的可否认问题,首先介绍了XML数字签名原理,然后分析了RSA签名机制和不可否认签名方案,在此基础上提出了一种改进的不可否认签名算法,并将其应用到XML数字签名结构的签名方法中,从而提出了一种...
  • 基于RSA的实用门限签名

    千次阅读 2020-04-22 17:31:29
    2 基于RSA的门限签名 2.1 系统初始化 系统中有lll个参与者,编号分别为1,...,l1,...,l1,...,l,有一个可信的dealer和一个敌手adversary。dealer选择两个长度(512bit)相等的素数ppp和qqq,设p=2p′+1,q=2q′+1p=2p...
  • 借助python的pycrypto库,使用公/私钥RSA加密和AES对称会话密钥加密,使用RSA算法进行签名。 具体实现: 事先生成好两对RSA公钥和密钥,分别保存在客户端和服务端本地,AES会话密钥由双方沟通确定。定义AESUtil类和...
  • RSA算法和RSA数字签名算法的实现

    千次阅读 2018-05-04 15:26:15
    RSA算法和RSA数字签名算法的实现http://blog.chinaunix.net/uid-21880738-id-1813146.html...实现RSA算法包括生成RSA密钥,用RSA加密规则和解密规则处理数据.RSA数字签名算法利用RSA算法实现数字签名.本文详述了R...
  • 基于RSA与HMAC的数字签名算法及其原理 数字签名是一种认证机制,它使得消息的产生者可以添加一个起签名作用的码字。通过计算消息的Hash值并使用产生者的私钥加密Hash值来生成签名。签名保证了消息来源和...
  • 针对数字签名技术中签名信息易被移除的问题,在语义技术的基础上提出了基于语义水印的数字签名算法。该算法的基本思想是在不改变文本语义的前提下,通过同义词替换算法嵌入签名信息,并在数据加密阶段,综合运用DES...
  • } /** * 随机生成密钥对 * @throws NoSuchAlgorithmException */ public static void genKeyPair() throws NoSuchAlgorithmException { // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 ...
  • 实验项目2 :RSA算法

    2021-05-30 16:38:55
    实验RSA数字签名 一、实验目的 (1)了解RSA算法的特点 (2)掌握RSA算法的加解密原理 (3)掌握RSA数字签名算法的原理 二、实验内容 RSA 公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥...
  • 针对传统RSA密码算法运算...然后通过仿真实验,将其与传统RSA算法以及基于乘同余对称特性的SMM算法和指数2k进制化相结合的组合优化算法相比较,实验结果表明新的RSA密码优化算法在提升运算速度方面达到了较高的水平。
  • 针对传统RSA密码算法运算...然后通过仿真实验,将其与传统RSA算法以及基于乘同余对称特性的SMM算法和指数2k进制化相结合的组合优化算法相比较,实验结果表明新的RSA密码优化算法在提升运算速度方面达到了较高的水平。
  • 为了解决电力调度系统的安全性问题,克服传统公钥密码体制证书管理复杂的缺陷,在无双线性对思想的基础上,构造了一种基于DSA的无证书数字签名方案。方案利用零知识方式对调度用户身份进行认证,将签名身份与公钥...
  • RSA算法C++实现

    2013-12-13 19:48:45
    RSA算法C++实现 报告+源代码bool prime(int n) { int m=sqrt(n); for(int i=2;i;i++) { if(n%i==0) break; } if(i>=m) return 1; else return 0; }
  • RSA算法是第一个既能用于数据加密也能用于数字签名的算法,因此它为公用网络上信息的加密和鉴别提供了一种基本的方法。它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开...
  • 为了解决目前无线ad-hoc网络安全路由协议中的签名算法运算效率较低,从而导致可实现性较差的问题,借鉴多维Hash链的思想,提出一种数字签名算法,并基于这种数字签名算法,给出一套无线ad-hoc安全路由协议的实例。该数字...
  • 实验三 DSA数字签名算法.doc
  • 直接将ElGamal 签名方案移植到椭圆曲线密码系统上...对MV 加密算法进行改进,降低其膨胀率,通过实验证明其执行速度快于RSA 和ECC-E 算法。执行效率及密钥长度方面的优势使2 种改进算法能更有效地应用于智能卡计算中。
  • 本文将详细介绍什么是数字签名,并采用Signtool工具对EXE文件进行签名,后续深入分析数字签名的格式及PE病毒内容。这些基础性知识不仅和系统安全相关,同样与我们身边常用的软件、文档、操作系统紧密联系,希望这些...
  • 密码编码学之数字签名

    千次阅读 2022-02-11 16:02:32
    目录一、数字签名1、 数字签名关键部分的描述2、 数字签名的要求3、 DSA数字签名算法4、 椭圆曲线数字签名算法(ECDSA)5、 RSA-PSS数字签名算法 一、数字签名 1、 数字签名关键部分的描述 数字签名具有认证功能,下面...
  • RSA算法加解密实验

    2021-05-20 18:14:29
    一、RSA算法加解密简述在公开密钥密码...正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册...
  • DSA数字签名算法

    2021-04-19 19:51:32
    数字签名算法
  • 基于RSA签名算法进行数字签名算法,采用MD5哈希函数,实现对文件的数字签名。程序分为签名生成部分和验证部分。这是自己独立完成的一个实验,过程是输入文件路径,利用入参字符串和私钥进行签名,再输入私钥进行...
  • 数字签名原理及其应用

    万次阅读 多人点赞 2017-06-25 15:40:34
    签名的作用无非就是证明某个文件上的内容确实是我写的/我认同的,别人不能冒充我的签名(不可伪造),我也不能否认上面的签名是我的(不可抵赖)。 我们知道,手写签名之所以不能伪造,是因为每一个人的...而数字签名

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,379
精华内容 951
关键字:

基于rsa的数字签名实验