Someguy123 / LiteVault-iOS

LiteVault for iOS - https://www.litevault.net
2 stars 0 forks source link

Wallet.js -> Swift Conversion #3

Closed losh11 closed 4 years ago

losh11 commented 8 years ago

Loading a Wallet

losh11 commented 8 years ago

@Someguy123 Not to sure how the logic to create a new wallet and send transactions work.

Would it be possible for you to explain to me what I'd have to do so that I can just post & get these, so when I load a wallet all I have to do is send a https://www.litevault.net/wallet/load/{identifier} in safari, and then it load a JSON with AES. So if you'd tell me how all these functions work, that'd be a lot easier!

Someguy123 commented 8 years ago

@losh11

Transactions For transactions, it's pretty complicated, you'll need some sort of Bitcoin library to deal with it. LiteVault uses BitcoinJS, but there's still a lot of work that happens behind the scenes of sending the coins. Take a look at the sendCoins() function in LiteVault:

(the code should be self explanatory, starting from line 347)

https://github.com/Someguy123/LiteVault/blob/master/lib/wallet.ts#L347

Note A quick note about the encryption/decryption. I use CryptoJS which handles almost EVERYTHING. I pass it the data and the password and it'll deal with encryption/decryption almost magically. However I did a lot of research into what happens behind the scenes, so I've done my best to explain what it does so that you can replicate it using standard libraries in Swift/ObjC.

Another thing: For many functions in LiteVault, you might be able to modify them to directly query Blockr.IO rather than LiteVault, LiteVault simply proxies the request to Blockr due to Cross-Origin problems in browsers, but you shouldn't have that issue from a native app. Example: /wallet/pushtx is simple a proxy which forwards the hex to http://ltc.blockr.io/api/v1/tx/push

Wallet Structure If you look inside wallet.ts on LiteVault, you'll see that the main parts of the wallet are here:

private identifier;
private password;

protected addresses : LTCAddressContainer = {};
protected balances : BalanceMap = {};

protected shared_key : string;

Creation Generally you'll send a POST request to /wallet/create - with the users email (if provided). The server will return JSON, which inside of the data key will contain an object with the users shared key and their identifier. Save the shared key to the wallet data, encrypt+encode, and post it to /wallet/update with the following post data:

Decryption

Basic steps for decrypting (encrypting is pretty much reverse):

If your crypto implementation doesn't natively support that padding, you should be able to find a library for it - in which case, disable any automatic padding in your library, and you pad before encrypting, and un-pad after decrypting.

Handling Key/IV/Salt for AES

To generate the key and IV, CryptoJS uses the OpenSSL key derivation function (i.e. a password goes in, and out comes a 256-bit key for AES). The salt used for the KDF when decrypting is stored between characters 8 and 16 of the decrypted data, and the actual wallet data is everything after the 16th character. Check the example python code below if you need to implement it by hand.

EXAMPLE Python Decryption script Here's an example python script dealing with the Litevault wallet format (encryption is just the decrypt process in sort-of reverse):

from base64 import b64decode, b64encode
from Crypto.Hash import MD5
from Crypto import Random
from Crypto.Cipher import AES
import Padding

class Litevault:
    def openssl_kdf(self, req, password, salt):
        prev = ''
        while req>0:
            prev = MD5.new(prev+password+salt).digest()
            req -= 16
            yield prev
    def decrypt(self, wallet_data, password):
        # Decode the wallet from base64, extract the salt and main data
        encrypted = b64decode(wallet_data)
        salt = encrypted[8:16]
        data = encrypted[16:]
        # Derive the key and iv using the OpenSSL KDF
        mat = ''.join([ x for x in self.openssl_kdf(32+16, password, salt) ])
        key = mat[0:32]
        iv  = mat[32:48]
        # Decrypt using AES with CBC mode
        dec = AES.new(key, AES.MODE_CBC, iv)
        clear = dec.decrypt(data)
        # Remove the padding, and return the fully decrypted wallet file
        return Padding.removePadding(clear, blocksize=32, mode='Random')
losh11 commented 8 years ago

Yeah, for the most part. I've just been looking at frameworks and trying to add them (because of swift 2.0 - a whole lot of frameworks still haven't been updated). I think I'm going to have to use something like this: https://github.com/CryptoCoinSwift/CryptoCoinFramework which already supports LTC.

There is a generate public function which I can steal. I'm thinking of running the function, and returning both pub and prove key. Then as variables, make it public. Now that it is public, just use to post data (including everything else + after cipher + other stuff) to /wallet/post.

I'll try to use blockr's get links instead. This is a lot more complicated than I initially thought, probably going to have to write a lot more code than 'wallet.js' for just the core stuff. At least after you've got core done in Swift/Obj-C, it's really easy to just use nibs and storyboards to create the UI.

On 19 July 2015 at 23:23, Someguy123 notifications@github.com wrote:

@losh11 https://github.com/losh11

Transactions For transactions, it's pretty complicated, you'll need some sort of Bitcoin library to deal with it. LiteVault uses BitcoinJS, but there's still a lot of work that happens behind the scenes of sending the coins. Take a look at the sendCoins() function in LiteVault:

(the code should be self explanatory, starting from line 347)

https://github.com/Someguy123/LiteVault/blob/master/lib/wallet.ts#L347

Note A quick note about the encryption/decryption. I use CryptoJS which handles almost EVERYTHING. I pass it the data and the password and it'll deal with encryption/decryption almost magically. However I did a lot of research into what happens behind the scenes, so I've done my best to explain what it does so that you can replicate it using standard libraries in Swift/ObjC.

Another thing: For many functions in LiteVault, you might be able to modify them to directly query Blockr.IO rather than LiteVault, LiteVault simply proxies the request to Blockr due to Cross-Origin problems in browsers, but you shouldn't have that issue from a native app. Example: /wallet/pushtx is simple a proxy which forwards the hex to http://ltc.blockr.io/api/v1/tx/push

Wallet Structure If you look inside wallet.ts on LiteVault, you'll see that the main parts of the wallet are here:

private identifier; private password;

protected addresses : LTCAddressContainer = {}; protected balances : BalanceMap = {};

protected shared_key : string;

Creation Generally you'll send a POST request to /wallet/create - with the users email (if provided). The server will return JSON, which inside of the data key will contain an object with the users shared key and their identifier. Save the shared key to the wallet data, encrypt+encode, and post it to /wallet/update with the following post data:

  • identifier (the users identifier),
  • shared_key (the shared key you just received),
  • wallet_data (the base64 encoded, AES encrypted wallet to store)

Decryption

Basic steps for decrypting (encrypting is pretty much reverse):

  • you need to first base64 decode the wallet,
  • use AES-256 in CBC mode (full details for IV+Salt+Key further down)
  • pad/unpad ISO 10126 (sometimes referred to as "random") padding.
  • you now have the raw JSON, decode into an object to use it.

If your crypto implementation doesn't natively support that padding, you should be able to find a library for it - in which case, disable any automatic padding in your library, and you pad before encrypting, and un-pad after decrypting.

Handling Key/IV/Salt for AES

To generate the key and IV, CryptoJS uses the OpenSSL key derivation function (i.e. a password goes in, and out comes a 256-bit key for AES). The salt used for the KDF when decrypting is stored between characters 8 and 16 of the decrypted data, and the actual wallet data is everything after the 16th character. Check the example python code below if you need to implement it by hand.

EXAMPLE Python Decryption script Here's an example python script dealing with the Litevault wallet format (encryption is just the decrypt process in sort-of reverse):

from base64 import b64decode, b64encode from Crypto.Hash import MD5 from Crypto import Random from Crypto.Cipher import AES import Padding

class Litevault: def openssl_kdf(self, req, password, salt): prev = '' while req>0: prev = MD5.new(prev+password+salt).digest() req -= 16 yield prev def decrypt(self, wallet_data, password):

Decode the wallet from base64, extract the salt and main data

    encrypted = b64decode(wallet_data)
    salt = encrypted[8:16]
    data = encrypted[16:]
    # Derive the key and iv using the OpenSSL KDF
    mat = ''.join([ x for x in self.openssl_kdf(32+16, password, salt) ])
    key = mat[0:32]
    iv  = mat[32:48]
    # Decrypt using AES with CBC mode
    dec = AES.new(key, AES.MODE_CBC, iv)
    clear = dec.decrypt(data)
    # Remove the padding, and return the fully decrypted wallet file
    return Padding.removePadding(clear, blocksize=32, mode='Random')

— Reply to this email directly or view it on GitHub https://github.com/Someguy123/LiteVault-iOS/issues/3#issuecomment-122711393 .

losh11 commented 8 years ago

@Someguy123 after decoding JSON "wallet", do you use the base64 as salt and data or plaintext?

Someguy123 commented 8 years ago

@losh11 The base64 data when decoded contains the IV, Salt, and data.

The big reply I made last time contains full details on how to decrypt it