openssl md5 rsa 签名和签名验证

#include
#include
#include
#include
#include
#include
#include


#define PRIVATEKEY "rsa-private-key.pem"//我的私钥

#define PUBLICKEY "rsa-public-key.pem-2"//我的公钥


#define HISPUBLICKKEY "his.pem-2" //对方公钥

//撕咬签名 md5
int sign(char *in, int in_len, char *out, int *out_len) {
    unsigned char sign_value[1024]; //保存签名值的数组
    FILE *file = NULL;
    int sign_len = 0; //签名值长度
    EVP_MD_CTX mdctx; //摘要算法上下文变量
    RSA *rsa = NULL; //RSA结构体变量
    EVP_PKEY *evpKey = NULL; //EVP KEY结构体变量
    int i = 0;


    //撕咬
    if ((file = fopen(PRIVATEKEY, "r")) == NULL) {
        perror("open key file error");
        return -1;
    }


    if ((rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL)) == NULL) {
        ERR_print_errors_fp(stdout);
        return -1;
    }


    evpKey = EVP_PKEY_new(); //新建一个EVP_PKEY变量
    if (evpKey == NULL) {
        printf("EVP_PKEY_new err\n");
        RSA_free(rsa);
        return;
    }


    if (EVP_PKEY_set1_RSA(evpKey, rsa) != 1) //保存RSA结构体到EVP_PKEY结构体
    {
        printf("EVP_PKEY_set1_RSA err\n");
        RSA_free(rsa);
        EVP_PKEY_free(evpKey);
        return;
    }


    EVP_MD_CTX_init(&mdctx); //初始化摘要上下文
    if (!EVP_SignInit_ex(&mdctx, EVP_md5(), NULL)) //签名初始化,设置摘要算法,本例为MD5
    {
        printf("err\n");
        EVP_PKEY_free(evpKey);
        RSA_free(rsa);
        return;
    }
    if (!EVP_SignUpdate(&mdctx, in, in_len)) //计算签名(摘要)Update
    {
        printf("err\n");
        EVP_PKEY_free(evpKey);
        RSA_free(rsa);
        return;
    }
    if (!EVP_SignFinal(&mdctx, sign_value, &sign_len, evpKey)) //签名输出
    {
        printf("err\n");
        EVP_PKEY_free(evpKey);
        RSA_free(rsa);
        return;
    }
    //printf("消息\"%s\"的签名值是: \n", in);
    for (i = 0; i < sign_len; i++) {
        //if (i % 16 == 0)
        //   printf("\n%08xH: ", i);
        //printf("%d ", *(sign_value + i));
        *(out + i) = *(sign_value + i);
    }
    //printf("\n");
    //printf("签名是:out=%s\n", sign_value);
    EVP_MD_CTX_cleanup(&mdctx);
    *out_len = sign_len;
}


//验证签名
int varitySign(char *in, char *in2) {
   
    //验证签名
    EVP_MD_CTX mdctx; //摘要算法上下文变量
    FILE *file;
    RSA *rsa = NULL; //RSA结构体变量
    EVP_PKEY *evpKey = NULL; //EVP KEY结构体变量
    int i;
    //弓腰
    if ((file = fopen(HISPUBLICKKEY, "r")) == NULL) {
        perror("open key file error");
        return -1;
    }
    if ((rsa = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL)) == NULL) {
        ERR_print_errors_fp(stdout);
        return -1;
    }


    evpKey = EVP_PKEY_new(); //新建一个EVP_PKEY变量
    if (evpKey == NULL) {
        printf("EVP_PKEY_new err\n");
        RSA_free(rsa);
        return -1;
    }


    if (EVP_PKEY_set1_RSA(evpKey, rsa) != 1) //保存RSA结构体到EVP_PKEY结构体
    {
        printf("EVP_PKEY_set1_RSA err\n");
        RSA_free(rsa);
        EVP_PKEY_free(evpKey);
        return -1;
    }




    EVP_MD_CTX_init(&mdctx); //初始化摘要上下文
    if (!EVP_VerifyInit_ex(&mdctx, EVP_md5(), NULL)) //验证初始化,设置摘要算法,一定要和签名一致。
    {
        printf("EVP_VerifyInit_ex err\n");
        EVP_PKEY_free(evpKey);
        RSA_free(rsa);
        return -1;
    }
    if (!EVP_VerifyUpdate(&mdctx, in, in_len)) //验证签名(摘要)Update  //原文和原文的长度
    {
        printf("err\n");
        EVP_PKEY_free(evpKey);
        RSA_free(rsa);
        return -1;
    }
    if (!EVP_VerifyFinal(&mdctx, in2, in_len2, evpKey))//验证签名      //签名后的文,和签名后的长度
    {
        printf("verify err\n");


        ERR_load_ERR_strings();
        ERR_load_crypto_strings();

        unsigned long ulErr = ERR_get_error(); // 获取错误号
        char szErrMsg[1024] = {0};
        char *pTmp = NULL;
        pTmp = ERR_error_string(ulErr, szErrMsg); // 格式:error:errId:库:函数:原因

        printf("错误具体原因:%s\n", szErrMsg);
        EVP_PKEY_free(evpKey);
        RSA_free(rsa);
        return -1;
    } else {
        printf("验证签名正确.\n");
    }
    //释放内存
    EVP_PKEY_free(evpKey);
    RSA_free(rsa);
    EVP_MD_CTX_cleanup(&mdctx);
    return 0;
}


ps. EVP_SignFinal()函数默认才用了pkcs1的填充模式
不知道有没有人可以修改这个填充模式,知道的请留言

你可能感兴趣的:(openssl md5 rsa 签名和签名验证)