CipherDigitalSignature.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Security.Cryptography;
  6. using Renci.SshNet.Common;
  7. namespace Renci.SshNet.Security.Cryptography
  8. {
  9. /// <summary>
  10. /// Implements digital signature where where asymmetric cipher is used,
  11. /// </summary>
  12. public abstract class CipherDigitalSignature : DigitalSignature
  13. {
  14. private AsymmetricCipher _cipher;
  15. private ObjectIdentifier _oid;
  16. /// <summary>
  17. /// Initializes a new instance of the <see cref="CipherDigitalSignature"/> class.
  18. /// </summary>
  19. /// <param name="oid">The object identifier.</param>
  20. /// <param name="cipher">The cipher.</param>
  21. public CipherDigitalSignature(ObjectIdentifier oid, AsymmetricCipher cipher)
  22. {
  23. if (cipher == null)
  24. throw new ArgumentNullException("cipher");
  25. this._cipher = cipher;
  26. this._oid = oid;
  27. }
  28. /// <summary>
  29. /// Verifies the signature.
  30. /// </summary>
  31. /// <param name="input">The input.</param>
  32. /// <param name="signature">The signature.</param>
  33. /// <returns></returns>
  34. public override bool Verify(byte[] input, byte[] signature)
  35. {
  36. var sig = this._cipher.Decrypt(signature);
  37. // TODO: Ensure that only 1 or 2 types are supported
  38. var position = 1;
  39. while (position < sig.Length && sig[position] != 0)
  40. position++;
  41. position++;
  42. var sig1 = new byte[sig.Length - position];
  43. Array.Copy(sig, position, sig1, 0, sig1.Length);
  44. var hashData = this.Hash(input);
  45. var expected = DerEncode(hashData);
  46. if (expected.Length != sig1.Length)
  47. return false;
  48. for (int i = 0; i < expected.Length; i++)
  49. {
  50. if (expected[i] != sig1[i])
  51. return false;
  52. }
  53. return true;
  54. }
  55. /// <summary>
  56. /// Creates the signature.
  57. /// </summary>
  58. /// <param name="input">The input.</param>
  59. /// <returns></returns>
  60. public override byte[] Sign(byte[] input)
  61. {
  62. // Calculate hash value
  63. var hashData = this.Hash(input);
  64. // Calculate DER string
  65. var derEncodedHash = DerEncode(hashData);
  66. // Calculate signature
  67. var rsaInputBlockSize = new byte[255];
  68. rsaInputBlockSize[0] = 0x01;
  69. for (int i = 1; i < rsaInputBlockSize.Length - derEncodedHash.Length - 1; i++)
  70. {
  71. rsaInputBlockSize[i] = 0xFF;
  72. }
  73. Array.Copy(derEncodedHash, 0, rsaInputBlockSize, rsaInputBlockSize.Length - derEncodedHash.Length, derEncodedHash.Length);
  74. return this._cipher.Encrypt(rsaInputBlockSize).TrimLeadingZero().ToArray();
  75. }
  76. /// <summary>
  77. /// Hashes the specified input.
  78. /// </summary>
  79. /// <param name="input">The input.</param>
  80. /// <returns></returns>
  81. protected abstract byte[] Hash(byte[] input);
  82. /// <summary>
  83. /// Encodes hash using DER.
  84. /// </summary>
  85. /// <param name="hashData">The hash data.</param>
  86. /// <returns>DER Encoded byte array</returns>
  87. protected byte[] DerEncode(byte[] hashData)
  88. {
  89. var data = new DerData();
  90. var alg = new DerData();
  91. alg.Write(this._oid);
  92. alg.WriteNull();
  93. data.Write(alg);
  94. data.Write(hashData);
  95. return data.Encode();
  96. }
  97. }
  98. }