"SHA512withRSA"서명, 서명 된 데이터 및 공개 키 (base64 형식)가 제 3 자에게 전송되었습니다. 공개 키를 사용하여 서명이 주어진 데이터에 맞는지 확인해야합니다.SHA512withRSA .Net의 서명 확인
기본 질문은 .Net (이 C# 코드)에서 어떻게 확인합니까?
.Net 프레임 워크에서만 가능합니다 (RSACryptoServiceProvider는 관련 클래스이지만 SHA1을 서명 알고리즘으로 지원함).
그렇지 않은 경우 어떤 라이브러리를 사용할 수 있습니까? 나는 BouncyCastle을 시도해 왔지만 이것을 명확하게 설명하는 문서를 찾을 수는 없습니다. 거의 모든 문서는 인증서를 다루는 것에 관한 것이고, 나는 인증서를 갖고 있지도 원하지도 않는다.
편집 : 새로운 샘플 코드 (계속 실패)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace SignatureVerificationTest
{
class Program
{
static void Main(string[] args)
{
var t = DoWorkAsync();
Console.ReadLine();
}
public static async Task DoWorkAsync()
{
var rawNotificationData = "merchantOrderId=e7ea4e4c-7ffa-4b19-8af9-ad875c493620&status=AUTHORISED&signature=hgvtCb6RjmhtumXTNuARW8fotZVoIJ%2FAaqXEow1pxA0Ic5afe0j2lGHO%2F6Q7rnPXqd728mMsmkjQSyxGDho7imxYGHEyEudt%2B%2FThOboAj%2FhePNLNfCeJR7DS7LIzO7SCTDkkTHZ%2F5sD5JhBATY3EFADrLnzzlF445mNRP%2Bv2vi3ogVC5k3oYfPCSmvOzd8DFUp6E6cwZelBGQjRHwVJf07%2B8x4esYxW%2FJii3z6quXzaKpImLFt3jaDTe109uwTwsv8bRBh%2F%2FSjFlHPaEr5QTAjTDA0IrMP6OggGTDkukW8sr7PUmQoq%2B4%2FLEIlHqXbuwZgJ2zr7fN75CcwWaj6FHfdiVvmeKGshO11DnHX7rN%2FTU36z7D7jRp%2Fykd4q409MorZUfZspHuXp2XRXo1732OZKRdYkX73eDphFKQUbmhGCf9wQq3xxxlw6Qr3ClTAi8SbOeY8IQIul%2Bp3x0X5G%2FiJmtiMcHMErxxCx2Y84OozrbvMEQP8qzY4FLUuV%2BKv9oragcXfDvpkJ4EAAqZPufXGZ3zCyk5yBJEXy6kqZ7ht16bpuD0aQMBlq2eTyQCOgtRvOPCFJYwCVJ8z43xQShffKa9Tj7gSgPE9LfvD3%2Ba4NdEh0Hg5yV7A7wABLySC%2F3thXvxVfVthNJEfdHZPhpAN2i3C5sql09R27k5SEV96c%3D";
//Find the signature in the data, and url decode the value
var x = rawNotificationData.Split(new char[] { '&' });
string notificationSignature = null;
foreach (var kvp in x)
{
var parts = kvp.Split(new char[] { '=' });
if (parts[0] == "signature")
{
notificationSignature = Uri.UnescapeDataString(parts[1]);
break;
}
}
// Get the portion of the string that was signed
// Should be;
// merchantOrderId=e7ea4e4c-7ffa-4b19-8af9-ad875c493620&status=AUTHORISED
var signedData = rawNotificationData.Substring(0, rawNotificationData.IndexOf("&signature=", StringComparison.OrdinalIgnoreCase));
//Define the public key (base 64 encoded string)
var publicKey = @"MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv3kDhkB2yHn/4N1KtNsm
8IuWuqfnOIDxOnR2txELEtKL1YqSTiAtoBHWfvGg2OMN1gu0/owecT7d9+TnXx7M
NE4CGp3UOLkdTzRifDMrMh5T9WVvyKfV4Chnv/tkmK7BMSe+yS4T+3IQVBv0zFKu
Hm9Y8Zicc5sIkTRdpgeg1wbYZkbKA5qZcYkKUKpWHKmWVMyIqqhwAcKFA9dc0j8f
h6EM3JWQhFOFkXngUHX4O+L2mJ7rnYsMZzujoK3fNk/HIHYtJiZbkbEOzlDGhzp0
ZackirqZ2iqPRSgZsVcyqTthNiYxjkOvB5AYb/Ww+3T/UQ2zaB0ac7dgLKrq8BL5
HpVke93F4kQQ6M1BmIWfLiQt3FLRX+LxkcNC5q1SaPW8D/7lnYACM0JErrpA8/Dc
7U7Th6R8Wk99V8O0FN6+t9gr3lwG99Hw7AykstlPWMdFDch+ljM4JGf/hvxcZDlp
ACSRPf1BXNON1E6WMofyAXNSsuQ3kG/go0f5pzix+K/484y4PPKizbWTGWElK9sJ
d2jDFEGG5iCoFzJNLvEvuvzHHhP+cM5y7LTX7D0B8LPdj1kIEboTAIfdhQ1IVVYa
mSo7WTB/sHgxGk9+8K3EboGAzSmgIqlLrMZob1h8/32LsVSxKhgxs01tGotB7rJO
MmwP7rPHQjvq0NoPMTFPd+ECAwEAAQ==";
// Decode the base64 key into raw bytes
// (Decodes to 550 bytes)
var rawKey = Convert.FromBase64String(publicKey);
//Create an RSA crypto provider instance initialised with the key
//Decodes to a 512 byte modulus and 3 (1, 0, 1) byte exponent
using (var rsa = CreateRsa(rawKey))
{
bool signatureVerified = rsa.VerifyData
(
System.Text.UTF8Encoding.UTF8.GetBytes(signedData),
CryptoConfig.MapNameToOID("SHA512"),
Convert.FromBase64String(notificationSignature)
);
//Fail if the signature didn't verify
Debug.Assert(signatureVerified, "Signature did not verify.");
}
}
private static readonly byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
private static RSACryptoServiceProvider CreateRsa(byte[] publicKey)
{
/*
This code parses the publickey bytes to extract the relevant bits of the public key, the initialises
the rsa crypto provider with the key.
Taken from "CreateRsa" below is modified from http://www.jensign.com/JavaScience/dotnet/pempublic/
Original license below applies.
Copyright(c) 2006 - 2014 JavaScience Consulting, Michel Gallant
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var mem = new System.IO.MemoryStream(publicKey);
BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
var seq = binr.ReadBytes(15); //read the Sequence OID
if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct
return null;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8203)
binr.ReadInt16(); //advance 2 bytes
else
return null;
bt = binr.ReadByte();
if (bt != 0x00) //expect null byte next
return null;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
twobytes = binr.ReadUInt16();
byte lowbyte = 0x00;
byte highbyte = 0x00;
if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus
else if (twobytes == 0x8202)
{
highbyte = binr.ReadByte(); //advance 2 bytes
lowbyte = binr.ReadByte();
}
else
return null;
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order
int modsize = BitConverter.ToInt32(modint, 0);
int firstbyte = binr.PeekChar();
if (firstbyte == 0x00)
{ //if first byte (highest order) of modulus is zero, don't include it
binr.ReadByte(); //skip this null byte
modsize -= 1; //reduce modulus buffer size by 1
}
byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes
if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data
return null;
int expbytes = (int)binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values)
byte[] exponent = binr.ReadBytes(expbytes);
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters();
RSAKeyInfo.Modulus = modulus;
RSAKeyInfo.Exponent = exponent;
RSA.ImportParameters(RSAKeyInfo);
RSA.PersistKeyInCsp = false;
return RSA;
}
private static bool CompareBytearrays(byte[] a, byte[] b)
{
if (a.Length != b.Length)
return false;
int i = 0;
foreach (byte c in a)
{
if (c != b[i])
return false;
i++;
}
return true;
}
}
}
그래서 여기에서 코드를 시도해 보았습니다. http://stackoverflow.com/questions/8437288/signing-and-verifying-signatures-with-rsa-c-sharp - 자체적으로 생성 된 서명은 유효화하지만 주어진 서명은 검증하지 않습니다. (키가 있습니다. 주어진). RSA.SigningAlgorithm 속성은 여전히 SHA1을 말합니다.하지만 중요한지는 알 수 없습니다. – Yort
코드가 작동하고 공개 키 만 잘못된 경우 코드에서 오류가 분명하지 않기 때문에 질문을 닫아야합니다. –