CipherDigitalSignature.cs 4.0 KB

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