zoukankan      html  css  js  c++  java
  • 08.公钥算法(数字签名和RSA)

    Diffie-Hellman (DH):使用在密钥协议
    DSA (Digital Signature Algorithm),:使用在数字签名
    RSA ( Rivest, Shamir, and Adleman):使用在密钥协商
     
    8.2 Diffie-Hellman
    Diffie-Hellman算法是有史以来发明的第一个公钥算法。 Whitfield Diffie和Martin Hellman于1976年推出,它是一个简单的算法,允许双方就使用不安全通道的密钥达成一致。 换句话说,它允许创建一个共享的秘密。 这个过程有时被称为密钥交换,但是在Diffie-Hellman中,更准确地称为密钥交换。
     
    Diffie-Hellman的主要用途是共享秘密协商。 算法本身可以提供认证,但OpenSSL不包含任何使用这些特性的高级接口,所以如果需要的话,它们必须由应用程序来实现。 出于这个原因,大多数使用这种算法的OpenSSL应用程序也将使用另一个进行身份验证。 就我们的目的而言,我们将主要从密钥协议的角度来讨论Diffie-Hellman。 有兴趣的读者可以参考RFC 2631了解更多关于使用它进行认证的信息。
     
    8.2.1 The Basics
    在openssl/dh.h
    typedef struct dh_st
    {
    BIGNUM *p; 共享公共值
    BIGNUM *g;共享公共值
    BIGNUM *pub_key;
    BIGNUM *priv_key;
    } DH;
     
    8.2.2 Generating and Exchanging Parameters
     
    函数
     
    DH *DH_generate_parameters(int prime_len, int generator,
    void (*callback)(int, int, void *), void
    *cb_arg);
    功能
    创建DH对象
    参数
     
     
    prime_len
    要生成的素数的大小,以位表示。
     
    generator
    用于g的值。
     
    callback
    指向在素数生成过程中将被调用的函数的指针,用于报告素数生成的状态。
     
    cb_arg
    指向特定于应用程序的数据的指针。
     
     
    函数
     
    int DH_check(DH *dh, int *codes);
    功能
    DH检测对象
    参数
     
    dh
    DH对象
    codes
     
    DH_CHECK_P_NOT_PRIME
     
    DH_CHECK_P_NOT_SAFE_PRIME
     
    DH_NOT_SUITABLE_GENERATOR
     
    DH_UNABLE_TO_CHECK_GENERATOR
     
     
    8.2.3 Computing Shared Secrets
     
    函数
     
    int DH_compute_key(unsigned char *secret,
    BIGNUM *pub_key, DH *dh);
     
    功能
    单独使用生成函数可能是危险的。
    虽然生成函数确实对生成的素数进行了有效性检查,
    但它可能会生成不适合与算法一起使用的素数。
    参数
     
     
    secret
     
    一个将被用来保存共享密钥的缓冲区
     
    pub_key
    一对公钥
     
     
    dh
    包含参数和调用者的私钥的DH对象
     
     
    8.3 Digital Signature Algorithm (DSA)
    DSA算法由美国国家标准与测试研究院(NIST)和国家安全局(NSA)开发。 这是1991年首次提出的,引起了很大的争议。 最后,在1994年,它成为一个标准。 顾名思义,DSA算法对计算数字签名非常有用,但这是唯一可以使用的方法。 它不能提供没有扩展的密钥协议或加密。
     
    8.3.1 The Basics
    openssl/dsa.h
    typedef struct dsa_st
    {
    BIGNUM *p;
    BIGNUM *q;
    BIGNUM *g;
    BIGNUM *pub_key;
    BIGNUM *priv_key;
    } DSA;
     
     
    8.3.2 Generating Parameters and Keys
     
    函数
     
    DSA * DSA_generate_parameters(int bits, unsigned char *seed, int
    seed_len,
    int *counter_ret, unsigned long *h_ret,
    void (*callback)(int, int, void *),
    功能
    生成DSA参数的接口类似于生成DiffieHellman参数的接口。
    参数
     
     
    bits
    要生成的素数的大小,以位表示。
     
    seed
    一个可选的包含数据的缓冲区,为函数提供一个开始查找的起点
    为素数
    seed_len
    种子缓冲区中包含的字节数。
     
    counter_ret
    一个可选参数,将接收函数经过的迭代次数,以找到满足p和q要求的素数。
     
    h_ret
    一个可选参数,将接收函数经过的迭代次数,以找到h的值,这是用来计算g的随机数。
     
    callback
    指向在素数生成过程中将被调用的函数的指针,用于报告素数生成的状态。
     
    cb_arg
    指向特定于应用程序的数据的指针。
     
     
    8.3.3 Signing and Verifying
    数字签名必须通过将要签名的数据的消息摘要进行计算。这不是巧合。 实际上,DSA算法不能用于计算大于其q参数的数据的签名。
     
    函数
     
    int DSA_sign_setup(DSA *dsa, BN_CTX *ctx,
    BIGNUM **kinvp, BIGNUM **rp);
     
    功能
    数字签名必须通过将要签名的数据的消息摘要进行计算。
    参数
     
    dsa
    包含将用于签名的参数和私钥的DSA对象。
     
    ctx
    将在预计算中使用的可选BIGNUM上下文。
     
    kinvp
    接收一个动态分配的BIGNUM,它将保存预先计算的kinv值。
     
    rp
    接收一个动态分配的BIGNUM,它将保存预先计算的r值。
     
     
    函数
     
    int DSA_sign(int type, const unsigned char *dgst, int len,
    unsigned char *sigret, unsigned int *siglen, DSA *dsa);
    功能
    提供函数DSA_sign用于使用DSA算法实际计算数字签名。
    参数
     
     
    type
    忽略DSA签名。
    dgst
    将被签名的数据的缓冲区,应始终是SHA1哈希。
     
     
    len
     
    数据缓冲区中用于签名的字节数。
    sigret
    一个将接收签名的缓冲区。
     
    siglen
    接收填充签名的sigret缓冲区的字节数。
     
    dsa
    用于签署数据缓冲区内容的DSA对象。
     
     
    函数
     
    int DSA_verify(int type, const unsigned char *dgst, int len,
    unsigned char *sigbuf, int siglen, DSA *dsa);
    功能
    函数DSA_verify用于验证签名,与用于创建签名的函数类似。
    参数
     
     
    type
    忽略DSA验证。
    dgst
    将被签名的数据的缓冲区,应始终是SHA1哈希。
     
     
    len
     
    数据缓冲区中用于签名的字节数。
    sigbuf
    将被验证的签名
     
    siglen
    接收填充签名的缓冲区的sigbuf
    字节数。
     
    dsa
    用于验证签名的DSA对象。
     
     
    8.4 RSA
    RSA发明于1977年,是第一个能够对数据进行数字签名和加密的公钥算法。 尽管它已经获得专利,但事实上已经成为公钥算法。 几乎所有在其产品中使用公钥密码术的公司都获得了该技术的许可。 该专利仅在美国获得专利,专利于2000年9月20日到期。
     
    8.4.1 The Basics
    typedef struct rsa_st
    {
    BIGNUM *p;
    BIGNUM *q;
    BIGNUM *n;
    BIGNUM *e;(e使用(p-1)(q-1))
    BIGNUM *d; (使用e,p和q计算)
    } RSA
     
    8.4.2 Generating Keys
    函数
     
    RSA *RSA_generate_key(int num, unsigned long e,
    void (*callback)(int, int, void *), void
    *cb_arg);
     
    功能
    RSA算法不需要参数来生成密钥,这使得密钥生成变得非常简单。
    参数
     
    num
    指定公共模数中的位数。
    e
    用于公共指数的值。
    callback
    指向在素数生成过程中将被调用的函数的指针,用于报告素数生成的状态。
     
    cb_arg
     
    指向特定于应用程序的数据的指针。
     
     
    8.4.3 Data Encryption, Key Agreement, and Key Transport
    现在我们已经探索了关键的设置,我们可以看看使用这些关键字的不同方法。 RSA算法允许保密,因为它可以加密数据。 用公钥加密的数据只能由拥有相应私钥的实体解密。
     
    函数
     
    int RSA_public_encrypt(int flen, unsigned char *from, unsigned char
    *to,RSA *rsa, int padding);
     
     
    功能
    RSA公钥加密数据
    参数
     
    flen
    指定要加密的缓冲区中的字节数。
    from
    包含要加密的数据的缓冲区。
    to
    将用于保存加密数据的缓冲区。
     
    rsa
     
    包含用于执行加密的公钥的RSA对象。
     
    padding
     
    指定在需要填充时应使用OpenSSL支持哪些内置填充类型。
     
     
    函数
    int RSA_private_decrypt(int flen, unsigned char *from, unsigned char
    *to,RSA *rsa, int padding);
     
    功能
    RSA私钥解密数据
    参数
     
    flen
    指定要加密的缓冲区中的字节数。
    from
    包含要加密的数据的缓冲区。
    to
    将用于保存加密数据的缓冲区。
     
    rsa
     
    包含用于执行加密的公钥的RSA对象。
     
    padding
     
    指定在需要填充时应使用OpenSSL支持哪些内置填充类型。
     
    padding参数
    意义
     
    RSA_PKCS1_PADDING
     
    如果使用这种填充类型,则要加密的数据长度必须小于
    RSA_size(RSA)-11。
     
    RSA_PKCS1_OAEP_PADDING
     
     
    If this type of padding is used, the length of the data to be encrypted must be smaller than
    RSA_size(rsa)-41.
     
     
    RSA_SSLV23_PADDING
     
     
    This type of padding is an SSL-specific modification to the RSA_PKCS1_PADDING type.
     
     
    RSA_NO_PADDING
     
     
    This disables automatic padding by the encryption function, and assumes that the caller
    will perform the padding.
     
     
    8.4.4 Signing and Verifying
    函数
     
    int RSA_sign(int type, unsigned char *m, unsigned int m_len,
    unsigned char *sigret, unsigned int *siglen, RSA *rsa)
     
    功能
    RSA签名
    参数
     
     
    type
     
    消息摘要算法,用于获取要签名的数据的加密哈希。
     
    m
     
    包含要签名的数据的缓冲区。
     
    m_len
     
    将在签名中考虑的数据缓冲区中的字节数。
     
    sigret
     
    签名数据
     
    siglen
     
    签名长度
     
    rsa
     
    包含用于签署数据的私钥的RSA对象
     
     
    函数
     
    int RSA_verify(int type, unsigned char *m, unsigned int m_len,
    unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
     
    功能
    RSA验签
    参数
     
     
    type
     
    消息摘要算法,用于获取要签名的数据的加密哈希。
     
    m
     
    包含要签名的数据的缓冲区。
     
    m_len
     
    将在签名中考虑的数据缓冲区中的字节数。
     
    sigbuf
     
    签名数据
     
    siglen
     
    签名长度
     
    rsa
     
    包含用于签署数据的私钥的RSA对象
     
     
    8.4.5 Practical Applications
     
    One-way authenticating key transport
     
    客户端选择一个随机的会话密钥,用服务器的公钥加密它
    将加密的数据发送到服务器。
     
    Two-way authenticating key transport
     
    本质上,客户端采取与上述协议相同的步骤,但在发送之前
    消息到服务器,它签署消息。
     
    Two-way authenticating key agreement
     
    客户端和服务器都选择随机数据作为密钥资料,用对方的公钥加密,用自己的私钥签名,然后发送
    数据给对方。
     
    8.5 The EVP Public Key Interface
     
    EVP_PKEY_assign_DSA
     
    EVP_PKEY_assign_RSA
     
     
     
     
     
    EVP_PKEY_set1_DSA
     
    EVP_PKEY_set1_RSA
     
     
     
     
    The functions' signatures are
    identical to EVP_PKEY_assign_DSA and EVP_PKEY_assign_RSA.
     
     
    EVP_PKEY_get1_DSA
     
    EVP_PKEY_get1_RSA
     
     
     
     
     
    DSA_free
     
    RSA_free
     
     
     
     
     
     
    8.5.1 Signing and Verifying
    EVP接口提供了一种使用DSA或DSA创建和验证数字签名的方法RSA密钥。
    函数
     
    int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type);
     
    功能
    初始化一个EVP_MD_CTX对象
    参数
     
     
    ctx
     
     
    EVP_MD_CTX 初始化
     
    type
     
    用于计算散列的消息摘要,实际上是用符号来代替数据本身。
     
     
     
    int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *buf, unsigned int
    len);
     
    一旦上下文已经被初始化,要被签名的数据必须被输入。
     
    int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *sig, unsigned int
    *siglen,EVP_PKEY *pkey);
     
    对于初始化的上下文,应根据需要多次调用EVP_VerifyUpdate
    为上下文提供所有据称用于创建签名的数据。
     
    int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *buf, unsigned int
    len);
     
    一旦所有数据已经与EVP_VerifyUpdate一起传递到上下文中,则必须调用EVP_VerifyFinal来执行签名的实际验证。...
     
    int EVP_VerifyFinal(EVP_MD_CTX *ctx, unsigned char *sigbuf,
    unsigned int siglen, EVP_PKEY *pkey);
    ctx
     
    一旦所有数据已经与EVP_VerifyUpdate一起传递到上下文中,则必须调用EVP_VerifyFinal来执行签名的实际验证。...
     
     
    8.5.2 Encrypting and Decrypting
    EVP接口还提供使用RSA密钥封装数据的接口。
    函数
     
    int EVP_SealInit(EVP_CIPHER_CTX *ctx, EVP_CIPHER *type,
    unsigned char **ek, int *ekl, unsigned char *iv,
    EVP_PKEY **pubk, int npubk);
     
    功能
    上下文对象的初始化通过调用EVP_SealInit来实现。
    参数
     
    ctx
     
    type
    用于执行实际加密的对称密码。
    ek
    一组缓冲区。 必须为数组分配与为指定加密的公钥一样多的元素。
    ekl
     
    一个数组,将接收每个公钥的实际加密密钥长度。
    iv
    包含要使用的初始化向量的缓冲区。
    pubk
    用于加密随机生成的会话密钥的公钥数组。
    npubk
    公钥密钥数组
     
    函数
    功能
     
    EVP_SealUpdate
     
     
     
    EVP_SealFinal
     
     
     
    EVP_OpenInit
     
    函数EVP_OpenInit初始化解密的上下文。
     
    EVP_OpenUpdate
     
    初始化上下文解密会话密钥并准备解密数据的上下文
    使用指定的对称密码。
     
    EVP_OpenFinal
     
    一旦所有要解密的数据都被送入EVP_OpenUpdate,就应该调用EVP_OpenFinal来完成这个工作。
     
    8.6 Encoding and Decoding Objects
    8.6.1 Writing and Reading DER-Encoded Objects
    int i2d_OBJNAME(OBJTYPE *obj, unsigned char **pp);
    OBJTYPE *d2i_OBJNAME(OBJTYPE **obj, unsigned char **pp, long length);
     
     
    Table 8-1. Functions for reading and writing DER encodings of public key objects
    Type of object
    OpenSSL
    object type
    Function to write the DER
    representation
    Function to read the DER
    representation
    Diffie-Hellman
    parameters
    DH
    i2d_DHparams
    d2i_DHParams
    DSA parameters
    DSA
    i2d_DSAparams
    d2i_DSAparams
    DSA public key
    DSA
    i2d_DSAPublicKey
    d2i_DSAPublicKey
    DSA private key
    DSA
    i2d_DSAPrivateKey
    d2i_DSAPrivateKey
    RSA public key
    RSA
    i2d_RSAPublicKey
    d2i_RSAPublicKey
    RSA private key
    RSA
    i2d_RSAPrivateKey
    d2i_RSAPrivateKey
    EVP_PKEY
    public key
    EVP_PKEY
    i2d_PublicKey
    d2i_PublicKey
    EVP_PKEY
    private key
    EVP_PKEY
    i2d_PrivateKey
    d2i_PrivateKey
    EVP_PKEY
    private key
    EVP_PKEY
    N/A
    d2i_AutoPrivateKey
     
    操作步骤:
    a.i2d_PublicKey 或 d2i_PublicKey
    b.d2i_AutoPrivateKey
    c.d2i_PrivateKey_bio或d2i_PrivateKey_fp
    d.d2i_AUtoPrivateKey_bio或d2i_AutoPrivateKey_fp
     
     
    8.6.2 Writing and Reading PEM-Encoded Objects
    函数
     
    int PEM_write_OBJNAME(FILE *fp, OBJTYPE *obj, const EVP_CIPHER *enc,
    unsigned char *kstr, int klen, pem_password_cb
    callback,void *cb_arg);
     
    功能
    编写私钥的函数有点复杂,因为PEM格式允许在编码和写出之前对它们进行加密。
    参数
     
     
    fp
     
    文件描述符
     
    obj
     
    用于执行实际加密的对称密码。
     
    enc
     
    用于加密密钥数据的可选密码。
     
    kstr
     
    包含用于加密的密码或密码的可选缓冲区。
     
    klen
     
    指定kstr缓冲区中包含的字节数。
     
    callback
     
    获取用于加密密钥数据的密码或密码的回调函数。
     
    cb_arg
     
     
     
    函数
     
    typedef int (*pem_password_cb)(char *buf, int len, int rwflag, void
    *cb_arg);
    功能
    用于写入BIO对象的函数具有相同的签名,不同之处在于FILE对象被替换为BIO对象。
    参数
     
    buf
    密码或密码将被写入的缓冲区。
     
    len
     
    密码缓冲区的大小
     
     
    rwflag
     
     
    指示是使用密码还是密码短语来加密或解密PEM数据。 在编写PEM数据时,这个参数将是非零的。 在阅读PEM数据时,这个参数将是零。
     
    cb_arg
     
     
     
     
     
    函数
     
    OBJTYPE *PEM_read_OBJNAME(FILE *fp, OBJTYPE **obj, pem_password_cb
    callback,void *cb_arg);
     
    功能
    读公钥,私钥和参数的功能都有相同的签名。
    参数
     
     
    fp
     
     
     
     
    obj
     
     
    要用读取的数据填充的对象。
     
     
    callback
     
     
     
    获取密码或密码(如果需要)的回调函数。
     
    cb_arg
     
     
     
     
     
    Table 8-2. Functions for reading and writing PEM encodings of public key objects
    Type of
    object
    OpenSSL
    object
    type
    Function to write the PEM
    representation
    Function to read the PEM
    representation
    Diffie
    Hellman
    parameters
    DH
    PEM_write_DHparams
    PEM_write_bio_DHparams
    PEM_read_DHparams
    PEM_read_bio_DHparams
    DSA
    parameters
    DSA
    PEM_write_DSAparams
    PEM_write_bio_DSAparams
    PEM_read_DSAparams
    PEM_read_bio_DSAparams
    DSA
    public key
    DSA
    PEM_write_DSA_PUBKEY
    PEM_write_bio_DSA_PUBKEY
    PEM_read_DSA_PUBKEY
    PEM_read_bio_DSA_PUBKEY
    DSA
    private key
    DSA
    PEM_write_DSAPrivateKey
    PEM_write_bio_DSAPrivateKey
    PEM_read_DSAPrivateKey
    PEM_read_bio_DSAPrivateKey
    RSA
    public key
    RSA
    PEM_write_RSA_PUBKEY
    PEM_write_bio_RSA_PUBKEY
    PEM_read_RSA_PUBKEY
    PEM_read_bio_RSA_PUBKEY
    RSA
    private key
    RSA
    PEM_write_RSAPrivateKey
    PEM_write_bio_RSAPrivateKey
    PEM_read_RSAPrivateKey
    PEM_read_bio_RSAPrivateKey
    EVP_PKEY
    public key
    EVP_PKEY
    PEM_write_PUBKEY
    PEM_write_bio_PUBKEY
    PEM_read_PUBKEY
    PEM_read_bio_PUBKEY
    EVP_PKEY
    private key
    EVP_PKEY
    PEM_write_PrivateKey
    PEM_write_bio_PrivateKey
    PEM_read_PrivateKey
    PEM_read_bio_PrivateKey
     
     
     
     
  • 相关阅读:
    基本类型与引用类型
    局部变量与实例变量
    语句块
    i++与++i
    JAVA基本概念
    网线8根线的排列方式
    Docker容器常用命令
    内存cache使用的场景
    Python爬虫:Xpath语法笔记
    python实现简单的聊天
  • 原文地址:https://www.cnblogs.com/aixiaoxiaoyu/p/8195626.html
Copyright © 2011-2022 走看看