Skip to content

Latest commit

 

History

History
44 lines (31 loc) · 3.78 KB

Encryption.md

File metadata and controls

44 lines (31 loc) · 3.78 KB

Wallet Encryption

This file explains how wallet encryption should be implemented. In general we are using AES 256 in CBC mode.

Key generation

When trying to unlock wallet, password should be obtained from the user. Key for AES encryption is derived from password using sha256 hash function, salted with bytes which are hard-coded into all ElectronPass applications.

To imagine how hard is to break sha256 hash, see this video

After the key has been generated, password string should be deleted, so that the chance of stealing user's password is minimal. Even key, derived from user's password should not be ever written to a disk.

IV generation

IV must not be reused for two message encryptions with the same key. Therefore IV should be randomly generated, using a cryptographically secure pseudorandom number generator. When using 32 byte IV, 2^256 different IVs can be generated, which means that chance of collision for two following encryptions is less than 10^-77.

We are aware of famous Birthday problem, so just for fun consider this: if you had 1 000 000 computers since the beginning of the Universe, and each of them generated 10^9 random IVs every second, then probability of two IVs being same would be lower than 10^-12.

Padding

Since AES CBC is a block cipher, the data length needs to be a multiple of the block size (16 bytes in the case of AES). Therefore data needs to be padded before the encryption. We are using PKCS#7 padding.

Encryption

We are using AES with CBC mode for encryption. It accepts the 256 bit key generated from the password. This mode also needs Initialization Vector. After we generate the key and IV vector and apply the PKCS#7 padding to the wallet, we encrypt it.

Authentication

For authentication we hash the encrypted wallet and the key with sha256. Pseudocode on that is shown bellow:

signature = sha256(encrypted_wallet + key)

Putting it together

Now that we have everything encrypted and we have generated the signature, we can put it all together into one string. The string is generated by appending the signature and iv to the encrypted wallet. Since all of these things are arrays of bytes, we can't really save them to a file. For that we first convert it to Base64. Pseudo code for this process:

encypted_wallet = base64(encrypted_bytes + signature + iv)

where encrypted_bytes is the result of AES256 encryption, signature is the wallet signature and iv is the iv used for encryption. encrypted_wallet is the string that gets saved to disk.

For decrypting the wallet, we first convert it from Base64 back to plain array of bytes, then we can extract the IV, signature and the actual encrypted data from that array. When the user wants to unlock a wallet with a password, we generate the key from that password as described above. Then we generate another signature by hashing the encrypted data and the newly generated key with sha256. If the signature extracted from the wallet and the generated signature are not the same, that means one of two things:

  • Someone has changed the encrypted wallet
  • The user has typed in the wrong password Since the latter is a lot more probable, we display the error as a wrong password.

If the signatures match, then we can just decrypt the encrypted data with the provided key and previously extracted IV.

Notes

When the wallet is locked, all sensitive data should be deleted (this includes AES key and also all data stored in wallet). We also recommend that you don't store the password in the RAM, but after the user types it in immediately generate a key and discard the plain password.