hank / feathercoin-wallet

Android Feathercoin Wallet App
4 stars 7 forks source link

Exported private key fails to be imported in feathercoind / feathercoin-qt, the official client #3

Closed brianddk closed 11 years ago

brianddk commented 11 years ago

Version: (Android) de.schildbach.wallet.feathercoin v1.092 (Windows) feathercoin-qt / feathercoind v0.6.4.2 (Cygwin) OpenSSL v1.0.1e

Procedure to reproduce error 1) From feathercoin-wallet choose {Backup keys -> Export private keys} 2) Choose a password {example "password"} and select export 3) Copy feathercoin-wallet file to Windows box. 4) Decrypt feathercoin-wallet keys to console using openssl: 4a) openssl enc -d -aes-256-cbc -a -in feathercoin-wallet 5) Open debug console in feathercoin-qt gui 6) Unlock wallet with cmd: { walletpassphrase passphrase timeout } 7) Import android key with cmd: { importprivkey feathercoinprivkey label } 8) Note error: {"code":-5,"message":"Invalid private key"}

Verification: Did same procedure with bitcoin-wallet and bitcoin-qt: PASS Did same procedure with litecoin-wallet and litecoin-qt: FAIL

BTW... many thanks for the app, I really like your crypto-currency apps!

PS: This issue seems to have been imported from the litecoin-wallet fork. Currently tracked in litecoin-wallet as issue #15

https://github.com/hank/litecoin-wallet/issues/15

hank commented 11 years ago

Thanks for the report! The version prefix to the exported private key is incorrect so the import to other clients doesn't work currently. This is the first bug I plan to fix once I get time. Feel free to look through the code and give me hints or a patch and I will get it done quicker.

brianddk commented 11 years ago

Apologies for not learning github markup, but I just wanted to get this out there first.

OK... you were right. Looks like the feathercoinj and FeatherCoin repositories have conflicting versions bytes for PrivateKeys. I think the one you were shooting for was 0x8E (128 + 14). That is what is used by FeatherCoin. feathercoinj on the other hand is using 0x80 (128) which I believe is the bitcoin private key header.

Here's a walk through for anyone reading along at home. (3) clearly expects the version to be 0x8E (128 + 14). The IsValid function is ultimately what causes the "Invalid private key" message. (4) through (7) clearly pass the version 128 straight down to the ToString function which ultimately write the key to the SD card.

I would suppose the most isolated change would be to change (5) to: super(params.dumpedPrivateKeyHeader + params.addressHeader, encode(keyBytes, compressed));

Although a broader change may be in order. The scope of my review was VERY narrow.

.. References: .. (1) FeatherCoin: src/base58.h ln:281

        PUBKEY_ADDRESS = 14,

(2) FeatherCoin: src/base58.h ln:409

        PRIVKEY_ADDRESS = CBitcoinAddress::PUBKEY_ADDRESS + 128,

(3) FeatherCoin: src/base58.h ln:430

    bool IsValid() const
    {
        bool fExpectTestNet = false;
        switch(nVersion)
        {
            case PRIVKEY_ADDRESS
                break
            case PRIVKEY_ADDRESS_TEST
                fExpectTestNet = true
                break
            default
                return false
        }
        return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1));
    }

(4) feathercoinj: src/main/java/com/google/feathercoin/core/NetworkParameters.java ln:146

            dumpedPrivateKeyHeader = 128;
            addressHeader = 14;

(5) feathercoinj: src/main/java/com/google/feathercoin/corecore/DumpedPrivateKey.java ln:35

        super(params.dumpedPrivateKeyHeader, encode(keyBytes, compressed));

(6) feathercoinj: src/main/java/com/google/feathercoin/core/VersionedChecksummedBytes.java ln:42

    protected VersionedChecksummedBytes(int version, byte[] bytes) {
        checkArgument(version < 256 && version >= 0);
        this.version = version;
        this.bytes = bytes;
    }

(7) feathercoinj: src/main/java/com/google/feathercoin/core/VersionedChecksummedBytes.java ln:53

        addressBytes[0] = (byte) version;
hank commented 11 years ago

Wow - fantastic job tracking that down! This will allow me to fix key exports in both feathercoinj and litecoinj and their associated android wallets. I really appreciate this - I did indeed change NetworkParameters to what I thought should work (the +14 on the address header) and I was confused on why this didn't work. As you found, the code kind of goes all over the place, and can be hard to grok without some time dedication. Again, I can't thank you enough for this analysis. I'll get to work on this very soon.

brianddk commented 11 years ago

While the patch is in, I wrote a little powershell script to thunk the header field to whatever you what. I listed "known" header fields as: [ftc-qt] FeatherCoin-Qt: 142 [ltc-qt] LiteCoin-Qt: 176 [ftc-and] feathercoin-wallet: 128 [ltc-and] litecoin-wallet: 128

## Powershell Privatekey header modification script.
## Known headers: { ftc-qt:142, ftc-and:128, ltc-qt:176, ltc-and:128 }
##   By d4n13 < https://github.com/d4n13 >.  Feel free to tip!
##     Feathercoin TipJar: 6mx5WVXsTEdsh9UCainpdAHDrDwH4mZQTD 
${codeString} = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
${hasher}   = [System.Security.Cryptography.HashAlgorithm]::create("sha256")
${base}     = New-Object System.Numerics.BigInteger -ArgumentList @(,58)
${bigInt}   = New-Object System.Numerics.BigInteger -ArgumentList @(,0)
${strKey}   = Read-Host -Prompt "Enter the key to modify"
${oldArray} = ${strKey}.ToCharArray()
foreach( ${char} in ${oldArray} ) {
    ${bigInt} = ${bigInt} * ${base}
    ${bigInt} = ${bigInt} + ${codeString}.IndexOf(${char})
}
${intArray} = ${bigInt}.ToByteArray()
${intArray} = ${intArray}[0..(${intArray}.Length-2)]
[System.Array]::Reverse(${intArray})
${intArray} = ${intArray}[0..(${intArray}.Length-5)]
Write-Host "The given key has a header byte of: $(${intArray}[0])"
${intArray}[0] = [Byte]::Parse((Read-Host -Prompt "Input 'desired' header byte"))
${chksum} = ${hasher}.ComputeHash(${hasher}.ComputeHash(${intArray}))
${intArray} = @(,0) + ${intArray} + ${chksum}[0..3]
[System.Array]::Reverse(${intArray})
${bigInt} = New-Object System.Numerics.BigInteger -ArgumentList @(,${intArray})
do {
    ${newArray} += @(,${codeString}[(${bigInt} % ${base})])
    ${bigInt} = (${bigInt} / ${base})
}
until (${bigInt}.IsZero)
[System.Array]::Reverse(${newArray})
${strKey} = New-Object System.String -ArgumentList @(,${newArray})
Write-Host "The modified key is: ${strKey}"
@("strKey", "intArray", "oldArray", "newArray") | % { Remove-Variable -Name $_ }
hank commented 11 years ago

Thanks!

hank commented 11 years ago

Just tried exporting in the new Litecoin wallet version I uploaded to Play just now (it hasn't appeared yet). I exported the keys and imported into the official client. It works. This is based on exactly the same code you have above, so I'm going to call this closed. If you can validate it, I'd appreciate it (Litecoin-wallet v1.091, Feathercoin-wallet v1.094).

brianddk commented 11 years ago

Confirmed... I exported from litecoin-qt and litecoin-wallet and they private keys matched.

Thanks.

hank commented 11 years ago

No problem! I'm not sure what feathercoin private keys are supposed to look like and didn't have an official client handy. If you could try with feathercoin wallet too, that would help. I can probably try on my end tonight.

On Tue, Jul 23, 2013 at 1:38 AM, d4n13 notifications@github.com wrote:

Confirmed... I exported from litecoin-qt and litecoin-wallet and they private keys matched.

Thanks.

— Reply to this email directly or view it on GitHubhttps://github.com/hank/feathercoin-wallet/issues/3#issuecomment-21394205 .

brianddk commented 11 years ago

Confirmed... Feathercoin-Wallet now exports keys correctly too.

I did have some weirdness updating feathercoin-wallet from google-play. In the search results feathercoin-wallet had a "update" by it, but when I opened the listing from search, there wasn't an update button. If I went back to search I could long click on the left of the item in the search results and pick "update". At that point it complained that the app was already installed.

Did the exact same steps this morning and this time the update took. Don't know if it was just wierdness on my phone or wierdness in the listing.

hank commented 11 years ago

Strange I'll try that tonight on another device. Thanks for the report and the test!

On Tue, Jul 23, 2013 at 9:42 AM, d4n13 notifications@github.com wrote:

Confirmed... Feathercoin-Wallet now exports keys correctly too.

I did have some weirdness updating feathercoin-wallet from google-play. In the search results feathercoin-wallet had a "update" by it, but when I opened the listing from search, there wasn't an update button. If I went back to search I could long click on the left of the item in the search results and pick "update". At that point it complained that the app was already installed.

Did the exact same steps this morning and this time the update took. Don't know if it was just wierdness on my phone or wierdness in the listing.

— Reply to this email directly or view it on GitHubhttps://github.com/hank/feathercoin-wallet/issues/3#issuecomment-21414491 .

hank commented 11 years ago

Finally coded this up in python:

https://github.com/hank/life/blob/master/code/python/cryptcoin_addr_convert/convert.py

TSavo commented 11 years ago

I got this working, please find the pull request for the fixed code here: https://github.com/hank/life/pull/1

bmilne81 commented 10 years ago

I'm one of the idiots that lost coins with the old wallet... i have about 31 ltc sitting in it and I can't access it. I did use openssl to decrypt a backup I had from 6-5-2013 and then converted the private key with the python script and it still tells me it's an invalid private key when I try to import it into litecoin-qt... any thoughts?

I'm a software developer so this is additionally embarrassing for me... :)

hank commented 10 years ago

@bmilne81 I'd be happy to try and help if you want. Email me at ralree@gmail.com if you like and we can work something out.