CryptoConvert.cs 21 KB

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