首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HMAC SHA256在Java上签名,在C++私钥上验证

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

Stack Overflow用户
提问于 2020-08-26 22:17:11
回答 2查看 1.7K关注 0票数 1

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

在Java中,我使用

代码语言:javascript
复制
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++上,要验证我真的尝试了不同的代码,例如:

代码语言:javascript
复制
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(), NULL, pkey);
    if (rc != 1) {
        printf("EVP_DigestSignInit failed, error 0x%lx\n", ERR_get_error());
        goto err;
    }

    rc = EVP_DigestSignUpdate(ctx, msg, mlen);
    if (rc != 1) {
        printf("EVP_DigestSignUpdate failed, error 0x%lx\n", ERR_get_error());
        goto err;
    }

    size = sizeof(buff);
    rc = EVP_DigestSignFinal(ctx, buff, &size);
    if (rc != 1) {
        printf("EVP_DigestSignFinal failed, error 0x%lx\n", ERR_get_error());
        goto err;
    }

    result = (vlen == size) && (CRYPTO_memcmp(val, buff, 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, 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

任何其他的例子都是假的。我不知道是什么问题,请帮帮忙!谢谢!

附注:私钥:

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/r4DHuklshDoR3xAYOSZ6/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 grwl/nBjXTTk3PVv+OmWGFRFE0BGuf7oYEuoX86732gAtLkImqLNeNNhgUVVhFiD UOOyWjybxH9UiH28eYBZqzJlyY9D3xeC3ZUkTvfJOURK5t8vagS/t8Vu3xsMHWQ7 DwIDAQAB

信息: 12105333071

来自Java的信号:XChhsTE+Yr4wkiibvTFiLTMhJ8tLqYo7WQs/VtNkE=

EN

回答 2

Stack Overflow用户

发布于 2020-08-27 16:01:38

仅仅使用HMACSHA256并不等于私钥/公钥签名。HMACSHA256的全名是“基于哈希的消息身份验证代码”,您可以用相同的“密钥”来“签名”和“验证”,这是一个字节数组,与私钥或公钥无关。

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

我安装了两个小程序来演示它是如何工作的。对于Java,我正在使用您的代码,除了使用Bouncy城堡作为“本地”Java应该有这个内置。同时,我也忽略了ApacheBase64转换,因为它也是内置的。C#-部件是同一个程序,但是有一个“验证”输出。

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

Java的结果-代码:

代码语言:javascript
复制
HMAC SHA256 sign on Java, Verify on C++ private-public keys
hmacSha256 (Base64): /1qkanJi8onWOxVe02MO/Wf1922aKzSTSfJk6E7o1x0=

C#的结果-代码:

代码语言:javascript
复制
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-代码:

代码语言:javascript
复制
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, InvalidKeyException, 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#-代码:

代码语言:javascript
复制
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);
        }
}
票数 1
EN

Stack Overflow用户

发布于 2021-01-13 14:35:09

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

代码语言:javascript
复制
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)

}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63606485

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档