Encryption 从Java到C的RSA签名端口#
我有一个Java中的方法,C#中的代码应该是相同的。我正在苦苦思索C#代码将如何实现这一点Encryption 从Java到C的RSA签名端口#,encryption,rsa,Encryption,Rsa,我有一个Java中的方法,C#中的代码应该是相同的。我正在苦苦思索C#代码将如何实现这一点 私有字符串签名SHA256RSA(字符串输入)引发异常 { 字节[]b1=Base64.getDecoder().decode(privKey); PKCS8EncodedKeySpec spec=新的PKCS8EncodedKeySpec(b1); KeyFactory kf=KeyFactory.getInstance(“RSA”); Signature privateSignature=Signat
私有字符串签名SHA256RSA(字符串输入)引发异常
{
字节[]b1=Base64.getDecoder().decode(privKey);
PKCS8EncodedKeySpec spec=新的PKCS8EncodedKeySpec(b1);
KeyFactory kf=KeyFactory.getInstance(“RSA”);
Signature privateSignature=Signature.getInstance(“SHA256withRSA”);
privatesign.initSign(kf.generatePrivate(spec));
privatesign.update(input.getBytes(StandardCharsets.UTF_8));
返回byteArrayToHex(privateSignature.sign());
}
使用.NET标准2.1,您需要一个小助手来解码Base64编码的DER文件中的私钥
using System;
using System.Security.Cryptography;
using System.Buffers.Binary;
using System.Text;
namespace Demo
{
class Program
{
const string DerPrivateKey = "MIIBywIBAAJhALkPdKoBJJg8t0Qg7VhyomS+PpKNMzn0NQ/P3zt55uAmLKenUV9xbMhW1SQRUbTEDdDUlfIiBMCzNAxB5od2IrhP4+/nKmUNsIoxOdwL0j//X74xalv9137T+y4ubLzVhwIDAQABAmAScdvq5dpD4ilR/QYq/qH48I1EBhbI+/Id9VYGk4vTY3qn6yFNJfz1qtHrml5OagvbBQLyPwjwxSumkzGelauqr4NvpOirK18v3xzhlsSmys6JZ5nILG16JByXxJjvziECMQDluHUNOCElxIbIrFOTVBaiqs4Iw9b/UJ7Wf7GglFk4pS00wjSnuDMDqGjyb4tgQ3UCMQDOOxdcSs2CPLrppT463NMqDoGide33X4s5y67E9v44IMTKuOwIXoDzgTcoGmeJwYsCMQDWUZRrA93xFXxGRngmsMH5e2+Dv+qbAsVeC35V+XGQJpKZcUKc4348wGdBIA4hfm0CMQCllxDkzDNDFZxHKqVTAiiTpl40olhWvmK+H2vPPztUugsJc34iIi+MVf6BtuHX3I0CMEDuG1uewuwcgHxWTGMnvSqQjkwtTUI0It6c8PTf8URGtoHx7HNl/wKoGGgXLTRY1w==";
static void Main(string[] args)
{
var signature = SignSHA256RSA(base64Key: DerPrivateKey, input: "Hello world!");
System.Console.WriteLine("Signature (HEX): " + signature);
}
private static string SignSHA256RSA(string base64Key, string input)
{
// Load key with the little DER helper
var rsa = LoadRSAKey(derPrivateKey: Convert.FromBase64String(DerPrivateKey));
// Sign
var inputBytes = Encoding.UTF8.GetBytes(input);
var signatureBytes = rsa.SignData(inputBytes, 0, inputBytes.Length, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
// Convert signature to hex
var signatureHex = BitConverter.ToString(signatureBytes).Replace("-", string.Empty);
return signatureHex;
}
private static RSA LoadRSAKey(ReadOnlySpan<byte> derPrivateKey)
{
// Expect sequence
if (AsnHelper.GetTag(derPrivateKey[0]) != 16)
throw new FormatException($"unexpected tag");
// Read sequence length
derPrivateKey = derPrivateKey.Slice(1);
if (!AsnHelper.TryReadLength(derPrivateKey, out var length, out var bytesRead))
throw new FormatException($"unexpected length");
var sequence = AsnHelper.ReadSequence(derPrivateKey.Slice(bytesRead, length));
// https://www.hanselman.com/blog/DecodingAnSSHKeyFromPEMToBASE64ToHEXToASN1ToPrimeDecimalNumbers.aspx
var rsaParameters = new RSAParameters
{
Modulus = sequence[1].RawData,
Exponent = sequence[2].RawData,
D = sequence[3].RawData,
P = sequence[4].RawData,
Q = sequence[5].RawData,
DP = sequence[6].RawData,
DQ = sequence[7].RawData,
InverseQ = sequence[8].RawData,
};
var rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
}
/// <summary>
/// Quick helper: only works on specific key format
///
/// https://en.wikipedia.org/wiki/X.690#BER_encoding
/// </summary>
internal static class AsnHelper
{
public static int GetTag(byte value) => value & 0b11111;
public static AsnEncodedDataCollection ReadSequence(ReadOnlySpan<byte> source)
{
var sequence = new AsnEncodedDataCollection();
while (!source.IsEmpty)
{
var tag = GetTag(source[0]);
if (tag != 2)
throw new FormatException("only support integer");
source = source.Slice(1);
if (!TryReadLength(source, out var length, out var bytesRead))
throw new FormatException("invalid length");
source = source.Slice(bytesRead);
var value = new AsnEncodedData(source.Slice(0, length).ToArray());
source = source.Slice(length);
sequence.Add(value);
}
return sequence;
}
public static bool TryReadLength(ReadOnlySpan<byte> source, out int length, out int bytesRead)
{
length = 0;
bytesRead = 0;
const byte MultiByteMarker = 0x80;
bytesRead = 1;
if ((source[0] & MultiByteMarker) == 0)
{
length = source[0];
return true;
}
int lengthLength = source[0] & 0x7F;
bytesRead += lengthLength;
if (lengthLength == 2)
{
length = BinaryPrimitives.ReadInt16BigEndian(source.Slice(1));
return true;
}
return false;
}
}
}
这就是我最终解决这个问题的方法
- 我使用了这个第三方库 然后我就用了这个代码
准确地指定在c#中要执行的操作。编写一个代码,执行与Java相同的操作,或者您希望验证用Java创建的签名。我不是这两种语言中的加密专家。你的目标是哪个.NET运行时?.NET标准2.1感谢你的评论。实际上,我用另一种方法解决了这个问题,使用第三方Nuget读取PEM文件。我将发布我的完整解决方案
private static string SignSHA256RSA(string itemToSign)
{
var bytes = Encoding.UTF8.GetBytes(itemToSign);
using (var stream = File.OpenRead(@"C:\PrivateKey.pem"))
using (var reader = new PemReader(stream))
{
var rsaParameters = reader.ReadRsaKey();
byte[] hv = SHA256.Create().ComputeHash(bytes);
RSACryptoServiceProvider prov = new RSACryptoServiceProvider();
RSAParameters rsp = new RSAParameters();
prov.ImportParameters(rsaParameters);
RSAPKCS1SignatureFormatter rf = new RSAPKCS1SignatureFormatter(prov);
rf.SetHashAlgorithm("SHA256");
byte[] signature = rf.CreateSignature(hv);
var finalHex = BitConverter.ToString(signature).Replace("-", string.Empty).ToLowerInvariant();
return finalHex;
}
}