polkadot-js / common

Utilities and base libraries for use across polkadot-js for Polkadot and Substrate. Includes base libraries, crypto helpers and cross-environment helpers.
Apache License 2.0
252 stars 142 forks source link

How to get private key from keystore #915

Closed wbh1328551759 closed 3 years ago

wbh1328551759 commented 3 years ago

Hello, I am a member of the chainx team. During the development of the wallet, we need to convert the keystore to the private key. After I try to use keyring.getPair to get the pair, I convert its encoded with stringToU8a and then use the decodePair method to decode it. But it failed and reported this error: image This is the code of my process:

      const accounts = keyring.getAccounts();
      const pair = keyring.getPair(accounts[0].address);
      const JSONPair = pair.toJson('1')  // '1'  is the password for this account
      const u8aEncoded = stringToU8a(JSONPair.encoded)
      console.log('pair2: ', decodePair('1', u8aEncoded ))

Then I read the code of decodePair function and found that the error is in this code image But what I can’t understand is that I manually printed out N, p, r, and found that this assert trigger condition was not met, but it triggered this problem. So I'm here for help. If I want to get the private key of my account from the keystore, how should I get it?

jacogr commented 3 years ago

Happy to help.

Do you have a sample file JSON that fails?

wbh1328551759 commented 3 years ago

yes, like this , and password is '1'

{"address":"5PjeoaQzCoYbSi42aQRKB3Sx18StCaEAzCbGEEbWbZyfKS3H","encoded":"JQUl8ZpoXv2OMkL9TPylLmcIye2cYhaS9INICbFgZTsAgAAAAQAAAAgAAAAr/0hJOOzokIdBG71TstigLABX9D5xGD7L37ySxtjDrVRg26LL90jLQ47quT9o3bq6ppXMVL6USk7Q4p3WU66bojTFuCDyhpYRhNbUqU6s0rD3S4bhv9lG+pG9vQ4eD5PVQUvxdANmJpYuDg45nrTmsMC5AHGdFGkHW/LHnkmbFid1cvPYkdiBoef5CIEdoly512pxMupVxnJWF1NT","encoding":{"content":["pkcs8","sr25519"],"type":["scrypt","xsalsa20-poly1305"],"version":"3"},"meta":{"genesisHash":"0x012cfb6997279fed8ff754a5a90cb30627c70fcdd79ee9c480bcef07de754810","name":"ss","tags":[],"whenCreated":1614751681701}}

jacogr commented 3 years ago

So technically, this should work -

import { decodePair } from '@polkadot/keyring/pair';
import { base64Decode } from '@polkadot/util-crypto';

...
const JSONPair = pair.toJson('1')
const decoded = decodePair('1', base64Decode(JSONPair.encoded), JSONPair.encoding.type);

So above the encoded part is base64, so needs to be decoded from that.

wbh1328551759 commented 3 years ago

Ohhh, thanks !. It worked successfully. I got the publicKey and secretKey through this method. Then I used the u8aToHex() method to process the secretKey and got a 64-bit Uint8Array data, so what do I need to do next to let the user to create the original account through this secretKey? Then I used the subarray(32) method, and then put it into the account creation component of the wallet, and found that the address generated by this result is not the address of the original account, but I have used publicKey to confirm that it is indeed corresponding, so is the method I used wrong? Still need to use what method to operate secretKey? This is the publicKey and secretKey I got

publicKey: 0x044adc4365288575acaaa1544e983b7e24255ad298fa0d09df8f4e96c458a923
secretKey: 0xe0f3d7c96717943a21213eb3f0137c10466ac9f9262a938af6ce40410092fc66e885414439fe67aa9a3480c76bfbcbc71b9852854b7f1ff43eaaa622d10c7d1b

I'm sorry i'm not very familiar with this

jacogr commented 3 years ago

If you have the public & secret, you can just use them as-is into createPair.

If you wish to extract the seed part, at least for sr25519 it would be .subarray(0, 32) (the first 32 bytes)

wbh1328551759 commented 3 years ago

I have verified that the publicKey of the account is indeed correct, but the account address of the seed conversion obtained through .subarray(0,32) is indeed not the same as the original one. I think I need to discuss this process with my colleagues tomorrow. Thank you for your reply, I will reply to you the result of this question as soon as the discussion is completed

jacogr commented 3 years ago

If the publicKey is correct, the private needs to match. Who’s means the address should be the same - the ss58 is just an encoding of the publicKey.

So assuming the address mismatch is just the ss58 format.

wbh1328551759 commented 3 years ago

Hi @jacogr . Now I get this object containing publicKey and secretKey through the decodePair() method, but the length of the secretKey obtained is 64 bits, which does not match expectations. I understand that the return value should be a 32-bit publicKey and secretKey, so yes what operation caused the difference in the number of digits of the secretKey? Do I need to use any operation to process the secretKey to make it the same as expected? And My goal now is to convert this secretKey into the seed that users can use to create the original account This is the object I got using decodePair image

jacogr commented 3 years ago

So it really depends on the type. For instance -

So it is tricky gong back to seed. The best way, which is what the keyring uses (which generally manages all the JSON encoding/decoding), is to actually pass the full public/private to the createPair from https://github.com/polkadot-js/common/blob/master/packages/keyring/src/pair/index.ts#L91 to re-create the pair.

It it optimized for the case to use the keyring to manage all of this. Internally the keyring applies the correct logic from JSON, from seed, etc.

wbh1328551759 commented 3 years ago

I think this is not a tricky way. Since users are allowed to create accounts through privateKeys, it should be possible in theory to allow users to export their private keys. This is convenient for users without saving their private keys. Then re-export the private key to save

I saw that the "ed25519" encrypted account can directly get the 32-byte seed, and since the encryption method we currently use is "sr25519", we can’t get the seed directly, so for the "sr25519" encrypted account, how should we parse out the 32-bit seed? What about the correct private key?

jacogr commented 3 years ago

The 64 bytes as-is is the correct private key (fully-expanded) for sr25519. (And which is actually used in all sr25519 interfaces)

wbh1328551759 commented 3 years ago

I know this, but why the raw seed generated by sr25519 encryption on this account creation page is 32-bit? The goal now is to be able to get this 32-bit and be able to use it to create the original account again, but the current implementation is the 64-bit secretKey I obtained cannot be used to recreate the original account image

jacogr commented 3 years ago

The above is a minisecret in sr25519 terminology - it gets expanded into a full pair with private/public when the creation takes place, see eg. https://github.com/polkadot-js/wasm/blob/master/packages/wasm-crypto/src/rs/sr25519.rs#L82-L88

See https://github.com/polkadot-js/common/pull/918/files for the additional createFromPair on the keyring.

wbh1328551759 commented 3 years ago

Hi, @jacogr ,At present, the function we want to achieve is to provide this minisecretkey to users, which is what the community wants us to do, so we want to know what method we should use to convert this 64-bit secretKey into the correct 32-bit minisecretKey

jacogr commented 3 years ago

I don’t believe that is exposed on the wasm layer, nor is there a function like this on the sr25519 libs.

This is the one area where I would suggest not listening to users - passing hex strings around instead of mnemonics is a very bad idea.

If you want to try, the secretKey is made of of 32 bytes + 32 bytes nonce - so the first 32 is the mini, but the ed25519 expansion mode shift is applied to it - not sure if the shift is on-way, if it is, can be re-used. See https://github.com/w3f/schnorrkel/blob/master/src/keys.rs

wbh1328551759 commented 3 years ago

OK, I understand what you mean. I think we should listen to your suggestions. Thank you for your patience and prompt reply. Thank you very much!

polkadot-js-bot commented 3 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue if you think you have a related problem or query.