ECIPs icon indicating copy to clipboard operation
ECIPs copied to clipboard

Utilizing a second authentication method to prove ownership and facilitate fund recovery in the event of a theft

Open pyskell opened this issue 8 years ago • 6 comments

ECIP: TBD Title: Utilizing a second authentication method to prove ownership and facilitate fund recovery in the event of a theft Status: Draft Type: Security Author: Pyskell Created: 2017-07-21

Abstract

We essentially live in the wild west of currency, we have no central authority, and therefore we need to be able to provide users with adequate means to protect themselves.

Issue

When a wallet's private key is stolen it becomes very hard or impossible to prove ownership of the stolen funds because both the attacker and the legitimate owner now control the private key and there is no way to prove legitimate ownership.

Solution

Provide a secondary means of authentication via a contract on the Ethereum Classic blockchain. This secondary authentication will serve solely to prove ownership, and is in no way used for transferring or accessing funds.

Current Scenario

  • At block 10 a wallet starts being used and has 1000 ETC deposited into it.
  • At block 100 the wallet is stolen and the funds are moved to an exchange.
  • The exchange freezes the funds but is unable to return them as they are not certain who is the attacker and who is the legitimate owner.

SecondAuth Scenario

  • At block 10 a wallet starts being used and has 1000 ETC deposited into it.
  • At block 11 the owner of the wallet submits a SecondAuth hash to a publicly known address. This is a hash of a sufficiently long string of characters (or other key) known only to the wallet's legitimate owner.
    • The key is stored completely offline and never needs to be used, even to move funds, which makes it extremely unlikely that an attacker would be able to obtain it.
  • At block 100 the wallet is stolen and the funds are moved to an exchange.
  • Both the attacker and the legitimate owner contact the exchange and claim ownership of the funds. The exchange checks the SecondAuth contract and finds that a hash exists for this address and requests that both parties provide the key. Only the legitimate owner is able to and the funds are returned to a new address under the legitimate owner's control.

pyskell avatar Jul 21 '17 15:07 pyskell

I also got a bit ahead of myself when writing this up so here's some additional points to hopefully facilitate discussion:

Possible Concerns

  • The attacker could query the SecondAuth contract to determine which addresses have SecondAuth and then not move these funds anywhere and/or not target these addresses.
    • The author's only solution for this is to achieve such high usage of SecondAuth that attackers are either completely disincentivized to steal wallets, or that they choose to take the risk.
    • Would be particularly effective if adopted by high value addresses.
  • Usage of a hash over a private key
    • Largely for key size and simplicity, SecondAuth is designed to be one-time-use for emergencies only, and small enough such that a naive user can write it down on a piece of paper and stash it away somewhere safe.
  • Users can choose a weak key that is effectively equivalent to no key at all
    • Client software can address this by generating a secure key for the user
  • Submitting a hash to the SecondAuth contract will cost a small amount of gas and a new address does not contain any funds.
    • The amount is very small and the client software can prompt a user to submit to the SecondAuth contract after funds are deposited.
  • Attackers will stop funneling funds through exchanges
    • This cuts off one of their main avenues for tumbling/laundering funds
    • This also applies to funds ending up at any other legitimately operating business whereby users will be able to reasonably identify their funds.

Additional Thoughts

  • This could eventually be integrated directly into the Ethereum Classic protocol.
  • Implementation is intended to be kept as simple as possible to make adoption of SecondAuth trivial.
  • Development of very small libraries and/or code samples to help enforce standards and facilitate adoption will be necessary. The author is more than happy to provide these.

Sample Contract Code

pragma solidity ^0.4.13;
contract SecondAuth {
    struct HashData{
        // Stores one of a keccak256, sha3, sha256, ripemd160, 
        // or any other hash which fits inside 32 bytes
        bytes32 byteHash;
        // Stores the block number when the hash for an address was committed
        uint hashCommitBlock;
    }

    // Both the event and public hashData are provided because events, 
    // although free to read, are not guaranteed to exist forever in the blockchain
    
    // ~500 gas to read / 0.000002 ETC (@4Gwei)
    mapping(address => HashData) public hashData;
    event StoreHash(address sender, bytes32 byteHash, uint hashCommitBlock);

    // ~66000 gas / 0.000264 ETC (@4 Gwei)
    function setHash(bytes32 byteHash) returns (bool success){
        if (hashData[msg.sender].byteHash == 0){
            hashData[msg.sender].byteHash = byteHash;
            hashData[msg.sender].hashCommitBlock = block.number;

            StoreHash(msg.sender, byteHash, block.number);
            
            return true;
        }

        return false;
    }
}

pyskell avatar Jul 21 '17 15:07 pyskell

What about building the 2FA into the wallet, rather than storing the hash separately? (eg, @Dexaran example here: https://github.com/Dexaran/Secret/blob/master/Secret.sol)

the password could still be added after the fact. Something like:

contract Bad_Guy_Owner{
    bytes32 public secret;
    bool locked = false;
    address public owner = msg.sender;
    function() payable
    {
        
    }
    function set_secret(bytes32  _secret)
    {
        if(msg.sender == owner && !locked) {
             secret = _secret;
             locked = true;
       } else {
           throw;
       }
    }

    function give_Me_Money(string _data)
    {
        if(msg.sender == owner && sha3(_data) == secret)
        {
            owner.send(this.balance);
        }
    }
    
}

elaineo avatar Jul 22 '17 06:07 elaineo

i guess the use case you're describing is pretty different, because it's a case where stolen funds have ended up at an exchange.

elaineo avatar Jul 22 '17 06:07 elaineo

Yeah, this is for proving ownership of stolen funds with the goal being to have it as cheap and simple for an end user and the exchange as possible. While also being easy to implement for wallet software.

Edit: It's also not simply for exchanges, but any legitimate business where stolen funds can end up.

pyskell avatar Jul 22 '17 15:07 pyskell

It seems like using 'raw' accounts as a general practice is a bad habit. If accounts are only used to manage contracts instead of holding funds they are less of a problem.

realcodywburns avatar Aug 05 '17 01:08 realcodywburns

@realcodywburns By raw accounts do you mean accounts that directly hold funds?

pyskell avatar Aug 07 '17 14:08 pyskell