Completed
Push — master ( 7beec5...72ed44 )
by Marek
17s queued 14s
created

ige.Authentication.encode()   A

Complexity

Conditions 3

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nop 2
dl 0
loc 10
rs 9.95
c 0
b 0
f 0
1
import binascii
2
from ige import SecurityException, log
3
import hashlib
4
import os
5
import rsa
6
import time
7
8
defaultMethod = "rsa"
9
10
# support for RSA keys
11
publicKey = None
12
privateKey = None
13
14
def init(configDir, authMethod, size=2048):
15
    # RSA needs init
16
    if authMethod == "rsa":
17
        initRSAKeys(configDir, size)
18
19
def _generateKeys(privatePath, publicPath, size):
20
    global publicKey, privateKey
21
    # no keys, let's generate them
22
    log.message("Generating RSA keys of size {0}, please wait...".format(size))
23
    publicKey, privateKey = rsa.newkeys(size)
24
    with open(privatePath, 'w') as privKeyFile:
25
        privKeyFile.write(privateKey.save_pkcs1())
26
    with open(publicPath, 'w') as pubKeyFile:
27
        pubKeyFile.write(publicKey.save_pkcs1())
28
29
def initRSAKeys(configDir, size):
30
    """Load or generate and save RSA keys"""
31
    global publicKey, privateKey
32
    privatePath = os.path.join(configDir, 'private.pem')
33
    publicPath = os.path.join(configDir, 'public.pem')
34
    try:
35
        log.message("Loading PRIVATE RSA key")
36
        with open(privatePath, 'rb') as privKeyFile:
37
            privateKey = rsa.PrivateKey.load_pkcs1(privKeyFile.read())
38
        log.message("Loading PUBLIC RSA key")
39
        with open(publicPath, 'rb') as pubKeyFile:
40
            publicKey = rsa.PublicKey.load_pkcs1(pubKeyFile.read())
41
    except ValueError:
42
        _generateKeys(privatePath, publicPath, size)
43
    except IOError:
44
        _generateKeys(privatePath, publicPath, size)
45
46
def getPublicKey():
47
    """Get current RSA public key"""
48
    assert publicKey is not None
49
    return publicKey
50
51
def getPrivateKey():
52
    """Get current RSA private key"""
53
    assert privateKey is not None
54
    return privateKey
55
56
#
57
def getMethod(challenge):
58
    return challenge.split(":")[0]
59
60
def getWelcomeString(method = "rsa"):
61
    """Return welcome string (typically a challenge)"""
62
    if method == "sha256":
63
        return "sha256:" + hashlib.sha256(str(time.time())).hexdigest()
64
    elif method == "rsa":
65
        publicKey = getPublicKey()
66
        return "rsa:%s:%s" % (publicKey.n, publicKey.e)
67
    raise SecurityException("Unsupported authentication method %s" % str(method))
68
69
def encode(password, challenge):
70
    """Encode password using auth method specified in the challenge"""
71
    method = getMethod(challenge)
72
    if method == "sha256":
73
        return hashlib.sha256(password + challenge).hexdigest()
74
    elif method == "rsa":
75
        dummy, n, e = challenge.split(":")
76
        key = rsa.PublicKey(int(n), int(e))
77
        return binascii.hexlify(rsa.encrypt(password.encode('utf-8'), key))
78
    raise SecurityException("Unsupported authentication method %s" % str(method))
79
80
def verify(encodedPassword, account, challenge):
81
    """Verify password based on client encoded password and auth method"""
82
    method = getMethod(challenge)
83
    unwrappedPassword = unwrapUserPassword(encodedPassword, challenge)
84
85
    return account.hashPassword(unwrappedPassword) == account.passwd
86
87
def unwrapUserPassword(password, challenge):
88
    """Decode password according to auth method (if possible)"""
89
    method = getMethod(challenge)
90
    if method == "sha256":
91
        return password
92
    elif method == "rsa":
93
        return rsa.decrypt(binascii.unhexlify(password), getPrivateKey())
94
    raise SecurityException("Unsupported authentication method %s" % str(method))
95
96