2016-06-01 4 views
2

У меня проблема, когда я пытаюсь проверить подпись ECDSA в Bouncy Castle на C#. Код принят из примера Java, который у меня есть, поэтому я на 100% уверен, что открытый ключ и подпись верны. Но реализация C# всегда возвращает, что подпись недопустима. Я проверил параметры кривой, и они верны. Я попытался с DER и «сырой» подписью, и снова это не сработало.Проверка подписи ECDSA с Bouncy Castle в C#

Кто-нибудь может определить, что я делаю неправильно:

namespace TestECDSA 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     byte[] b = new byte[] { 0x2B, 0xA1, 0x41, 0x00 }; 

     string pubKey = "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"; 
     string signature = "AAD03D3D38CE53B673CF8F1C016C8D3B67EA98CBCF72627788368C7C54AA2FC4"; 

     X9ECParameters curve = SecNamedCurves.GetByName("secp128r1"); 
     ECDomainParameters curveSpec = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed()); 

     ECPublicKeyParameters key = new ECPublicKeyParameters("ECDSA", curve.Curve.DecodePoint(Hex.Decode(pubKey)), curveSpec); 

     ISigner signer = SignerUtilities.GetSigner("NONEwithECDSA");    

     signer.Init(false, key); 

     signer.BlockUpdate(b, 0, b.Length); 

     if (signer.VerifySignature(derEncodeSignature(Hex.Decode(signature)))) 
      System.Console.WriteLine("Verified Signature"); 
     else 
      System.Console.WriteLine("Not Verified Signature"); 
    } 

    public static byte[] derEncodeSignature(byte[] signature) 
    { 
     byte[] encoded = new byte[6 + signature.Length]; 

     byte[] r = RangeSubset(signature, 0, 16); 
     byte[] s = RangeSubset(signature, 16, 16); 

     encoded[0] = 0x30; 
     encoded[1] = 0x24; 
     encoded[2] = 0x02; 
     encoded[3] = 0x10; 

     encoded[4 + r.Length] = 0x02; 
     encoded[5 + r.Length] = 0x10; 

     Array.Copy(r, 0, encoded, 4, r.Length); 
     Array.Copy(s, 0, encoded, 6 + r.Length, r.Length); 

     return encoded; 
    } 

    public static T[] RangeSubset<T>(T[] array, int startIndex, int length) 
    { 
     T[] subset = new T[length]; 
     Array.Copy(array, startIndex, subset, 0, length); 
     return subset; 
    } 
} 
} 
+0

'NONEwithECDSA'? Ты уверен? ECDSA требует хэш-значения! 'NONEwithECDSA' следует использовать только в том случае, если вы предварительно вычислите вещи сами, я полагаю. –

+0

B содержит хэш так, что это правильно. – sposnjak

+0

Хэш из 4 байтов? Или это сокращенная выборка? secp128r1 бит слишком короткий (сопоставим с 64-битным симметричным размером ключа). –

ответ

2

dbugger был прав. Кодирование DER неверно. Код в вопрос должен быть заменен:

private static byte[] derEncodeSignature(byte[] signature) 
    { 
     byte[] r = signature.RangeSubset(0, (signature.Length/2)); 
     byte[] s = signature.RangeSubset((signature.Length/2), (signature.Length/2)); 

     MemoryStream stream = new MemoryStream(); 
     DerOutputStream der = new DerOutputStream(stream); 

     Asn1EncodableVector v = new Asn1EncodableVector(); 
     v.Add(new DerInteger(new BigInteger(1, r))); 
     v.Add(new DerInteger(new BigInteger(1, s))); 
     der.WriteObject(new DerSequence(v)); 

     return stream.ToArray(); 
    } 
3

Вместо DER-кодирующего подпись самостоятельно, вы можете использовать signer.GenerateSignature() следующим образом:

 var signerAlgorithm = "SHA256withECDSA"; 

     ISigner signer = SignerUtilities.GetSigner(signerAlgorithm); 
     signer.Init(true, privateSigningKey); 
     signer.BlockUpdate(data, 0, data.Length); 
     byte[] signature = signer.GenerateSignature(); 

     return signature; 

 Смежные вопросы

  • Нет связанных вопросов^_^