PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/Model/Bitcoin.cs

https://github.com/aantonop/Bitcoin-Address-Utility
C# | 449 lines | 317 code | 90 blank | 42 comment | 138 complexity | 648a54b0816fb113d675a7d8c74390a0 MD5 | raw file
  1. // Copyright 2012 Mike Caldwell (Casascius)
  2. // This file is part of Bitcoin Address Utility.
  3. // Bitcoin Address Utility is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. // Bitcoin Address Utility is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU General Public License for more details.
  11. // You should have received a copy of the GNU General Public License
  12. // along with Bitcoin Address Utility. If not, see http://www.gnu.org/licenses/.
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Text;
  17. using System.Drawing;
  18. using System.Security.Cryptography;
  19. using System.IO;
  20. using Org.BouncyCastle.Asn1;
  21. using Org.BouncyCastle.Crypto;
  22. using Org.BouncyCastle.Crypto.Digests;
  23. using Org.BouncyCastle.Crypto.Generators;
  24. using Org.BouncyCastle.Crypto.Parameters;
  25. using Org.BouncyCastle.Security;
  26. using Org.BouncyCastle.Math.EC;
  27. namespace Casascius.Bitcoin {
  28. public class Util {
  29. public static string PassphraseToPrivHex(string passphrase) {
  30. return ByteArrayToString(ComputeSha256(passphrase));
  31. }
  32. public static string ByteArrayToBase58Check(byte[] ba) {
  33. byte[] bb = new byte[ba.Length + 4];
  34. Array.Copy(ba, bb, ba.Length);
  35. Sha256Digest bcsha256a = new Sha256Digest();
  36. bcsha256a.BlockUpdate(ba, 0, ba.Length);
  37. byte[] thehash = new byte[32];
  38. bcsha256a.DoFinal(thehash, 0);
  39. bcsha256a.BlockUpdate(thehash, 0, 32);
  40. bcsha256a.DoFinal(thehash, 0);
  41. for (int i = 0; i < 4; i++) bb[ba.Length + i] = thehash[i];
  42. return Base58.FromByteArray(bb);
  43. }
  44. public static byte[] ValidateAndGetHexPublicKey(string PubHex) {
  45. byte[] hex = GetHexBytes(PubHex, 64);
  46. if (hex == null || hex.Length < 64 || hex.Length > 65) {
  47. throw new ApplicationException("Hex is not 64 or 65 bytes.");
  48. }
  49. // if leading 00, change it to 0x80
  50. if (hex.Length == 65) {
  51. if (hex[0] == 0 || hex[0] == 4) {
  52. hex[0] = 4;
  53. } else {
  54. throw new ApplicationException("Not a valid public key");
  55. }
  56. }
  57. // add 0x80 byte if not present
  58. if (hex.Length == 64) {
  59. byte[] hex2 = new byte[65];
  60. Array.Copy(hex, 0, hex2, 1, 64);
  61. hex2[0] = 4;
  62. hex = hex2;
  63. }
  64. return hex;
  65. }
  66. public static byte[] ValidateAndGetHexPublicHash(string PubHash) {
  67. byte[] hex = GetHexBytes(PubHash, 20);
  68. if (hex == null || hex.Length != 20) {
  69. throw new ApplicationException("Hex is not 20 bytes.");
  70. }
  71. return hex;
  72. }
  73. public static byte[] ValidateAndGetHexPrivateKey(byte leadingbyte, string PrivHex, int desiredByteCount) {
  74. if (desiredByteCount != 32 && desiredByteCount != 33) throw new ApplicationException("desiredByteCount must be 32 or 33");
  75. byte[] hex = GetHexBytes(PrivHex, 32);
  76. if (hex == null || hex.Length < 32 || hex.Length > 33) {
  77. throw new ApplicationException("Hex is not 32 or 33 bytes.");
  78. }
  79. // if leading 00, change it to 0x80
  80. if (hex.Length == 33) {
  81. if (hex[0] == 0 || hex[0] == 0x80) {
  82. hex[0] = 0x80;
  83. } else {
  84. throw new ApplicationException("Not a valid private key");
  85. }
  86. }
  87. // add 0x80 byte if not present
  88. if (hex.Length == 32 && desiredByteCount==33) {
  89. byte[] hex2 = new byte[33];
  90. Array.Copy(hex, 0, hex2, 1, 32);
  91. hex2[0] = 0x80;
  92. hex = hex2;
  93. }
  94. if (desiredByteCount==33) hex[0] = leadingbyte;
  95. if (desiredByteCount == 32 && hex.Length == 33) {
  96. byte[] hex2 = new byte[33];
  97. Array.Copy(hex, 1, hex2, 0, 32);
  98. hex = hex2;
  99. }
  100. return hex;
  101. }
  102. /// <summary>
  103. /// Trims whitespace from within and outside string.
  104. /// Whitespace is anything non-alphanumeric that may have been inserted into a string.
  105. /// </summary>
  106. public static string Base58Trim(string base58) {
  107. char[] strin = base58.ToCharArray();
  108. char[] cc = new char[base58.Length];
  109. int pos = 0;
  110. for (int i = 0; i < base58.Length; i++) {
  111. char c = strin[i];
  112. if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
  113. cc[pos++] = c;
  114. }
  115. }
  116. return new String(cc, 0, pos);
  117. }
  118. /// <summary>
  119. /// Converts a base-58 string to a byte array, checking the checksum, and
  120. /// returning null if it wasn't valid. Appending "?" to the end of the string skips
  121. /// the checksum calculation, but still strips the four checksum bytes from the
  122. /// result.
  123. /// </summary>
  124. public static byte[] Base58CheckToByteArray(string base58) {
  125. bool IgnoreChecksum = false;
  126. if (base58.EndsWith("?")) {
  127. IgnoreChecksum = true;
  128. base58 = base58.Substring(0, base58.Length - 1);
  129. }
  130. byte[] bb = Base58.ToByteArray(base58);
  131. if (bb == null || bb.Length < 4) return null;
  132. if (IgnoreChecksum == false) {
  133. Sha256Digest bcsha256a = new Sha256Digest();
  134. bcsha256a.BlockUpdate(bb, 0, bb.Length - 4);
  135. byte[] checksum = new byte[32]; //sha256.ComputeHash(bb, 0, bb.Length - 4);
  136. bcsha256a.DoFinal(checksum, 0);
  137. bcsha256a.BlockUpdate(checksum, 0, 32);
  138. bcsha256a.DoFinal(checksum, 0);
  139. for (int i = 0; i < 4; i++) {
  140. if (checksum[i] != bb[bb.Length - 4 + i]) return null;
  141. }
  142. }
  143. byte[] rv = new byte[bb.Length - 4];
  144. Array.Copy(bb, 0, rv, 0, bb.Length - 4);
  145. return rv;
  146. }
  147. public static string ByteArrayToString(byte[] ba) {
  148. return ByteArrayToString(ba, 0, ba.Length);
  149. }
  150. public static string ByteArrayToString(byte[] ba, int offset, int count) {
  151. string rv = "";
  152. int usedcount = 0;
  153. for (int i = offset; usedcount < count; i++, usedcount++) {
  154. rv += String.Format("{0:X2}", ba[i]) + " ";
  155. }
  156. return rv;
  157. }
  158. public static byte[] GetHexBytes(string source, int minimum) {
  159. byte[] hex = HexStringToBytes(source);
  160. if (hex == null) return null;
  161. // assume leading zeroes if we're short a few bytes
  162. if (hex.Length > (minimum - 6) && hex.Length < minimum) {
  163. byte[] hex2 = new byte[minimum];
  164. Array.Copy(hex, 0, hex2, minimum - hex.Length, hex.Length);
  165. hex = hex2;
  166. }
  167. // clip off one overhanging leading zero if present
  168. if (hex.Length == minimum + 1 && hex[0] == 0) {
  169. byte[] hex2 = new byte[minimum];
  170. Array.Copy(hex, 1, hex2, 0, minimum);
  171. hex = hex2;
  172. }
  173. return hex;
  174. }
  175. /// <summary>
  176. /// Converts a hex string to bytes. Hex chars can optionally be space-delimited, otherwise,
  177. /// any two contiguous hex chars are considered to be a byte. If testingForValidHex==true,
  178. /// then if any invalid characters are found, the function returns null instead of bytes.
  179. /// </summary>
  180. public static byte[] HexStringToBytes(string source, bool testingForValidHex=false) {
  181. List<byte> bytes = new List<byte>();
  182. bool gotFirstChar = false;
  183. byte accum = 0;
  184. foreach (char c in source.ToCharArray()) {
  185. if (c == ' ' || c == '-' || c == ':') {
  186. // if we got a space, then accept it as the end if we have 1 character.
  187. if (gotFirstChar) {
  188. bytes.Add(accum);
  189. accum = 0;
  190. gotFirstChar = false;
  191. }
  192. } else if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
  193. // get the character's value
  194. byte v = (byte)(c - 0x30);
  195. if (c >= 'A' && c <= 'F') v = (byte)(c + 0x0a - 'A');
  196. if (c >= 'a' && c <= 'f') v = (byte)(c + 0x0a - 'a');
  197. if (gotFirstChar == false) {
  198. gotFirstChar = true;
  199. accum = v;
  200. } else {
  201. accum <<= 4;
  202. accum += v;
  203. bytes.Add(accum);
  204. accum = 0;
  205. gotFirstChar = false;
  206. }
  207. } else {
  208. if (testingForValidHex) return null;
  209. }
  210. }
  211. if (gotFirstChar) bytes.Add(accum);
  212. return bytes.ToArray();
  213. }
  214. public static string PrivHexToPubHex(string PrivHex) {
  215. var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
  216. return PrivHexToPubHex(PrivHex, ps.G);
  217. }
  218. public static string PrivHexToPubHex(string PrivHex, ECPoint point) {
  219. byte[] hex = ValidateAndGetHexPrivateKey(0x00, PrivHex, 33);
  220. if (hex == null) throw new ApplicationException("Invalid private hex key");
  221. Org.BouncyCastle.Math.BigInteger Db = new Org.BouncyCastle.Math.BigInteger(hex);
  222. ECPoint dd = point.Multiply(Db);
  223. byte[] pubaddr = PubKeyToByteArray(dd);
  224. return ByteArrayToString(pubaddr);
  225. }
  226. public static ECPoint PrivHexToPubKey(string PrivHex) {
  227. byte[] hex = ValidateAndGetHexPrivateKey(0x00, PrivHex, 33);
  228. if (hex == null) throw new ApplicationException("Invalid private hex key");
  229. Org.BouncyCastle.Math.BigInteger Db = new Org.BouncyCastle.Math.BigInteger(1, hex);
  230. var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
  231. return ps.G.Multiply(Db);
  232. }
  233. public static ECPoint PrivKeyToPubKey(byte[] PrivKey) {
  234. if (PrivKey == null || PrivKey.Length > 32) throw new ApplicationException("Invalid private hex key");
  235. Org.BouncyCastle.Math.BigInteger Db = new Org.BouncyCastle.Math.BigInteger(1, PrivKey);
  236. var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
  237. return ps.G.Multiply(Db);
  238. }
  239. public static byte[] PubKeyToByteArray(ECPoint point) {
  240. byte[] pubaddr = new byte[65];
  241. byte[] Y = point.Y.ToBigInteger().ToByteArray();
  242. Array.Copy(Y, 0, pubaddr, 64 - Y.Length + 1, Y.Length);
  243. byte[] X = point.X.ToBigInteger().ToByteArray();
  244. Array.Copy(X, 0, pubaddr, 32 - X.Length + 1, X.Length);
  245. pubaddr[0] = 4;
  246. return pubaddr;
  247. }
  248. public static string PubHexToPubHash(string PubHex) {
  249. byte[] hex = ValidateAndGetHexPublicKey(PubHex);
  250. if (hex == null) throw new ApplicationException("Invalid public hex key");
  251. return PubHexToPubHash(hex);
  252. }
  253. public static string PubHexToPubHash(byte[] PubHex) {
  254. byte[] shaofpubkey = ComputeSha256(PubHex);
  255. RIPEMD160 rip = System.Security.Cryptography.RIPEMD160.Create();
  256. byte[] ripofpubkey = rip.ComputeHash(shaofpubkey);
  257. return ByteArrayToString(ripofpubkey);
  258. }
  259. public static string PubHashToAddress(string PubHash, string AddressType) {
  260. byte[] hex = ValidateAndGetHexPublicHash(PubHash);
  261. if (hex == null) throw new ApplicationException("Invalid public hex key");
  262. byte[] hex2 = new byte[21];
  263. Array.Copy(hex, 0, hex2, 1, 20);
  264. int cointype = 0;
  265. if (Int32.TryParse(AddressType, out cointype) == false) cointype = 0;
  266. if (AddressType == "Testnet") cointype = 111;
  267. if (AddressType == "Namecoin") cointype = 52;
  268. if (AddressType == "Litecoin") cointype = 48;
  269. hex2[0] = (byte)(cointype & 0xff);
  270. return ByteArrayToBase58Check(hex2);
  271. }
  272. public static bool PassphraseTooSimple(string passphrase) {
  273. int Lowercase = 0, Uppercase = 0, Numbers = 0, Symbols = 0, Spaces = 0;
  274. foreach (char c in passphrase.ToCharArray()) {
  275. if (c >= 'a' && c <= 'z') {
  276. Lowercase++;
  277. } else if (c >= 'A' && c <= 'Z') {
  278. Uppercase++;
  279. } else if (c >= '0' && c <= '9') {
  280. Numbers++;
  281. } else if (c == ' ') {
  282. Spaces++;
  283. } else {
  284. Symbols++;
  285. }
  286. }
  287. // let mini private keys through - they won't contain words, they are nonsense characters, so their entropy is a bit better per character
  288. if (MiniKeyPair.IsValidMiniKey(passphrase) != 1) return false;
  289. if (passphrase.Length < 30 && (Lowercase < 10 || Uppercase < 3 || Numbers < 2 || Symbols < 2)) {
  290. return true;
  291. }
  292. return false;
  293. }
  294. public static byte[] ComputeSha256(string ofwhat) {
  295. UTF8Encoding utf8 = new UTF8Encoding(false);
  296. return ComputeSha256(utf8.GetBytes(ofwhat));
  297. }
  298. public static byte[] ComputeSha256(byte[] ofwhat) {
  299. Sha256Digest sha256 = new Sha256Digest();
  300. sha256.BlockUpdate(ofwhat, 0, ofwhat.Length);
  301. byte[] rv = new byte[32];
  302. sha256.DoFinal(rv, 0);
  303. return rv;
  304. }
  305. public static byte[] ComputeDoubleSha256(string ofwhat) {
  306. UTF8Encoding utf8 = new UTF8Encoding(false);
  307. return ComputeDoubleSha256(utf8.GetBytes(ofwhat));
  308. }
  309. public static byte[] ComputeDoubleSha256(byte[] ofwhat) {
  310. Sha256Digest sha256 = new Sha256Digest();
  311. sha256.BlockUpdate(ofwhat, 0, ofwhat.Length);
  312. byte[] rv = new byte[32];
  313. sha256.DoFinal(rv, 0);
  314. sha256.BlockUpdate(rv, 0, rv.Length);
  315. sha256.DoFinal(rv, 0);
  316. return rv;
  317. }
  318. public static Int64 nonce = 0;
  319. public static byte[] Force32Bytes(byte[] inbytes) {
  320. if (inbytes.Length == 32) return inbytes;
  321. byte[] rv = new byte[32];
  322. if (inbytes.Length > 32) {
  323. Array.Copy(inbytes, inbytes.Length - 32, rv, 0, 32);
  324. } else {
  325. Array.Copy(inbytes, 0, rv, 32 - inbytes.Length, inbytes.Length);
  326. }
  327. return rv;
  328. }
  329. /// <summary>
  330. /// Extension for cloning a byte array
  331. /// </summary>
  332. public static byte[] CloneByteArray(byte[] ba) {
  333. if (ba == null) return null;
  334. byte[] copy = new byte[ba.Length];
  335. Array.Copy(ba, copy, ba.Length);
  336. return copy;
  337. }
  338. /// <summary>
  339. /// Extension for cloning a portion of a byte array
  340. /// </summary>
  341. public static byte[] CloneByteArray(byte[] ba, int offset, int length) {
  342. if (ba == null) return null;
  343. byte[] copy = new byte[length];
  344. Array.Copy(ba, offset, copy, 0, length);
  345. return copy;
  346. }
  347. public static byte[] ConcatenateByteArrays(params byte[][] bytearrays) {
  348. int totalLength = 0;
  349. for (int i = 0; i < bytearrays.Length; i++) totalLength += bytearrays[i].Length;
  350. byte[] rv = new byte[totalLength];
  351. int idx = 0;
  352. for (int i = 0; i < bytearrays.Length; i++) {
  353. Array.Copy(bytearrays[i], 0, rv, idx, bytearrays[i].Length);
  354. idx += bytearrays[i].Length;
  355. }
  356. return rv;
  357. }
  358. }
  359. }