CryptoConvert.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. //
  2. // CryptoConvert.cs - Crypto Convertion Routines
  3. //
  4. // Author:
  5. // Sebastien Pouliot <sebastien@ximian.com>
  6. //
  7. // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
  8. // Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Globalization;
  31. using System.Security.Cryptography;
  32. using System.Text;
  33. namespace MediaBrowser.Server.Mono.Security {
  34. public sealed class CryptoConvert {
  35. private CryptoConvert ()
  36. {
  37. }
  38. static private int ToInt32LE (byte [] bytes, int offset)
  39. {
  40. return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset];
  41. }
  42. static private uint ToUInt32LE (byte [] bytes, int offset)
  43. {
  44. return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
  45. }
  46. static private byte [] GetBytesLE (int val)
  47. {
  48. return new byte [] {
  49. (byte) (val & 0xff),
  50. (byte) ((val >> 8) & 0xff),
  51. (byte) ((val >> 16) & 0xff),
  52. (byte) ((val >> 24) & 0xff)
  53. };
  54. }
  55. static private byte[] Trim (byte[] array)
  56. {
  57. for (int i=0; i < array.Length; i++) {
  58. if (array [i] != 0x00) {
  59. byte[] result = new byte [array.Length - i];
  60. Buffer.BlockCopy (array, i, result, 0, result.Length);
  61. return result;
  62. }
  63. }
  64. return null;
  65. }
  66. // convert the key from PRIVATEKEYBLOB to RSA
  67. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/private_key_blobs.asp
  68. // e.g. SNK files, PVK files
  69. static public RSA FromCapiPrivateKeyBlob (byte[] blob)
  70. {
  71. return FromCapiPrivateKeyBlob (blob, 0);
  72. }
  73. static public RSA FromCapiPrivateKeyBlob (byte[] blob, int offset)
  74. {
  75. if (blob == null)
  76. throw new ArgumentNullException ("blob");
  77. if (offset >= blob.Length)
  78. throw new ArgumentException ("blob is too small.");
  79. RSAParameters rsap = new RSAParameters ();
  80. try {
  81. if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
  82. (blob [offset+1] != 0x02) || // Version (0x02)
  83. (blob [offset+2] != 0x00) || // Reserved (word)
  84. (blob [offset+3] != 0x00) ||
  85. (ToUInt32LE (blob, offset+8) != 0x32415352)) // DWORD magic = RSA2
  86. throw new CryptographicException ("Invalid blob header");
  87. // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
  88. // int algId = ToInt32LE (blob, offset+4);
  89. // DWORD bitlen
  90. int bitLen = ToInt32LE (blob, offset+12);
  91. // DWORD public exponent
  92. byte[] exp = new byte [4];
  93. Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
  94. Array.Reverse (exp);
  95. rsap.Exponent = Trim (exp);
  96. int pos = offset+20;
  97. // BYTE modulus[rsapubkey.bitlen/8];
  98. int byteLen = (bitLen >> 3);
  99. rsap.Modulus = new byte [byteLen];
  100. Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
  101. Array.Reverse (rsap.Modulus);
  102. pos += byteLen;
  103. // BYTE prime1[rsapubkey.bitlen/16];
  104. int byteHalfLen = (byteLen >> 1);
  105. rsap.P = new byte [byteHalfLen];
  106. Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen);
  107. Array.Reverse (rsap.P);
  108. pos += byteHalfLen;
  109. // BYTE prime2[rsapubkey.bitlen/16];
  110. rsap.Q = new byte [byteHalfLen];
  111. Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen);
  112. Array.Reverse (rsap.Q);
  113. pos += byteHalfLen;
  114. // BYTE exponent1[rsapubkey.bitlen/16];
  115. rsap.DP = new byte [byteHalfLen];
  116. Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen);
  117. Array.Reverse (rsap.DP);
  118. pos += byteHalfLen;
  119. // BYTE exponent2[rsapubkey.bitlen/16];
  120. rsap.DQ = new byte [byteHalfLen];
  121. Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen);
  122. Array.Reverse (rsap.DQ);
  123. pos += byteHalfLen;
  124. // BYTE coefficient[rsapubkey.bitlen/16];
  125. rsap.InverseQ = new byte [byteHalfLen];
  126. Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen);
  127. Array.Reverse (rsap.InverseQ);
  128. pos += byteHalfLen;
  129. // ok, this is hackish but CryptoAPI support it so...
  130. // note: only works because CRT is used by default
  131. // http://bugzilla.ximian.com/show_bug.cgi?id=57941
  132. rsap.D = new byte [byteLen]; // must be allocated
  133. if (pos + byteLen + offset <= blob.Length) {
  134. // BYTE privateExponent[rsapubkey.bitlen/8];
  135. Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
  136. Array.Reverse (rsap.D);
  137. }
  138. }
  139. catch (Exception e) {
  140. throw new CryptographicException ("Invalid blob.", e);
  141. }
  142. RSA rsa = null;
  143. try
  144. {
  145. rsa = RSA.Create();
  146. rsa.ImportParameters(rsap);
  147. }
  148. catch (CryptographicException ce)
  149. {
  150. // this may cause problem when this code is run under
  151. // the SYSTEM identity on Windows (e.g. ASP.NET). See
  152. // http://bugzilla.ximian.com/show_bug.cgi?id=77559
  153. try
  154. {
  155. CspParameters csp = new CspParameters();
  156. csp.Flags = CspProviderFlags.UseMachineKeyStore;
  157. rsa = new RSACryptoServiceProvider(csp);
  158. rsa.ImportParameters(rsap);
  159. }
  160. catch
  161. {
  162. // rethrow original, not the later, exception if this fails
  163. throw ce;
  164. }
  165. }
  166. return rsa;
  167. }
  168. static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob)
  169. {
  170. return FromCapiPrivateKeyBlobDSA (blob, 0);
  171. }
  172. static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob, int offset)
  173. {
  174. if (blob == null)
  175. throw new ArgumentNullException ("blob");
  176. if (offset >= blob.Length)
  177. throw new ArgumentException ("blob is too small.");
  178. DSAParameters dsap = new DSAParameters ();
  179. try {
  180. if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
  181. (blob [offset + 1] != 0x02) || // Version (0x02)
  182. (blob [offset + 2] != 0x00) || // Reserved (word)
  183. (blob [offset + 3] != 0x00) ||
  184. (ToUInt32LE (blob, offset + 8) != 0x32535344)) // DWORD magic
  185. throw new CryptographicException ("Invalid blob header");
  186. int bitlen = ToInt32LE (blob, offset + 12);
  187. int bytelen = bitlen >> 3;
  188. int pos = offset + 16;
  189. dsap.P = new byte [bytelen];
  190. Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
  191. Array.Reverse (dsap.P);
  192. pos += bytelen;
  193. dsap.Q = new byte [20];
  194. Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
  195. Array.Reverse (dsap.Q);
  196. pos += 20;
  197. dsap.G = new byte [bytelen];
  198. Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
  199. Array.Reverse (dsap.G);
  200. pos += bytelen;
  201. dsap.X = new byte [20];
  202. Buffer.BlockCopy (blob, pos, dsap.X, 0, 20);
  203. Array.Reverse (dsap.X);
  204. pos += 20;
  205. dsap.Counter = ToInt32LE (blob, pos);
  206. pos += 4;
  207. dsap.Seed = new byte [20];
  208. Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
  209. Array.Reverse (dsap.Seed);
  210. pos += 20;
  211. }
  212. catch (Exception e) {
  213. throw new CryptographicException ("Invalid blob.", e);
  214. }
  215. DSA dsa = null;
  216. try
  217. {
  218. dsa = (DSA)DSA.Create();
  219. dsa.ImportParameters(dsap);
  220. }
  221. catch (CryptographicException ce)
  222. {
  223. // this may cause problem when this code is run under
  224. // the SYSTEM identity on Windows (e.g. ASP.NET). See
  225. // http://bugzilla.ximian.com/show_bug.cgi?id=77559
  226. try
  227. {
  228. CspParameters csp = new CspParameters();
  229. csp.Flags = CspProviderFlags.UseMachineKeyStore;
  230. dsa = new DSACryptoServiceProvider(csp);
  231. dsa.ImportParameters(dsap);
  232. }
  233. catch
  234. {
  235. // rethrow original, not the later, exception if this fails
  236. throw ce;
  237. }
  238. }
  239. return dsa;
  240. }
  241. static public byte[] ToCapiPrivateKeyBlob (RSA rsa)
  242. {
  243. RSAParameters p = rsa.ExportParameters (true);
  244. int keyLength = p.Modulus.Length; // in bytes
  245. byte[] blob = new byte [20 + (keyLength << 2) + (keyLength >> 1)];
  246. blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
  247. blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
  248. // [2], [3] // RESERVED - Always 0
  249. blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
  250. blob [8] = 0x52; // Magic - RSA2 (ASCII in hex)
  251. blob [9] = 0x53;
  252. blob [10] = 0x41;
  253. blob [11] = 0x32;
  254. byte[] bitlen = GetBytesLE (keyLength << 3);
  255. blob [12] = bitlen [0]; // bitlen
  256. blob [13] = bitlen [1];
  257. blob [14] = bitlen [2];
  258. blob [15] = bitlen [3];
  259. // public exponent (DWORD)
  260. int pos = 16;
  261. int n = p.Exponent.Length;
  262. while (n > 0)
  263. blob [pos++] = p.Exponent [--n];
  264. // modulus
  265. pos = 20;
  266. byte[] part = p.Modulus;
  267. int len = part.Length;
  268. Array.Reverse (part, 0, len);
  269. Buffer.BlockCopy (part, 0, blob, pos, len);
  270. pos += len;
  271. // private key
  272. part = p.P;
  273. len = part.Length;
  274. Array.Reverse (part, 0, len);
  275. Buffer.BlockCopy (part, 0, blob, pos, len);
  276. pos += len;
  277. part = p.Q;
  278. len = part.Length;
  279. Array.Reverse (part, 0, len);
  280. Buffer.BlockCopy (part, 0, blob, pos, len);
  281. pos += len;
  282. part = p.DP;
  283. len = part.Length;
  284. Array.Reverse (part, 0, len);
  285. Buffer.BlockCopy (part, 0, blob, pos, len);
  286. pos += len;
  287. part = p.DQ;
  288. len = part.Length;
  289. Array.Reverse (part, 0, len);
  290. Buffer.BlockCopy (part, 0, blob, pos, len);
  291. pos += len;
  292. part = p.InverseQ;
  293. len = part.Length;
  294. Array.Reverse (part, 0, len);
  295. Buffer.BlockCopy (part, 0, blob, pos, len);
  296. pos += len;
  297. part = p.D;
  298. len = part.Length;
  299. Array.Reverse (part, 0, len);
  300. Buffer.BlockCopy (part, 0, blob, pos, len);
  301. return blob;
  302. }
  303. static public byte[] ToCapiPrivateKeyBlob (DSA dsa)
  304. {
  305. DSAParameters p = dsa.ExportParameters (true);
  306. int keyLength = p.P.Length; // in bytes
  307. // header + P + Q + G + X + count + seed
  308. byte[] blob = new byte [16 + keyLength + 20 + keyLength + 20 + 4 + 20];
  309. blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
  310. blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
  311. // [2], [3] // RESERVED - Always 0
  312. blob [5] = 0x22; // ALGID
  313. blob [8] = 0x44; // Magic
  314. blob [9] = 0x53;
  315. blob [10] = 0x53;
  316. blob [11] = 0x32;
  317. byte[] bitlen = GetBytesLE (keyLength << 3);
  318. blob [12] = bitlen [0];
  319. blob [13] = bitlen [1];
  320. blob [14] = bitlen [2];
  321. blob [15] = bitlen [3];
  322. int pos = 16;
  323. byte[] part = p.P;
  324. Array.Reverse (part);
  325. Buffer.BlockCopy (part, 0, blob, pos, keyLength);
  326. pos += keyLength;
  327. part = p.Q;
  328. Array.Reverse (part);
  329. Buffer.BlockCopy (part, 0, blob, pos, 20);
  330. pos += 20;
  331. part = p.G;
  332. Array.Reverse (part);
  333. Buffer.BlockCopy (part, 0, blob, pos, keyLength);
  334. pos += keyLength;
  335. part = p.X;
  336. Array.Reverse (part);
  337. Buffer.BlockCopy (part, 0, blob, pos, 20);
  338. pos += 20;
  339. Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
  340. pos += 4;
  341. part = p.Seed;
  342. Array.Reverse (part);
  343. Buffer.BlockCopy (part, 0, blob, pos, 20);
  344. return blob;
  345. }
  346. static public RSA FromCapiPublicKeyBlob (byte[] blob)
  347. {
  348. return FromCapiPublicKeyBlob (blob, 0);
  349. }
  350. static public RSA FromCapiPublicKeyBlob (byte[] blob, int offset)
  351. {
  352. if (blob == null)
  353. throw new ArgumentNullException ("blob");
  354. if (offset >= blob.Length)
  355. throw new ArgumentException ("blob is too small.");
  356. try {
  357. if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
  358. (blob [offset+1] != 0x02) || // Version (0x02)
  359. (blob [offset+2] != 0x00) || // Reserved (word)
  360. (blob [offset+3] != 0x00) ||
  361. (ToUInt32LE (blob, offset+8) != 0x31415352)) // DWORD magic = RSA1
  362. throw new CryptographicException ("Invalid blob header");
  363. // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
  364. // int algId = ToInt32LE (blob, offset+4);
  365. // DWORD bitlen
  366. int bitLen = ToInt32LE (blob, offset+12);
  367. // DWORD public exponent
  368. RSAParameters rsap = new RSAParameters ();
  369. rsap.Exponent = new byte [3];
  370. rsap.Exponent [0] = blob [offset+18];
  371. rsap.Exponent [1] = blob [offset+17];
  372. rsap.Exponent [2] = blob [offset+16];
  373. int pos = offset+20;
  374. // BYTE modulus[rsapubkey.bitlen/8];
  375. int byteLen = (bitLen >> 3);
  376. rsap.Modulus = new byte [byteLen];
  377. Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
  378. Array.Reverse (rsap.Modulus);
  379. RSA rsa = null;
  380. try
  381. {
  382. rsa = RSA.Create();
  383. rsa.ImportParameters(rsap);
  384. }
  385. catch (CryptographicException)
  386. {
  387. // this may cause problem when this code is run under
  388. // the SYSTEM identity on Windows (e.g. ASP.NET). See
  389. // http://bugzilla.ximian.com/show_bug.cgi?id=77559
  390. CspParameters csp = new CspParameters();
  391. csp.Flags = CspProviderFlags.UseMachineKeyStore;
  392. rsa = new RSACryptoServiceProvider(csp);
  393. rsa.ImportParameters(rsap);
  394. }
  395. return rsa;
  396. }
  397. catch (Exception e) {
  398. throw new CryptographicException ("Invalid blob.", e);
  399. }
  400. }
  401. static public DSA FromCapiPublicKeyBlobDSA (byte[] blob)
  402. {
  403. return FromCapiPublicKeyBlobDSA (blob, 0);
  404. }
  405. static public DSA FromCapiPublicKeyBlobDSA (byte[] blob, int offset)
  406. {
  407. if (blob == null)
  408. throw new ArgumentNullException ("blob");
  409. if (offset >= blob.Length)
  410. throw new ArgumentException ("blob is too small.");
  411. try {
  412. if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
  413. (blob [offset + 1] != 0x02) || // Version (0x02)
  414. (blob [offset + 2] != 0x00) || // Reserved (word)
  415. (blob [offset + 3] != 0x00) ||
  416. (ToUInt32LE (blob, offset + 8) != 0x31535344)) // DWORD magic
  417. throw new CryptographicException ("Invalid blob header");
  418. int bitlen = ToInt32LE (blob, offset + 12);
  419. DSAParameters dsap = new DSAParameters ();
  420. int bytelen = bitlen >> 3;
  421. int pos = offset + 16;
  422. dsap.P = new byte [bytelen];
  423. Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
  424. Array.Reverse (dsap.P);
  425. pos += bytelen;
  426. dsap.Q = new byte [20];
  427. Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
  428. Array.Reverse (dsap.Q);
  429. pos += 20;
  430. dsap.G = new byte [bytelen];
  431. Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
  432. Array.Reverse (dsap.G);
  433. pos += bytelen;
  434. dsap.Y = new byte [bytelen];
  435. Buffer.BlockCopy (blob, pos, dsap.Y, 0, bytelen);
  436. Array.Reverse (dsap.Y);
  437. pos += bytelen;
  438. dsap.Counter = ToInt32LE (blob, pos);
  439. pos += 4;
  440. dsap.Seed = new byte [20];
  441. Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
  442. Array.Reverse (dsap.Seed);
  443. pos += 20;
  444. DSA dsa = (DSA)DSA.Create ();
  445. dsa.ImportParameters (dsap);
  446. return dsa;
  447. }
  448. catch (Exception e) {
  449. throw new CryptographicException ("Invalid blob.", e);
  450. }
  451. }
  452. static public byte[] ToCapiPublicKeyBlob (RSA rsa)
  453. {
  454. RSAParameters p = rsa.ExportParameters (false);
  455. int keyLength = p.Modulus.Length; // in bytes
  456. byte[] blob = new byte [20 + keyLength];
  457. blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
  458. blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
  459. // [2], [3] // RESERVED - Always 0
  460. blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
  461. blob [8] = 0x52; // Magic - RSA1 (ASCII in hex)
  462. blob [9] = 0x53;
  463. blob [10] = 0x41;
  464. blob [11] = 0x31;
  465. byte[] bitlen = GetBytesLE (keyLength << 3);
  466. blob [12] = bitlen [0]; // bitlen
  467. blob [13] = bitlen [1];
  468. blob [14] = bitlen [2];
  469. blob [15] = bitlen [3];
  470. // public exponent (DWORD)
  471. int pos = 16;
  472. int n = p.Exponent.Length;
  473. while (n > 0)
  474. blob [pos++] = p.Exponent [--n];
  475. // modulus
  476. pos = 20;
  477. byte[] part = p.Modulus;
  478. int len = part.Length;
  479. Array.Reverse (part, 0, len);
  480. Buffer.BlockCopy (part, 0, blob, pos, len);
  481. pos += len;
  482. return blob;
  483. }
  484. static public byte[] ToCapiPublicKeyBlob (DSA dsa)
  485. {
  486. DSAParameters p = dsa.ExportParameters (false);
  487. int keyLength = p.P.Length; // in bytes
  488. // header + P + Q + G + Y + count + seed
  489. byte[] blob = new byte [16 + keyLength + 20 + keyLength + keyLength + 4 + 20];
  490. blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
  491. blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
  492. // [2], [3] // RESERVED - Always 0
  493. blob [5] = 0x22; // ALGID
  494. blob [8] = 0x44; // Magic
  495. blob [9] = 0x53;
  496. blob [10] = 0x53;
  497. blob [11] = 0x31;
  498. byte[] bitlen = GetBytesLE (keyLength << 3);
  499. blob [12] = bitlen [0];
  500. blob [13] = bitlen [1];
  501. blob [14] = bitlen [2];
  502. blob [15] = bitlen [3];
  503. int pos = 16;
  504. byte[] part;
  505. part = p.P;
  506. Array.Reverse (part);
  507. Buffer.BlockCopy (part, 0, blob, pos, keyLength);
  508. pos += keyLength;
  509. part = p.Q;
  510. Array.Reverse (part);
  511. Buffer.BlockCopy (part, 0, blob, pos, 20);
  512. pos += 20;
  513. part = p.G;
  514. Array.Reverse (part);
  515. Buffer.BlockCopy (part, 0, blob, pos, keyLength);
  516. pos += keyLength;
  517. part = p.Y;
  518. Array.Reverse (part);
  519. Buffer.BlockCopy (part, 0, blob, pos, keyLength);
  520. pos += keyLength;
  521. Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
  522. pos += 4;
  523. part = p.Seed;
  524. Array.Reverse (part);
  525. Buffer.BlockCopy (part, 0, blob, pos, 20);
  526. return blob;
  527. }
  528. // PRIVATEKEYBLOB
  529. // PUBLICKEYBLOB
  530. static public RSA FromCapiKeyBlob (byte[] blob)
  531. {
  532. return FromCapiKeyBlob (blob, 0);
  533. }
  534. static public RSA FromCapiKeyBlob (byte[] blob, int offset)
  535. {
  536. if (blob == null)
  537. throw new ArgumentNullException ("blob");
  538. if (offset >= blob.Length)
  539. throw new ArgumentException ("blob is too small.");
  540. switch (blob [offset]) {
  541. case 0x00:
  542. // this could be a public key inside an header
  543. // like "sn -e" would produce
  544. if (blob [offset + 12] == 0x06) {
  545. return FromCapiPublicKeyBlob (blob, offset + 12);
  546. }
  547. break;
  548. case 0x06:
  549. return FromCapiPublicKeyBlob (blob, offset);
  550. case 0x07:
  551. return FromCapiPrivateKeyBlob (blob, offset);
  552. }
  553. throw new CryptographicException ("Unknown blob format.");
  554. }
  555. static public DSA FromCapiKeyBlobDSA (byte[] blob)
  556. {
  557. return FromCapiKeyBlobDSA (blob, 0);
  558. }
  559. static public DSA FromCapiKeyBlobDSA (byte[] blob, int offset)
  560. {
  561. if (blob == null)
  562. throw new ArgumentNullException ("blob");
  563. if (offset >= blob.Length)
  564. throw new ArgumentException ("blob is too small.");
  565. switch (blob [offset]) {
  566. case 0x06:
  567. return FromCapiPublicKeyBlobDSA (blob, offset);
  568. case 0x07:
  569. return FromCapiPrivateKeyBlobDSA (blob, offset);
  570. }
  571. throw new CryptographicException ("Unknown blob format.");
  572. }
  573. static public byte[] ToCapiKeyBlob (AsymmetricAlgorithm keypair, bool includePrivateKey)
  574. {
  575. if (keypair == null)
  576. throw new ArgumentNullException ("keypair");
  577. // check between RSA and DSA (and potentially others like DH)
  578. if (keypair is RSA)
  579. return ToCapiKeyBlob ((RSA)keypair, includePrivateKey);
  580. else if (keypair is DSA)
  581. return ToCapiKeyBlob ((DSA)keypair, includePrivateKey);
  582. else
  583. return null; // TODO
  584. }
  585. static public byte[] ToCapiKeyBlob (RSA rsa, bool includePrivateKey)
  586. {
  587. if (rsa == null)
  588. throw new ArgumentNullException ("rsa");
  589. if (includePrivateKey)
  590. return ToCapiPrivateKeyBlob (rsa);
  591. else
  592. return ToCapiPublicKeyBlob (rsa);
  593. }
  594. static public byte[] ToCapiKeyBlob (DSA dsa, bool includePrivateKey)
  595. {
  596. if (dsa == null)
  597. throw new ArgumentNullException ("dsa");
  598. if (includePrivateKey)
  599. return ToCapiPrivateKeyBlob (dsa);
  600. else
  601. return ToCapiPublicKeyBlob (dsa);
  602. }
  603. static public string ToHex (byte[] input)
  604. {
  605. if (input == null)
  606. return null;
  607. StringBuilder sb = new StringBuilder (input.Length * 2);
  608. foreach (byte b in input) {
  609. sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture));
  610. }
  611. return sb.ToString ();
  612. }
  613. static private byte FromHexChar (char c)
  614. {
  615. if ((c >= 'a') && (c <= 'f'))
  616. return (byte) (c - 'a' + 10);
  617. if ((c >= 'A') && (c <= 'F'))
  618. return (byte) (c - 'A' + 10);
  619. if ((c >= '0') && (c <= '9'))
  620. return (byte) (c - '0');
  621. throw new ArgumentException ("invalid hex char");
  622. }
  623. static public byte[] FromHex (string hex)
  624. {
  625. if (hex == null)
  626. return null;
  627. if ((hex.Length & 0x1) == 0x1)
  628. throw new ArgumentException ("Length must be a multiple of 2");
  629. byte[] result = new byte [hex.Length >> 1];
  630. int n = 0;
  631. int i = 0;
  632. while (n < result.Length) {
  633. result [n] = (byte) (FromHexChar (hex [i++]) << 4);
  634. result [n++] += FromHexChar (hex [i++]);
  635. }
  636. return result;
  637. }
  638. }
  639. }