Iso9796d2Signer.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using System.Collections;
  4. using Org.BouncyCastle.Crypto;
  5. using Org.BouncyCastle.Crypto.Digests;
  6. using Org.BouncyCastle.Crypto.Parameters;
  7. using Org.BouncyCastle.Utilities;
  8. namespace Org.BouncyCastle.Crypto.Signers
  9. {
  10. /// <summary> ISO9796-2 - mechanism using a hash function with recovery (scheme 1)</summary>
  11. public class Iso9796d2Signer : ISignerWithRecovery
  12. {
  13. /// <summary>
  14. /// Return a reference to the recoveredMessage message.
  15. /// </summary>
  16. /// <returns>The full/partial recoveredMessage message.</returns>
  17. /// <seealso cref="ISignerWithRecovery.GetRecoveredMessage"/>
  18. public byte[] GetRecoveredMessage()
  19. {
  20. return recoveredMessage;
  21. }
  22. [Obsolete("Use 'IsoTrailers' instead")]
  23. public const int TrailerImplicit = 0xBC;
  24. [Obsolete("Use 'IsoTrailers' instead")]
  25. public const int TrailerRipeMD160 = 0x31CC;
  26. [Obsolete("Use 'IsoTrailers' instead")]
  27. public const int TrailerRipeMD128 = 0x32CC;
  28. [Obsolete("Use 'IsoTrailers' instead")]
  29. public const int TrailerSha1 = 0x33CC;
  30. [Obsolete("Use 'IsoTrailers' instead")]
  31. public const int TrailerSha256 = 0x34CC;
  32. [Obsolete("Use 'IsoTrailers' instead")]
  33. public const int TrailerSha512 = 0x35CC;
  34. [Obsolete("Use 'IsoTrailers' instead")]
  35. public const int TrailerSha384 = 0x36CC;
  36. [Obsolete("Use 'IsoTrailers' instead")]
  37. public const int TrailerWhirlpool = 0x37CC;
  38. private IDigest digest;
  39. private IAsymmetricBlockCipher cipher;
  40. private int trailer;
  41. private int keyBits;
  42. private byte[] block;
  43. private byte[] mBuf;
  44. private int messageLength;
  45. private bool fullMessage;
  46. private byte[] recoveredMessage;
  47. private byte[] preSig;
  48. private byte[] preBlock;
  49. /// <summary>
  50. /// Generate a signer with either implicit or explicit trailers for ISO9796-2.
  51. /// </summary>
  52. /// <param name="cipher">base cipher to use for signature creation/verification</param>
  53. /// <param name="digest">digest to use.</param>
  54. /// <param name="isImplicit">whether or not the trailer is implicit or gives the hash.</param>
  55. public Iso9796d2Signer(
  56. IAsymmetricBlockCipher cipher,
  57. IDigest digest,
  58. bool isImplicit)
  59. {
  60. this.cipher = cipher;
  61. this.digest = digest;
  62. if (isImplicit)
  63. {
  64. trailer = IsoTrailers.TRAILER_IMPLICIT;
  65. }
  66. else if (IsoTrailers.NoTrailerAvailable(digest))
  67. {
  68. throw new ArgumentException("no valid trailer", "digest");
  69. }
  70. else
  71. {
  72. trailer = IsoTrailers.GetTrailer(digest);
  73. }
  74. }
  75. /// <summary> Constructor for a signer with an explicit digest trailer.
  76. ///
  77. /// </summary>
  78. /// <param name="cipher">cipher to use.
  79. /// </param>
  80. /// <param name="digest">digest to sign with.
  81. /// </param>
  82. public Iso9796d2Signer(IAsymmetricBlockCipher cipher, IDigest digest)
  83. : this(cipher, digest, false)
  84. {
  85. }
  86. public virtual string AlgorithmName
  87. {
  88. get { return digest.AlgorithmName + "with" + "ISO9796-2S1"; }
  89. }
  90. public virtual void Init(bool forSigning, ICipherParameters parameters)
  91. {
  92. RsaKeyParameters kParam = (RsaKeyParameters) parameters;
  93. cipher.Init(forSigning, kParam);
  94. keyBits = kParam.Modulus.BitLength;
  95. block = new byte[(keyBits + 7) / 8];
  96. if (trailer == IsoTrailers.TRAILER_IMPLICIT)
  97. {
  98. mBuf = new byte[block.Length - digest.GetDigestSize() - 2];
  99. }
  100. else
  101. {
  102. mBuf = new byte[block.Length - digest.GetDigestSize() - 3];
  103. }
  104. Reset();
  105. }
  106. /// <summary> compare two byte arrays - constant time.</summary>
  107. private bool IsSameAs(byte[] a, byte[] b)
  108. {
  109. int checkLen;
  110. if (messageLength > mBuf.Length)
  111. {
  112. if (mBuf.Length > b.Length)
  113. {
  114. return false;
  115. }
  116. checkLen = mBuf.Length;
  117. }
  118. else
  119. {
  120. if (messageLength != b.Length)
  121. {
  122. return false;
  123. }
  124. checkLen = b.Length;
  125. }
  126. bool isOkay = true;
  127. for (int i = 0; i != checkLen; i++)
  128. {
  129. if (a[i] != b[i])
  130. {
  131. isOkay = false;
  132. }
  133. }
  134. return isOkay;
  135. }
  136. /// <summary> clear possible sensitive data</summary>
  137. private void ClearBlock(
  138. byte[] block)
  139. {
  140. Array.Clear(block, 0, block.Length);
  141. }
  142. public virtual void UpdateWithRecoveredMessage(
  143. byte[] signature)
  144. {
  145. byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
  146. if (((block[0] & 0xC0) ^ 0x40) != 0)
  147. throw new InvalidCipherTextException("malformed signature");
  148. if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
  149. throw new InvalidCipherTextException("malformed signature");
  150. int delta = 0;
  151. if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
  152. {
  153. delta = 1;
  154. }
  155. else
  156. {
  157. int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
  158. if (IsoTrailers.NoTrailerAvailable(digest))
  159. throw new ArgumentException("unrecognised hash in signature");
  160. if (sigTrail != IsoTrailers.GetTrailer(digest))
  161. throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
  162. delta = 2;
  163. }
  164. //
  165. // find out how much padding we've got
  166. //
  167. int mStart = 0;
  168. for (mStart = 0; mStart != block.Length; mStart++)
  169. {
  170. if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
  171. break;
  172. }
  173. mStart++;
  174. int off = block.Length - delta - digest.GetDigestSize();
  175. //
  176. // there must be at least one byte of message string
  177. //
  178. if ((off - mStart) <= 0)
  179. throw new InvalidCipherTextException("malformed block");
  180. //
  181. // if we contain the whole message as well, check the hash of that.
  182. //
  183. if ((block[0] & 0x20) == 0)
  184. {
  185. fullMessage = true;
  186. recoveredMessage = new byte[off - mStart];
  187. Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
  188. }
  189. else
  190. {
  191. fullMessage = false;
  192. recoveredMessage = new byte[off - mStart];
  193. Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
  194. }
  195. preSig = signature;
  196. preBlock = block;
  197. digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length);
  198. messageLength = recoveredMessage.Length;
  199. recoveredMessage.CopyTo(mBuf, 0);
  200. }
  201. /// <summary> update the internal digest with the byte b</summary>
  202. public virtual void Update(
  203. byte input)
  204. {
  205. digest.Update(input);
  206. if (messageLength < mBuf.Length)
  207. {
  208. mBuf[messageLength] = input;
  209. }
  210. messageLength++;
  211. }
  212. /// <summary> update the internal digest with the byte array in</summary>
  213. public virtual void BlockUpdate(
  214. byte[] input,
  215. int inOff,
  216. int length)
  217. {
  218. while (length > 0 && messageLength < mBuf.Length)
  219. {
  220. //for (int i = 0; i < length && (i + messageLength) < mBuf.Length; i++)
  221. //{
  222. // mBuf[messageLength + i] = input[inOff + i];
  223. //}
  224. this.Update(input[inOff]);
  225. inOff++;
  226. length--;
  227. }
  228. digest.BlockUpdate(input, inOff, length);
  229. messageLength += length;
  230. }
  231. /// <summary> reset the internal state</summary>
  232. public virtual void Reset()
  233. {
  234. digest.Reset();
  235. messageLength = 0;
  236. ClearBlock(mBuf);
  237. if (recoveredMessage != null)
  238. {
  239. ClearBlock(recoveredMessage);
  240. }
  241. recoveredMessage = null;
  242. fullMessage = false;
  243. if (preSig != null)
  244. {
  245. preSig = null;
  246. ClearBlock(preBlock);
  247. preBlock = null;
  248. }
  249. }
  250. /// <summary> Generate a signature for the loaded message using the key we were
  251. /// initialised with.
  252. /// </summary>
  253. public virtual byte[] GenerateSignature()
  254. {
  255. int digSize = digest.GetDigestSize();
  256. int t = 0;
  257. int delta = 0;
  258. if (trailer == IsoTrailers.TRAILER_IMPLICIT)
  259. {
  260. t = 8;
  261. delta = block.Length - digSize - 1;
  262. digest.DoFinal(block, delta);
  263. block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
  264. }
  265. else
  266. {
  267. t = 16;
  268. delta = block.Length - digSize - 2;
  269. digest.DoFinal(block, delta);
  270. block[block.Length - 2] = (byte) ((uint)trailer >> 8);
  271. block[block.Length - 1] = (byte) trailer;
  272. }
  273. byte header = 0;
  274. int x = (digSize + messageLength) * 8 + t + 4 - keyBits;
  275. if (x > 0)
  276. {
  277. int mR = messageLength - ((x + 7) / 8);
  278. header = (byte) (0x60);
  279. delta -= mR;
  280. Array.Copy(mBuf, 0, block, delta, mR);
  281. }
  282. else
  283. {
  284. header = (byte) (0x40);
  285. delta -= messageLength;
  286. Array.Copy(mBuf, 0, block, delta, messageLength);
  287. }
  288. if ((delta - 1) > 0)
  289. {
  290. for (int i = delta - 1; i != 0; i--)
  291. {
  292. block[i] = (byte) 0xbb;
  293. }
  294. block[delta - 1] ^= (byte) 0x01;
  295. block[0] = (byte) 0x0b;
  296. block[0] |= header;
  297. }
  298. else
  299. {
  300. block[0] = (byte) 0x0a;
  301. block[0] |= header;
  302. }
  303. byte[] b = cipher.ProcessBlock(block, 0, block.Length);
  304. ClearBlock(mBuf);
  305. ClearBlock(block);
  306. return b;
  307. }
  308. /// <summary> return true if the signature represents a ISO9796-2 signature
  309. /// for the passed in message.
  310. /// </summary>
  311. public virtual bool VerifySignature(byte[] signature)
  312. {
  313. byte[] block;
  314. if (preSig == null)
  315. {
  316. try
  317. {
  318. block = cipher.ProcessBlock(signature, 0, signature.Length);
  319. }
  320. catch (Exception)
  321. {
  322. return false;
  323. }
  324. }
  325. else
  326. {
  327. if (!Arrays.AreEqual(preSig, signature))
  328. throw new InvalidOperationException("updateWithRecoveredMessage called on different signature");
  329. block = preBlock;
  330. preSig = null;
  331. preBlock = null;
  332. }
  333. if (((block[0] & 0xC0) ^ 0x40) != 0)
  334. return ReturnFalse(block);
  335. if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
  336. return ReturnFalse(block);
  337. int delta = 0;
  338. if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
  339. {
  340. delta = 1;
  341. }
  342. else
  343. {
  344. int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
  345. if (IsoTrailers.NoTrailerAvailable(digest))
  346. throw new ArgumentException("unrecognised hash in signature");
  347. if (sigTrail != IsoTrailers.GetTrailer(digest))
  348. throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
  349. delta = 2;
  350. }
  351. //
  352. // find out how much padding we've got
  353. //
  354. int mStart = 0;
  355. for (; mStart != block.Length; mStart++)
  356. {
  357. if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
  358. {
  359. break;
  360. }
  361. }
  362. mStart++;
  363. //
  364. // check the hashes
  365. //
  366. byte[] hash = new byte[digest.GetDigestSize()];
  367. int off = block.Length - delta - hash.Length;
  368. //
  369. // there must be at least one byte of message string
  370. //
  371. if ((off - mStart) <= 0)
  372. {
  373. return ReturnFalse(block);
  374. }
  375. //
  376. // if we contain the whole message as well, check the hash of that.
  377. //
  378. if ((block[0] & 0x20) == 0)
  379. {
  380. fullMessage = true;
  381. // check right number of bytes passed in.
  382. if (messageLength > off - mStart)
  383. {
  384. return ReturnFalse(block);
  385. }
  386. digest.Reset();
  387. digest.BlockUpdate(block, mStart, off - mStart);
  388. digest.DoFinal(hash, 0);
  389. bool isOkay = true;
  390. for (int i = 0; i != hash.Length; i++)
  391. {
  392. block[off + i] ^= hash[i];
  393. if (block[off + i] != 0)
  394. {
  395. isOkay = false;
  396. }
  397. }
  398. if (!isOkay)
  399. {
  400. return ReturnFalse(block);
  401. }
  402. recoveredMessage = new byte[off - mStart];
  403. Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
  404. }
  405. else
  406. {
  407. fullMessage = false;
  408. digest.DoFinal(hash, 0);
  409. bool isOkay = true;
  410. for (int i = 0; i != hash.Length; i++)
  411. {
  412. block[off + i] ^= hash[i];
  413. if (block[off + i] != 0)
  414. {
  415. isOkay = false;
  416. }
  417. }
  418. if (!isOkay)
  419. {
  420. return ReturnFalse(block);
  421. }
  422. recoveredMessage = new byte[off - mStart];
  423. Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
  424. }
  425. //
  426. // if they've input a message check what we've recovered against
  427. // what was input.
  428. //
  429. if (messageLength != 0)
  430. {
  431. if (!IsSameAs(mBuf, recoveredMessage))
  432. {
  433. return ReturnFalse(block);
  434. }
  435. }
  436. ClearBlock(mBuf);
  437. ClearBlock(block);
  438. return true;
  439. }
  440. private bool ReturnFalse(byte[] block)
  441. {
  442. ClearBlock(mBuf);
  443. ClearBlock(block);
  444. return false;
  445. }
  446. /// <summary>
  447. /// Return true if the full message was recoveredMessage.
  448. /// </summary>
  449. /// <returns> true on full message recovery, false otherwise.</returns>
  450. /// <seealso cref="ISignerWithRecovery.HasFullMessage"/>
  451. public virtual bool HasFullMessage()
  452. {
  453. return fullMessage;
  454. }
  455. }
  456. }
  457. #endif