CryptoPrivateKeyRsa.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using Renci.SshNet.Common;
  6. using Renci.SshNet.Security.Cryptography;
  7. using Renci.SshNet.Security.Cryptography.Ciphers;
  8. namespace Renci.SshNet.Security
  9. {
  10. /// <summary>
  11. /// Represents RSA private key
  12. /// </summary>
  13. internal class CryptoPrivateKeyRsa : CryptoPrivateKey
  14. {
  15. private byte[] _modulus;
  16. private byte[] _exponent;
  17. private byte[] _dValue;
  18. private byte[] _pValue;
  19. private byte[] _qValue;
  20. private byte[] _dpValue;
  21. private byte[] _dqValue;
  22. private byte[] _inverseQ;
  23. /// <summary>
  24. /// Gets key name.
  25. /// </summary>
  26. public override string Name
  27. {
  28. get { return "ssh-rsa"; }
  29. }
  30. /// <summary>
  31. /// Loads key specific data.
  32. /// </summary>
  33. /// <param name="data">The data.</param>
  34. public override void Load(IEnumerable<byte> data)
  35. {
  36. MemoryStream ms = null;
  37. try
  38. {
  39. ms = new MemoryStream(data.ToArray());
  40. using (var binr = new BinaryReader(ms))
  41. {
  42. byte bt = 0;
  43. ushort twobytes = 0;
  44. int elems = 0;
  45. twobytes = binr.ReadUInt16();
  46. if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
  47. binr.ReadByte(); //advance 1 byte
  48. else if (twobytes == 0x8230)
  49. binr.ReadInt16(); //advance 2 bytes
  50. else
  51. throw new SshException("RSA key is not valid for use in specified state");
  52. twobytes = binr.ReadUInt16();
  53. if (twobytes != 0x0102) //version number
  54. throw new SshException("RSA key version is not supported.");
  55. bt = binr.ReadByte();
  56. if (bt != 0x00)
  57. throw new SshException("RSA key is not valid for use in specified state");
  58. //------ all private key components are Integer sequences ----
  59. elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
  60. this._modulus = binr.ReadBytes(elems);
  61. elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
  62. this._exponent = binr.ReadBytes(elems);
  63. elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
  64. this._dValue = binr.ReadBytes(elems);
  65. elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
  66. this._pValue = binr.ReadBytes(elems);
  67. elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
  68. this._qValue = binr.ReadBytes(elems);
  69. elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
  70. this._dpValue = binr.ReadBytes(elems);
  71. elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
  72. this._dqValue = binr.ReadBytes(elems);
  73. elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
  74. this._inverseQ = binr.ReadBytes(elems);
  75. }
  76. }
  77. finally
  78. {
  79. if (ms != null)
  80. {
  81. ms.Dispose();
  82. ms = null;
  83. }
  84. }
  85. }
  86. /// <summary>
  87. /// Gets the public key.
  88. /// </summary>
  89. /// <returns></returns>
  90. public override CryptoPublicKey GetPublicKey()
  91. {
  92. return new CryptoPublicKeyRsa(this._modulus, this._exponent);
  93. }
  94. /// <summary>
  95. /// Gets the signature.
  96. /// </summary>
  97. /// <param name="key">The key data bytes.</param>
  98. /// <returns></returns>
  99. public override byte[] GetSignature(IEnumerable<byte> key)
  100. {
  101. var signature = new RsaDigitalSignature(this._exponent, this._modulus, this._dValue, this._dpValue, this._dqValue, this._inverseQ, this._pValue, this._qValue);
  102. return new SignatureKeyData
  103. {
  104. AlgorithmName = this.Name,
  105. Signature = signature.CreateSignature(key.ToArray()),
  106. }.GetBytes().ToArray();
  107. }
  108. /// <summary>
  109. /// Gets key data byte array.
  110. /// </summary>
  111. /// <returns>
  112. /// The data byte array.
  113. /// </returns>
  114. public override IEnumerable<byte> GetBytes()
  115. {
  116. throw new NotImplementedException();
  117. }
  118. private static int GetIntegerSize(BinaryReader binr)
  119. {
  120. byte bt = 0;
  121. byte lowbyte = 0x00;
  122. byte highbyte = 0x00;
  123. int count = 0;
  124. bt = binr.ReadByte();
  125. if (bt != 0x02) //expect integer
  126. return 0;
  127. bt = binr.ReadByte();
  128. if (bt == 0x81)
  129. count = binr.ReadByte(); // data size in next byte
  130. else
  131. if (bt == 0x82)
  132. {
  133. highbyte = binr.ReadByte(); // data size in next 2 bytes
  134. lowbyte = binr.ReadByte();
  135. byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
  136. count = (int)(modint[3] << 24 | modint[2] << 16 | modint[1] << 8 | modint[0]);
  137. }
  138. else
  139. {
  140. count = bt; // we already have the data size
  141. }
  142. return count;
  143. }
  144. }
  145. }