首页 > 解决方案 > 如何将带有 ASN1 和 SHA256 的数字签名从 C# 转换为 Java

问题描述

昨天,我决定做数字签名,然后我找到了 c# 示例代码。我试图将其转换为 java,但由于我的知识有限,它还没有完成。

这是 C# 代码

public string Sign(string payload, string privateKey)
{
List<string> segments = new List<string>();
var header = new { alg = "RS256" };

DateTime issued = DateTime.Now;
DateTime expire = DateTime.Now.AddHours(10);    

byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
byte[] payloadBytes = Encoding.UTF8.GetBytes(payload);

segments.Add(Base64UrlEncode(headerBytes));
segments.Add(Base64UrlEncode(payloadBytes));

string stringToSign = string.Join(".", segments.ToArray());

byte[] bytesToSign = Encoding.UTF8.GetBytes(stringToSign);

byte[] keyBytes = Convert.FromBase64String(privateKey);

var privKeyObj = Asn1Object.FromByteArray(keyBytes);
var privStruct = RsaPrivateKeyStructure.GetInstance((Asn1Sequence)privKeyObj);

ISigner sig = SignerUtilities.GetSigner("SHA256withRSA");

sig.Init(true, new RsaKeyParameters(true, privStruct.Modulus, privStruct.PrivateExponent));

sig.BlockUpdate(bytesToSign, 0, bytesToSign.Length);
byte[] signature = sig.GenerateSignature();

//segments.Add(Base64UrlEncode(signature));
return Base64UrlEncode(signature);
}

private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}

然后这是我的转换 java 代码,我尝试从 Java 逐行覆盖到 C#。但是某些代码行让我感到困惑。

private static String sign(String payload, String privateKey) throws Exception{
    String header = "{\"alg\":\"RS256\"}";

    Date issued = new Date();
    Date expire = new Date( issued.getTime() + 10 * 60 * 60 * 1000 );

    byte[] headerBytes = header.getBytes(StandardCharsets.UTF_8);
    byte[] payloadBytes = payload.getBytes(StandardCharsets.UTF_8);

    String stringToSign = Base64UrlEncode(headerBytes) + "." + Base64UrlEncode(payloadBytes);
    byte[] byteToSign = stringToSign.getBytes(StandardCharsets.UTF_8);

    byte[] keyBytes = Base64.getDecoder().decode(privateKey.getBytes(StandardCharsets.UTF_8));

    PemReader reader = new PemReader(new StringReader(privateKey));

    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(reader.readPemObject().getContent());
    KeyFactory kf = KeyFactory.getInstance("RSA");

    Signature privateSignature = Signature.getInstance("SHA256withRSA");
    privateSignature.initSign(kf.generatePrivate(spec));
    privateSignature.update(byteToSign);
    byte[] signature = privateSignature.sign();


    return Base64UrlEncode(signature);
}

private static String Base64UrlEncode(byte[] input){
    String output = java.util.Base64.getEncoder().encodeToString(input);
    output = output.split("=")[0];
    output.replace('+','-');
    output.replace('/','_');
    return output;
}

我对那些 C# 代码行感到困惑

var privKeyObj = Asn1Object.FromByteArray(keyBytes);
var privStruct = RsaPrivateKeyStructure.GetInstance((Asn1Sequence)privKeyObj);

ISigner sig = SignerUtilities.GetSigner("SHA256withRSA");

sig.Init(true, new RsaKeyParameters(true, privStruct.Modulus, privStruct.PrivateExponent));

sig.BlockUpdate(bytesToSign, 0, bytesToSign.Length);
byte[] signature = sig.GenerateSignature();

//segments.Add(Base64UrlEncode(signature));
return Base64UrlEncode(signature);

SignerUtilities Init 和 BlockUpdate 到底是什么我可以用什么类来用 ASN1Object 替换 SignerUtilities

感谢所有阅读这篇文章的人!

标签: javac#bouncycastle

解决方案


推荐阅读