Forum Home
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Popular

    BIP38 - Encrypting Feathercoin Private Keys

    Technical Development
    7
    10
    3911
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C
      chrisj Regular Member last edited by

      There is another company in addition to Netnerd who is producing collectable Feathercoin Wallets: http://finitebydesign.net/

      One of my favourite features in Bitcoin is BIP38 which allows you to encrypt your private keys. This could be really good for collectable companies as they can get customers to send in their own private keys without worrying about trust.

      What’s it going to take to get this feature in to Feathercoin?

      1 Reply Last reply Reply Quote 1
      • wrapper
        wrapper Moderators last edited by

        Interesting : Bip 38

        http://www.youtube.com/watch?v=ksK9_PAWfz0

        1 Reply Last reply Reply Quote 0
        • E
          estrabd Regular Member last edited by

          [quote name=“chrisj” post=“58458” timestamp=“1392120022”]
          There is another company in addition to Netnerd who is producing collectable Feathercoin Wallets: http://finitebydesign.net/

          One of my favourite features in Bitcoin is BIP38 which allows you to encrypt your private keys. This could be really good for collectable companies as they can get customers to send in their own private keys without worrying about trust.

          What’s it going to take to get this feature in to Feathercoin?
          [/quote]

          This would be pretty great. Where can we see the dev process in action? Is there a mailing list? Not sure, but it looks like GH is used as a dumping ground and not really a place to view or participate in works-in-progress.

          1 Reply Last reply Reply Quote 1
          • MrWyrm
            MrWyrm administrators last edited by

            This sounds interesting.

            Like what I do: 6uuy6isbrW1SBF191Bzgui1gWxPdNKx2PB

            1 Reply Last reply Reply Quote 0
            • E
              estrabd Regular Member last edited by

              I am sure the concepts can be easily transferred - if not, it seems to just be AES encryption turned into QR code. We can’t have a FIP38? 8)

              1 Reply Last reply Reply Quote 0
              • E
                estrabd Regular Member last edited by

                https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki#Suggestions_for_implementers_of_proposal_with_altchains

                1 Reply Last reply Reply Quote 0
                • wrapper
                  wrapper Moderators last edited by

                  Cheers Estrabd, interesting read.

                  1 Reply Last reply Reply Quote 0
                  • N
                    netnerd Regular Member last edited by

                    This is something that I would like to see implemented into feathercoin as this is something that could be used for my NFC version of the Wallet Physical Coin.

                    1 Reply Last reply Reply Quote 0
                    • E
                      eaxvac Regular Member last edited by

                      BIP38 is a ridiculously tough encryption, it is also memory intensive!

                      I tried bruteforcing one a few days back with a C# implementation and it takes 0.25 seconds to decrypt one on a fourth generation quad core i5 processor. Memory usage = 300MB. Despite my best effort to optimize the code… (100% CPU utilization).

                      Having a password of at least 6 character will ensure that it’ll take 8000 years on a single machine. (72 ^ 6 tries)

                      Great! I support that since its safe.

                              public Exception DecryptWithPassphrase(string passphrase) {
                                  // check for null entry
                                  if (passphrase == null || passphrase == "") {
                                      return new ArgumentException("Passphrase is required");
                                  }
                      
                                  Bip38Intermediate intermediate = new Bip38Intermediate(passphrase, _ownerentropy, LotSequencePresent);
                      
                                  // derive the 64 bytes we need
                                  // get ECPoint from passpoint            
                                  PublicKey pk = new PublicKey(intermediate.passpoint);
                      
                                  byte[] addresshashplusownerentropy = Util.ConcatenateByteArrays(_addressHash, intermediate.ownerentropy);
                      
                                  // derive encryption key material
                                  byte[] derived = new byte[64];
                                  SCrypt.ComputeKey(intermediate.passpoint, addresshashplusownerentropy, 1024, 1, 1, 1, derived);
                      
                                  byte[] derivedhalf2 = new byte[32];
                                  Array.Copy(derived, 32, derivedhalf2, 0, 32);
                      
                                  byte[] unencryptedpubkey = new byte[33];
                                  // recover the 0x02 or 0x03 prefix
                                  unencryptedpubkey[0] = (byte)(_encryptedpointb[0] ^ (derived[63] & 0x01));
                      
                                  // decrypt
                                  var aes = Aes.Create();
                                  aes.KeySize = 256;
                                  aes.Mode = CipherMode.ECB;
                                  aes.Key = derivedhalf2;
                                  ICryptoTransform decryptor = aes.CreateDecryptor();
                      
                                  decryptor.TransformBlock(_encryptedpointb, 1, 16, unencryptedpubkey, 1);
                                  decryptor.TransformBlock(_encryptedpointb, 1, 16, unencryptedpubkey, 1);
                                  decryptor.TransformBlock(_encryptedpointb, 1 + 16, 16, unencryptedpubkey, 17);
                                  decryptor.TransformBlock(_encryptedpointb, 1 + 16, 16, unencryptedpubkey, 17);
                      
                                  // xor out the padding
                                  for (int i = 0; i < 32; i++) unencryptedpubkey[i + 1] ^= derived[i];
                      
                                  // reconstitute the ECPoint
                                  var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
                                  ECPoint point;
                                  try {
                                      point = ps.Curve.DecodePoint(unencryptedpubkey);
                      
                                      // multiply passfactor.  Result is going to be compressed.
                                      ECPoint pubpoint = point.Multiply(new BigInteger(1, intermediate.passfactor));
                      
                                      // Do we want it uncompressed?  then we will have to uncompress it.
                                      if (IsCompressedPoint==false) {
                                          pubpoint = ps.Curve.CreatePoint(pubpoint.X.ToBigInteger(), pubpoint.Y.ToBigInteger(), false);
                                      }
                      
                                      // Convert to bitcoin address and check address hash.
                                      PublicKey generatedaddress = new PublicKey(pubpoint);
                      
                                      // get addresshash
                                      UTF8Encoding utf8 = new UTF8Encoding(false);
                                      Sha256Digest sha256 = new Sha256Digest();
                                      byte[] generatedaddressbytes = utf8.GetBytes(generatedaddress.AddressBase58);
                                      sha256.BlockUpdate(generatedaddressbytes, 0, generatedaddressbytes.Length);
                                      byte[] addresshashfull = new byte[32];
                                      sha256.DoFinal(addresshashfull, 0);
                                      sha256.BlockUpdate(addresshashfull, 0, 32);
                                      sha256.DoFinal(addresshashfull, 0);
                      
                                      for (int i = 0; i < 4; i++) {
                                          if (addresshashfull[i] != _addressHash[i]) {
                                              return new ArgumentException("This passphrase is wrong or does not belong to this confirmation code.");
                                          }
                                      }
                      
                                      this.PublicKey = generatedaddress;
                                  } catch {
                                      return new ArgumentException("This passphrase is wrong or does not belong to this confirmation code.");
                                  }
                                  return null;
                              }    
                          }
                      
                      
                      #region Bruteforce
                              /* An array containing the characters which will be used to create the brute force keys,
                           * if less characters are used (e.g. only lower case chars) the faster the password is matched  */
                              private static char[] charactersToTest =
                              {
                                  '1','2','3','4','5','6','7','8','9','0',
                                  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
                              'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
                              'u', 'v', 'w', 'x', 'y', 'z','A','B','C','D','E',
                              'F','G','H','I','J','K','L','M','N','O','P','Q','R',
                              'S','T','U','V','W','X','Y','Z','!','$','#','@','-'
                              };
                      
                              /* The length of the charactersToTest Array is stored in a
                               * additional variable to increase performance  */
                              private static int charactersToTestLength = charactersToTest.Length;
                              private static long computedKeys = 0;
                      
                              private bool passFound = false;
                              private string pass = null;
                              private string currentComputingPass = "";
                      
                              private System.Windows.Forms.Timer updateTimer;
                      
                              private void button_bruteforcePrivKey_Click(object sender, EventArgs e)
                              {
                                  // Disable button
                                  button_bruteforcePrivKey.Enabled = false;
                      
                                  // Referencing
                                  string privateKey = txtPrivWIF.Text; // 6PfR1Z9cEHVsHaQTzggoaZmEeQVQAqPbR6A5gd3Eop3JBTZ9oQLUi7hShs
                      
                                  passFound = false;
                                  pass = null;
                                  currentComputingPass = "";
                      
                                  int threads = 10;
                                  int.TryParse(textBox_threads.Text, out threads);
                      
                                  if (updateTimer != null)
                                  {
                                      updateTimer.Stop();
                                      updateTimer = null;
                                  }
                                  updateTimer = new System.Windows.Forms.Timer();
                                  updateTimer.Interval = 100;
                                  updateTimer.Tick += updateTimer_Tick;
                                  updateTimer.Start();
                      
                                  try
                                  {
                                      object interpretation = StringInterpreter.Interpret(privateKey, compressed: compressToolStripMenuItem.Checked, addressType: this.AddressTypeByte);
                      
                                      if (interpretation is PassphraseKeyPair)
                                      {
                                          string passPhrase = txtPassphrase.Text;
                      
                                          PassphraseKeyPair ppkp = (PassphraseKeyPair)interpretation;
                      
                                              Task.Run(() =>
                                              {
                                                  startBruteForce(6, ppkp);
                                              });
                                      }
                                  }
                                  catch (Exception ae)
                                  {
                                      MessageBox.Show(ae.Message);
                                  }
                                  finally
                                  {
                                  }
                              }
                      
                              void updateTimer_Tick(object sender, EventArgs e)
                              {
                                  label_tries.Text = computedKeys.ToString();
                                  label_bruteforcetxt.Text = currentComputingPass;
                      
                                  if (pass != null)
                                  {
                                      txtPassphrase.Text = pass;
                                  }
                              }
                      
                              /// 
                              /// Starts the recursive method which will create the keys via brute force
                              /// 
                              /// The length of the key
                              private void startBruteForce(int keyLength, PassphraseKeyPair ppkp)
                              {
                                  var keyChars = createCharArray(keyLength, charactersToTest[0]);
                                  // The index of the last character will be stored for slight perfomance improvement
                                  var indexOfLastChar = keyLength - 1;
                                  createNewKey(0, keyChars, keyLength, indexOfLastChar, ppkp);
                              }
                      
                              /// 
                              /// Creates a new char array of a specific length filled with the defaultChar
                              /// 
                              /// The length of the array
                              /// The char with whom the array will be filled
                              /// 
                              private char[] createCharArray(int length, char defaultChar)
                              {
                                  return (from c in new char[length] select defaultChar).ToArray();
                              }
                      
                              /// 
                              /// This is the main workhorse, it creates new keys and compares them to the password until the password
                              /// is matched or all keys of the current key length have been checked
                              /// 
                              /// The position of the char which is replaced by new characters currently
                              /// The current key represented as char array
                              /// The length of the key
                              /// The index of the last character of the key
                              private void createNewKey(int currentCharPosition, char[] keyChars, int keyLength, int indexOfLastChar, PassphraseKeyPair ppkp)
                              {
                                  int tryingNumber = 0;
                                  var nextCharPosition = currentCharPosition + 1;
                      
                                  // We are looping trough the full length of our charactersToTest array
                                  for (int i = 0; i < charactersToTestLength; i++)
                                  {
                                      /* The character at the currentCharPosition will be replaced by a
                                       * new character from the charactersToTest array => a new key combination will be created */
                                      keyChars[currentCharPosition] = charactersToTest[i];
                      
                                      // The method calls itself recursively until all positions of the key char array have been replaced
                                      if (currentCharPosition < indexOfLastChar)
                                      {
                                          createNewKey(nextCharPosition, keyChars, keyLength, indexOfLastChar, ppkp);
                                      }
                                      else
                                      {
                                          // A new key has been created, remove this counter to improve performance
                                          computedKeys++;
                      
                                          string txt = new String(keyChars);
                       
                                          while (tryingNumber > 4)
                                          {
                                              Thread.Sleep(10);
                                          }
                                          tryingNumber++;
                      
                                          Task.Run(() =>
                                              {
                                                  /* The char array will be converted to a string and compared to the password. If the password
                                                   * is matched the loop breaks and the password is stored as result. */
                                                  currentComputingPass = txt;
                                                  System.Diagnostics.Debug.WriteLine(txt);
                                                  if (ppkp.DecryptWithPassphrase(txt))
                                                  {
                                                      if (!passFound)
                                                      {
                                                          passFound = true;
                                                          pass = txt;
                                                      }
                                                  }
                                                  tryingNumber--;
                                              });
                      
                                          if (passFound)
                                              return;
                                      }
                                  }
                              }
                              #endregion
                      
                      1 Reply Last reply Reply Quote 1
                      • M
                        mnstrcck last edited by

                        I concur - this would open up a ton of wonderful, flexible uses for Feathercoin wallets.

                        1 Reply Last reply Reply Quote 1
                        • First post
                          Last post