Skip to content

Wallet Protection

Adam edited this page Apr 1, 2016 · 1 revision

Omniwallet is not built like most other web applications. We built Omni from the ground up with security in mind. First of all, as a rule omni never sends your password to the server. Your password is only used locally to unlock your private key(s). Speaking of keys, they are also not stored unencrypted on the server. https://github.com/OmniLayer/omniwallet/blob/master/design/login.md

Here’s a walkthrough of the account creation workflow.

  • When an account is created, the user creates a random UUID using a secure random 1 method, and sends to the server.
  • If the UUID exists, the server returns an EXISTING_UUID error.
  • The server creates a salt (see Salt Creation above)
  • The server creates create_pow_challenge as a random string and stores it in the session.
  • The server sends (salt, create_pow_challenge) to the client.
  • The client iterates nonce values (nonce ← 0; nonce < inf; ++nonce) and calculates HASH(CONCAT(pow_challenge, nonce)), and when it reaches a hash that ends in ACCOUNT_CREATION_DIFFICULTY, proceeds.
  • The client generates a symmetric key from CONCAT( password, salt ).
  • The client generates a public/private key pair based on random values.
  • The client sends ( nonce, public key, encrypted empty wallet file ) to the server. 1 2
  • The server validates that HASH( CONCAT( nonce, create_pow_challenge_from_session )) ends in ACCOUNT_CREATION_DIFFICULTY, the server rejects it if not.
  • The server forgets the nonce, stores the public key in the session, and the encrypted wallet file associated with the given UUID.

Now here’s the workflow for logging in to use your wallet.

  • The client sends his UUID to the server.
  • The server calculates the matching salt.
  • The server creates a random pow_challenge and stores it in the session.
  • The server sends ( salt, pow_challenge ) to the client.
  • The client iterates nonce values (nonce ← 0; nonce < inf; ++nonce) and calculates HASH(CONCAT(pow_challenge, nonce)), and when it reaches a hash that ends in LOGIN_DIFFICULTY, proceeds.
  • The client calculates the symmetric key based on the user’s password and the salt provided by the server, and stores it in a javascript variable.
  • The client calculates a public/private key pair for signing requests.
  • The client sends ( nonce, public key ) to the server.
  • The server validates HASH(CONCAT(pow_challenge, nonce)) ends in LOGIN_DIFFICULTY.
  • If valid, the server sends the encrypted wallet file to the client, and stores the public key in the session.

Take a look at Omni’s encryption code and let us know what you think, where can improvements be made, or if we are doing something you consider unsafe.

https://github.com/OmniLayer/omniwallet/blob/master/www/js/cryptUtil.js https://github.com/OmniLayer/omniwallet/blob/master/www/js/CreateWalletController.js

The actual creation of a transaction is elegant in it’s simplicity.

  • A JSON payload is crafted locally.
  • The payload contains: from_address, pubKey, to_address, amount, currency, fee
  • The JSON Payload is posted to the Omni server which responds with a specialized transaction for the wallet owner’s public key.
  • The client in turn signs the transaction and posts it back to Omni to broadcast into the bitcoin network.
  • Notice how the server never needs your private key, and you only use it client side.

Due to our use of the nonces, csrf and session fixation attacks are impossible or minor nuisances at most. (csrf can be used to force log out a user) We are not aware of any session fixation attacks or XSS. But we would like YOU to verify that.

Clone this wiki locally