-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
922 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
try: | ||
from Cryptodome.Cipher import AES | ||
from Cryptodome import Random | ||
except ImportError: | ||
try: | ||
from Crypto.Cipher import AES | ||
from Crypto import Random | ||
except ImportError: | ||
raise ImportError("Missing dependency: pyCryptodome") | ||
import hashlib | ||
import base64 | ||
|
||
|
||
class AESCipher(object): | ||
""" | ||
A classical AES Cipher. Can use any size of data and any size of password thanks to padding. | ||
Also ensure the coherence and the type of the data with a unicode to byte converter. | ||
""" | ||
def __init__(self, key): | ||
self.bs = 32 | ||
self.key = hashlib.sha256(AESCipher.str_to_bytes(key)).digest() | ||
|
||
@staticmethod | ||
def str_to_bytes(data): | ||
u_type = type(b''.decode('utf8')) | ||
if isinstance(data, u_type): | ||
return data.encode('utf8') | ||
return data | ||
|
||
def _pad(self, s): | ||
return s + (self.bs - len(s) % self.bs) * AESCipher.str_to_bytes(chr(self.bs - len(s) % self.bs)) | ||
|
||
@staticmethod | ||
def _unpad(s): | ||
return s[:-ord(s[len(s) - 1:])] | ||
|
||
def encrypt(self, raw): | ||
raw = self._pad(AESCipher.str_to_bytes(raw)) | ||
iv = Random.new().read(AES.block_size) | ||
cipher = AES.new(self.key, AES.MODE_CBC, iv) | ||
return base64.b64encode(iv + cipher.encrypt(raw)).decode('utf-8') | ||
|
||
def decrypt(self, enc): | ||
enc = base64.b64decode(enc) | ||
iv = enc[:AES.block_size] | ||
cipher = AES.new(self.key, AES.MODE_CBC, iv) | ||
return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8') | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from .base import ( | ||
InRamConfigurationStore, | ||
InRamPlainKeyStore, | ||
InRamEncryptedKeyStore, | ||
SqliteConfigurationStore, | ||
SqlitePlainKeyStore, | ||
SqliteEncryptedKeyStore | ||
) | ||
from .sqlite import SQLiteFile | ||
|
||
__all__ = [ | ||
"base", | ||
"sqlite", | ||
"ram" | ||
] | ||
|
||
|
||
def get_default_config_store(): | ||
return SqliteConfigurationStore() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import os | ||
import logging | ||
|
||
from .masterpassword import MasterPassword | ||
from .interfaces import KeyInterface, ConfigInterface | ||
from .ram import InRamStore | ||
from .sqlite import SQLiteStore | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
# Configuration | ||
class InRamConfigurationStore(InRamStore, ConfigInterface): | ||
""" A simple example that shows how to set defaults | ||
for the Base Store | ||
""" | ||
pass | ||
|
||
|
||
class SqliteConfigurationStore(SQLiteStore, ConfigInterface): | ||
""" This is the configuration storage that stores key/value | ||
pairs in the `config` table of the SQLite3 database. | ||
""" | ||
__tablename__ = "config" | ||
__key__ = "key" | ||
__value__ = "value" | ||
|
||
|
||
# Keys | ||
class InRamPlainKeyStore(InRamStore, KeyInterface): | ||
""" A simple Store that stores keys unencrypted in RAM | ||
""" | ||
def getPublicKeys(self): | ||
return [k for k, v in self.items()] | ||
|
||
def getPrivateKeyForPublicKey(self, pub): | ||
return self.get(str(pub), None) | ||
|
||
def add(self, wif, pub): | ||
self[str(pub)] = str(wif) | ||
|
||
def delete(self, pub): | ||
InRamStore.delete(self, str(pub)) | ||
|
||
|
||
class InRamEncryptedKeyStore(MasterPassword, InRamStore, KeyInterface): | ||
|
||
# Interface to deal with encrypted keys | ||
def getPublicKeys(self): | ||
return [k for k, v in self.items()] | ||
|
||
def getPrivateKeyForPublicKey(self, pub): | ||
assert self.unlocked() | ||
wif = self.get(str(pub), None) | ||
if wif: | ||
return self.decrypt(wif) # From Masterpassword | ||
|
||
def add(self, wif, pub): | ||
assert self.unlocked() # From Masterpassword | ||
self[str(pub)] = self.encrypt(str(wif)) # From Masterpassword | ||
|
||
def delete(self, pub): | ||
InRamStore.delete(self, str(pub)) | ||
|
||
def is_encrypted(self): | ||
return True | ||
|
||
def locked(self): | ||
return MasterPassword.locked(self) | ||
|
||
def unlock(self, password): | ||
return MasterPassword.unlock(self, password) | ||
|
||
def lock(self): | ||
return MasterPassword.lock(self) | ||
|
||
|
||
class SqlitePlainKeyStore(SQLiteStore, KeyInterface): | ||
""" This is the key storage that stores the public key and the | ||
**unencrypted** private key in the `keys` table in the SQLite3 | ||
database. | ||
""" | ||
__tablename__ = 'keys' | ||
__key__ = "pub" | ||
__value__ = "wif" | ||
|
||
def getPublicKeys(self): | ||
return [k for k, v in self.items()] | ||
|
||
def getPrivateKeyForPublicKey(self, pub): | ||
return self[pub] | ||
|
||
def add(self, wif, pub=None): | ||
self[str(pub)] = str(wif) | ||
|
||
def delete(self, pub): | ||
SQLiteStore.delete(self, str(pub)) | ||
|
||
|
||
class SqliteEncryptedKeyStore(MasterPassword, SQLiteStore, KeyInterface): | ||
""" This is the key storage that stores the public key and the | ||
**encrypted** private key in the `keys` table in the SQLite3 database. | ||
""" | ||
__tablename__ = 'keys' | ||
__key__ = "pub" | ||
__value__ = "wif" | ||
|
||
def __init__(self, *args, **kwargs): | ||
SQLiteStore.__init__(self, *args, **kwargs) | ||
MasterPassword.__init__(self, *args, **kwargs) | ||
|
||
# Interface to deal with encrypted keys | ||
def getPublicKeys(self): | ||
return [k for k, v in self.items()] | ||
|
||
def getPrivateKeyForPublicKey(self, pub): | ||
assert self.unlocked() | ||
wif = self.get(str(pub), None) | ||
if wif: | ||
return self.decrypt(wif) # From Masterpassword | ||
|
||
def add(self, wif, pub): | ||
assert self.unlocked() # From Masterpassword | ||
self[str(pub)] = self.encrypt(str(wif)) # From Masterpassword | ||
|
||
def delete(self, pub): | ||
SQLiteStore.delete(self, str(pub)) | ||
|
||
def is_encrypted(self): | ||
return True | ||
|
||
def locked(self): | ||
return MasterPassword.locked(self) | ||
|
||
def unlock(self, password): | ||
return MasterPassword.unlock(self, password) | ||
|
||
def lock(self): | ||
return MasterPassword.lock(self) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class WrongMasterPasswordException(Exception): | ||
""" The password provided could not properly unlock the wallet | ||
""" | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
class StoreInterface: | ||
|
||
defaults = {} | ||
|
||
def __init__(self, *args, **kwargs): | ||
pass | ||
|
||
def __setitem__(self, key, value): | ||
""" Sets an item in the store | ||
""" | ||
pass | ||
|
||
def __getitem__(self, key): | ||
""" Gets an item from the store as if it was a dictionary | ||
""" | ||
pass | ||
|
||
def __iter__(self): | ||
""" Iterates through the store | ||
""" | ||
pass | ||
|
||
def __len__(self): | ||
""" return lenght of store | ||
""" | ||
pass | ||
|
||
def __contains__(self, key): | ||
""" Tests if a key is contained in the store. | ||
""" | ||
pass | ||
|
||
def items(self): | ||
""" returns all items off the store as tuples | ||
""" | ||
pass | ||
|
||
def get(self, key, default=None): | ||
""" Return the key if exists or a default value | ||
""" | ||
pass | ||
|
||
# Specific for this library | ||
def delete(self, key): | ||
""" Delete a key from the store | ||
""" | ||
pass | ||
|
||
def wipe(self): | ||
""" Wipe the store | ||
""" | ||
pass | ||
|
||
|
||
class KeyInterface(StoreInterface): | ||
""" The BaseKeyStore defines the interface for key storage | ||
""" | ||
|
||
# Interface to deal with encrypted keys | ||
def getPublicKeys(self): | ||
""" Returns the public keys stored in the database | ||
""" | ||
pass | ||
|
||
def getPrivateKeyForPublicKey(self, pub): | ||
""" Returns the (possibly encrypted) private key that | ||
corresponds to a public key | ||
:param str pub: Public key | ||
The encryption scheme is BIP38 | ||
""" | ||
pass | ||
|
||
def add(self, wif, pub=None): | ||
""" Add a new public/private key pair (correspondence has to be | ||
checked elsewhere!) | ||
:param str pub: Public key | ||
:param str wif: Private key | ||
""" | ||
pass | ||
|
||
def delete(self, pub): | ||
""" Delete a pubkey/privatekey pair from the store | ||
""" | ||
pass | ||
|
||
def is_encrypted(self): | ||
""" Returns True/False to indicate required use of unlock | ||
""" | ||
return False | ||
|
||
def unlock(self, password): | ||
""" Tries to unlock the wallet if required | ||
""" | ||
pass | ||
|
||
def locked(self): | ||
""" is the wallet locked? | ||
""" | ||
return False | ||
|
||
def lock(self): | ||
""" Lock the wallet again | ||
""" | ||
pass | ||
|
||
|
||
class ConfigInterface(StoreInterface): | ||
""" The BaseKeyStore defines the interface for key storage | ||
Inherits StoreInterface. Not additional methods required. | ||
""" | ||
pass |
Oops, something went wrong.