HMAC SHA256在Java上签名,在C ++私钥-公钥上验证

如何解决HMAC SHA256在Java上签名,在C ++私钥-公钥上验证

我尝试使用私钥通过Java对某些数据进行签名,然后使用公钥通过C ++对其进行验证。我使用Java作为客户端,使用C ++作为服务器。 Java在Windows上运行,C ++在Ubuntu上运行

在Java中我使用

key = "MIIEowIBAAKCAQ......s8mFoA2"; //private key
        
        
        byte[] b1 = Base64.decodeBase64(key);

this.Sign =  hmacSha256Base64("test",b1);

/**************/

public static String hmacSha256Base64(String message,byte[] secretKey) throws
      NoSuchAlgorithmException,InvalidKeyException,UnsupportedEncodingException,NoSuchProviderException {
       
       Mac hmacSha256;
       try {
        hmacSha256 = Mac.getInstance("HmacSHA256","BC");
       } catch (NoSuchAlgorithmException nsae) {
        hmacSha256 = Mac.getInstance("HMAC-SHA-256");
       }
       SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey,"HmacSHA256");
       hmacSha256.init(secretKeySpec);
       // Build and return signature
       return Base64.encodeBase64String(hmacSha256.doFinal(message.getBytes("UTF-8")));
      }

在C ++上,要验证我是否真正尝试其他代码,例如:

int verify_it(const unsigned char *msg,size_t mlen,const unsigned char *val,size_t vlen,EVP_PKEY *pkey)
{
    /* Returned to caller */
    int result = 0;
    EVP_MD_CTX* ctx = NULL;
    unsigned char buff[EVP_MAX_MD_SIZE];
    size_t size;
    int rc;

    if (!msg || !mlen || !val || !vlen || !pkey)
        return 0;

    ctx = EVP_MD_CTX_new();
    if (ctx == NULL) {
        printf("EVP_MD_CTX_create failed,error 0x%lx\n",ERR_get_error());
        goto err;
    }

    rc = EVP_DigestSignInit(ctx,NULL,EVP_sha256(),pkey);
    if (rc != 1) {
        printf("EVP_DigestSignInit failed,ERR_get_error());
        goto err;
    }

    rc = EVP_DigestSignUpdate(ctx,msg,mlen);
    if (rc != 1) {
        printf("EVP_DigestSignUpdate failed,ERR_get_error());
        goto err;
    }

    size = sizeof(buff);
    rc = EVP_DigestSignFinal(ctx,buff,&size);
    if (rc != 1) {
        printf("EVP_DigestSignFinal failed,ERR_get_error());
        goto err;
    }

    result = (vlen == size) && (CRYPTO_memcmp(val,size) == 0);
err:
    EVP_MD_CTX_free(ctx);
    return result;
} 

RSA* createPublicRSA(std::string TermId,bool is_local) {
    RSA *rsa = NULL;
    BIO *keybio;

    FILE * fp = fopen((SettingsConfig["UserKeys"] + "user_public/" + TermId).c_str(),"rb");

    if (fp != 0)
    {
        rsa = PEM_read_RSA_PUBKEY(fp,&rsa,NULL);
        fclose(fp);
    }
    
    return rsa;
}

size_t calcDecodeLength(const char* b64input) {
    size_t len = strlen(b64input),padding = 0;

    if (b64input[len - 1] == '=' && b64input[len - 2] == '=') //last two chars are =
        padding = 2;
    else if (b64input[len - 1] == '=') //last char is =
        padding = 1;
    return (len * 3) / 4 - padding;
}

void Base64Decode(const char* b64message,unsigned char** buffer,size_t* length) {
    BIO *bio,*b64;

    int decodeLen = calcDecodeLength(b64message);
    *buffer = (unsigned char*)malloc(decodeLen + 1);
    (*buffer)[decodeLen] = '\0';

    bio = BIO_new_mem_buf(b64message,-1);
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_push(b64,bio);

    *length = BIO_read(bio,*buffer,strlen(b64message));
    BIO_free_all(bio);
}       
std::string test = "XChhsTE....NkE="; //Sign from Java      
    std::string msg = "test";
    
    RSA* publicRSA = createPublicRSA("#1.pem",false); //public key

    EVP_PKEY* pubKey = EVP_PKEY_new();
    EVP_PKEY_assign_RSA(pubKey,publicRSA);


    unsigned char* encMessage;
    size_t encMessageLength;

    Base64Decode(test.c_str(),&encMessage,&encMessageLength);

    int result_sign = verify_it((unsigned char*)msg.c_str(),msg.length(),encMessage,encMessageLength,pubKey);

    std::cout << std::to_string(result_sign) << std::endl; //return 0

其他任何示例都返回false。不知道是什么问题,请帮忙!谢谢!

p.s。私钥:

MIIEowIBAAKCAQEAra2jau89VIfcunyOth5O08EZqFVSgVzk9Tv0ELG + zH89D / s0DMLSkACXUSYq2EFRXUS05doajB55ZVoD2qYiUjJPrZDnPS + H3F / 9tqRf + o2bbb4DWRd9MJbMt2E2Q8auIN3M49XvlQnZ2 + dSvplLepYv6H + fbILBsYfQUxh4RX5B + qvk1JdbMh1rhgLV6y9 / lYkF3UlL8W5EBA2A1YQvgrwl / nBjXTTk3PVv + OmWGFRFE0BGuf7oYEuoX86732gAtLkImqLNeNNhgUVVhFiDUOOyWjybxH9UiH28eYBZqzJlyY9D3xeC3ZUkTvfJOURK5t8vagS / t8Vu3xsMHWQ7DwIDAQABAoIBAHbNlkGp0Uwne6fdWEnfxZA4QPLTGpL / FmdiUXux + pAsYXqzHVG1Ww / CN7 / 82cYAOEYSn6OzZAGBPw1DW + uPRV7wp2xU + Ljz8H69g7ISEs1zXGTfW67v0GUSYor2ZoZKPAajcmpPh4ltqacxP3q9pdH / NlpWIpm5gAGOo8STsoHl0PItHpxYbWXRylzWIgysalYPRERicT / ibQlJ4w8jhdk1lqYZAyEg2trJXDXxiNGx19OxEfRoqDVumK + W7Pn38ye9zgjuR8TYRAMPJ1WcQ9HZPLZKbVBvjztLSvUk / Q + Z8PoomIN9s + Ggev1y6 + ccOiRWpPQLp45483k5fHHXTpECgYEA4KJsRwGTw3yomIAN + k0eFSL / + + bJJBimQXjRcc0qw + NbeLoytfVrnSCBD85QYamcB8tMg CvcCdJve46ByOsmYN6jXLdUmai4Nt / kJfUU6bWpPwBdtUOGKb9mYH4xLGnnJqyUhCJ + vhY6WrOUBXu1KfkQZUEc / R / EWyEo09UNsCsCgYEAxe3IQ2tXI1zJ91xu0R309eToH / ZhfVSKR6UBoCKptEweBBPlCj8tQcKS6Ao9Oyk28rSoAYM8thy1V9 + XItku97L + fP1JSZMkGq3g / r4DH uklshDoR3xAYOSZ6 / 89BxsV0O9a92bb0CV472wM7HHH0KAMtODwRqw8IpC5qlMHiq0CgYEAxYTMJJt0bF3 + eSmQINkSbI97 + PkVUL / XW5469H1mo0d70f6Mxj7aQwdr + I / t8BFnGzceNFmMf25z7HbgE + UAuAjMKEhjsUEzybyQhfe8TcwYZ3dQ7oPTQn4z7QDJCD6Oq + jwJkeWnlo5MWvZ6gBeyetgyUe50R6Z72920NzzzkUCgYBeY / V7YXde3 + NZWfVnONgXZCDnDUKU2HpRjHln + T / foeU2oJ478sEMeVRB4JAu5IrV2B2 / Cu0rFCnPTEvxTI2 / htcimFAZDFjNeFqyYb9vQFS / xJxhavnwu1REXaam + T2 + lEdXcPAnJZe05lyLbf + SmKE2qYcszPqoqUhB1 / LiyQKBgGDXVyw05oSvR9GGKfMKIghRimeF97 + EZhS718zcuDqXJ8Qmn + S + qrrwvn1X7TZbZ3bnM6JSnC5FcgLLVTWulLShjIo2ctsqaZUPnUJTBPoCJMkmGCR8H6XaVuFlfElT / jXglqwS + UkMMM2WPkDubnLzuTuslH1DJnrBBs8mFoA2

公钥:

-----公钥-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAra2jau89VIfcunyOth5O 08EZqFVSgVzk9Tv0ELG + zH89D / s0DMLSkACXUSYq2EFRXUS05doajB55ZVoD2qYi UjJPrZDnPS + H3f / 9tqRf + o2bbb4DWRd9MJbMt2E2Q8auIN3M49XvlQnZ2 + dSvplL epYv6H + fbILBsYfQUxh4RX5B + qvk1JdbMh1rhgLV6y9 / lYkF3UlL8W5EBA2A1YQv 抓取/ nBjXTTk3PVv + OmWGFRFE0BGuf7oYEuoX86732gAtLkImqLNeNNhgUVVhFiD UOOyWjybxH9UiH28eYBZqzJlyY9D3xeC3ZUkTvfJOURK5t8vagS / t8Vu3xsMHWQ7 迪达卡 -----结束公钥-----

消息:12105333071

来自Java的签名:XChhsTE + Yr4wkiibvTFiLTMhJ8tLqYo7WQs /// VtNkE =

解决方法

仅使用HMACSHA256与私钥/公钥签名不同。 HMACSHA256的全名是“基于哈希的消息身份验证代码”,您可以使用相同的“密钥”对它进行“签名”和“验证”,该“密钥”只是字节数组,与私钥或公钥无关。

您当然可以将私钥/公钥的编码字节作为输入,但是这样做时(我建议这样做) 您需要将相同密钥传递给验证部分。

我设置了两个小程序来演示其工作原理。对于Java,我使用您的代码,除了将Bouncy Castle用作“本地” Java外 应该有这个内置。同样,我也没有内置apache-Base64-conversion。 C#部分是同一程序,但是具有“验证”输出。

两个代码示例都没有任何特殊处理,仅用于教育目的。

Java代码的结果

HMAC SHA256 sign on Java,Verify on C++ private-public keys
hmacSha256 (Base64): /1qkanJi8onWOxVe02MO/Wf1922aKzSTSfJk6E7o1x0=

C#代码的结果

HMAC SHA256 sign on Java,Verify on C++ private-public keys
HMACSHA256 in C#: /1qkanJi8onWOxVe02MO/Wf1922aKzSTSfJk6E7o1x0=
HMACSHA256 Java : /1qkanJi8onWOxVe02MO/Wf1922aKzSTSfJk6E7o1x0=
Hashes are equal: True

Java代码:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class Org {
    public static void main(String[] args) throws NoSuchAlgorithmException,InvalidKeyException,UnsupportedEncodingException {
        System.out.println("HMAC SHA256 sign on Java,Verify on C++ private-public keys");
        String message = "12105333071";
        String key = "12345678901234567";
        String result = hmacSha256Base64(message,key.getBytes(StandardCharsets.UTF_8));
        System.out.println("hmacSha256 (Base64): " + result);
    }
    public static String hmacSha256Base64(String message,byte[] secretKey) throws
            NoSuchAlgorithmException,UnsupportedEncodingException {

        Mac hmacSha256;
        try {
            hmacSha256 = Mac.getInstance("HmacSHA256");
        } catch (NoSuchAlgorithmException nsae) {
            hmacSha256 = Mac.getInstance("HMAC-SHA-256");
        }
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey,"HmacSHA256");
        hmacSha256.init(secretKeySpec);
        // Build and return signature
        return Base64.getEncoder().encodeToString(hmacSha256.doFinal(message.getBytes("UTF-8")));
    }
}

C#代码:

using System;
using System.Text;
using System.Security.Cryptography;

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("HMAC SHA256 sign on Java,Verify on C++ private-public keys");
            string message = "12105333071";
            string key = "12345678901234567";
            string expectedHashBase64 = "/1qkanJi8onWOxVe02MO/Wf1922aKzSTSfJk6E7o1x0="; // from Java
            // generate HMACSHA256
            string hmacSha256DigestBase64 = HmacSha256DigestBase64(key,message);
            Console.WriteLine("HMACSHA256 in C#: " + hmacSha256DigestBase64);
            Console.WriteLine("HMACSHA256 Java : " + expectedHashBase64);
            Console.WriteLine("Hashes are equal: " + hmacSha256DigestBase64.Equals(expectedHashBase64,StringComparison.OrdinalIgnoreCase));
            //Console.ReadLine();
        }
    
        private static string HmacSha256DigestBase64(string secret,string message)
        {
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] keyBytes = encoding.GetBytes(secret);
            byte[] messageBytes = encoding.GetBytes(message);
            System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);
            byte[] bytes = cryptographer.ComputeHash(messageBytes);
        return Convert.ToBase64String(bytes);
        }
}
,

完成集合的 Golang 代码(经过测试以产生与 Michael Fehr 的 java 代码形式完全相同的结果:

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "fmt"
    b64 "encoding/base64"
)

func main() {

    secret := "12345678901234567"
    data := "12105333071"
    fmt.Printf("Secret: %s Data: %s\n",secret,data)

    // Create a new HMAC by defining the hash type and the key (as byte array)
    h := hmac.New(sha256.New,[]byte(secret))

    // Write Data to it
    h.Write([]byte(data))

    // Get result and base64 encode the string
    sha := b64.StdEncoding.EncodeToString(h.Sum(nil))

    fmt.Println("Result: " + sha)

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-