mirror of
https://github.com/xcat2/confluent.git
synced 2025-02-16 18:49:04 +00:00
Split out crypt stuff into it's own file
This commit is contained in:
parent
71e1607b57
commit
dc8c9d091c
@ -32,9 +32,6 @@ import math
|
||||
import os
|
||||
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import HMAC
|
||||
from Crypto.Hash import SHA25sterkey = None
|
||||
_masterintegritykey = None
|
||||
_cfgstore = {}
|
||||
|
||||
@ -102,125 +99,6 @@ def _expand_expression(attribute, nodeobj):
|
||||
pass
|
||||
|
||||
|
||||
def unlock_config_keys(passphrase=None):
|
||||
_init_masterkey(passphrase)
|
||||
|
||||
|
||||
def _pbkdf2(passphrase, salt, iterations, size):
|
||||
blocks = int(math.ceil(size/32.0)) # Hardcoded to SHA256 behavior
|
||||
retkey = ""
|
||||
for block in xrange(blocks):
|
||||
citerations = iterations
|
||||
tsalt = salt + chr(block)
|
||||
currval = HMAC.new(passphrase, tsalt, SHA256).digest()
|
||||
currarray = array.array('L',currval)
|
||||
while citerations > 1:
|
||||
currval = HMAC.new(passphrase, currval).digest()
|
||||
nextarray = array.array('L',currval)
|
||||
for index in range(nextarray):
|
||||
currarray[index] = currarray[index] ^ nextarray[index]
|
||||
currval = currarray.tostring()
|
||||
currarray = nextarray
|
||||
citerations = citerations - 1
|
||||
retkey += currval
|
||||
return retkey[:size]
|
||||
|
||||
|
||||
def _derive_keys(passphrase, salt):
|
||||
tmpkey = _pbkdf2(passphrase, salt, 50000, 32)
|
||||
finalkey = _pbkdf2(tmpkey, salt, 50000, 96)
|
||||
return (finalkey[:32],finalkey[32:])
|
||||
|
||||
|
||||
def _get_protected_key(keydict, passphrase):
|
||||
if keydict['unencryptedvalue']:
|
||||
return keydict['unencryptedvalue']
|
||||
# TODO(jbjohnso): check for TPM sealing
|
||||
if 'passphraseprotected' in keydict:
|
||||
if passphrase is None:
|
||||
raise Exception("Passphrase protected secret requires passhrase")
|
||||
for pp in keydict['passphraseprotected']:
|
||||
salt = pp[0]
|
||||
privkey, integkey = _derive_keys(passphrase, salt)
|
||||
return _decrypt_value(pp[1:], key=privkey, integritykey=integkey)
|
||||
else:
|
||||
raise Exception("No available decryption key")
|
||||
|
||||
|
||||
def _format_key(key, passphrase=None):
|
||||
if passphrase is not None:
|
||||
salt = os.urandom(32)
|
||||
privkey, integkey = _derive_keys(passphrase, salt)
|
||||
cval = _crypt_value(key, key=privkey, integritykey=integkey)
|
||||
return {"passphraseprotected": cval}
|
||||
else:
|
||||
return {"unencryptedvalue": key}
|
||||
|
||||
|
||||
def _init_masterkey(passphrase=None):
|
||||
if 'master_privacy_key' in _cfgstore['globals']:
|
||||
_masterkey = _get_protected_key(
|
||||
_cfgstore['globals']['master_privacy_key'],
|
||||
passphrase=passphrase)
|
||||
else:
|
||||
_masterkey = os.urandom(32)
|
||||
_cfgstore['globals']['master_privacy_key'] = _format_key(_masterkey,
|
||||
passphrase=passphrase)
|
||||
if 'master_integrity_key' in _cfgstore['globals']:
|
||||
_masterintegritykey = _get_protected_key(
|
||||
_cfgstore['globals']['master_integrity_key'],
|
||||
passphrase=passphrase
|
||||
)
|
||||
else:
|
||||
_masterintegritykey = os.urandom(64)
|
||||
_cfgstore['globals']['master_integrity_key'] = _format_key(
|
||||
_masterintegritykey,
|
||||
passphrase=passphrase
|
||||
)
|
||||
|
||||
|
||||
|
||||
def _decrypt_value(cryptvalue,
|
||||
key=_masterkey,
|
||||
integritykey=_masterintegritykey):
|
||||
iv, cipherdata, hmac = cryptvalue
|
||||
if _masterkey is None or _masterintegritykey is None:
|
||||
_init_masterkey()
|
||||
check_hmac = HMAC.new(_masterintegritykey, cryptvalue, SHA256).digest()
|
||||
if hmac != check_hmac:
|
||||
raise Exception("bad HMAC value on crypted value")
|
||||
decrypter = AES.new(_masterkey, AES.MODE_CBC, iv)
|
||||
value = decrypter.decrypt(cryptvalue)
|
||||
padsize = ord(value[-1])
|
||||
pad = value[-padsize:]
|
||||
# Note that I cannot grasp what could be done with a subliminal
|
||||
# channel in padding in this case, but check the padding anyway
|
||||
for padbyte in pad:
|
||||
if ord(padbyte) != padsize:
|
||||
raise Exception("bad padding in encrypted value")
|
||||
return value[0:-padsize]
|
||||
|
||||
|
||||
def _crypt_value(value,
|
||||
key=_masterkey,
|
||||
integritykey=_masterintegritykey):
|
||||
# encrypt given value
|
||||
# PKCS7 is the padding scheme to employ, if no padded needed, pad with 16
|
||||
# check HMAC prior to attempting decrypt
|
||||
if key is None or integritykey is None:
|
||||
_init_masterkey()
|
||||
key=_masterkey
|
||||
integritykey=_masterintegritykey
|
||||
iv = os.urandom(16)
|
||||
crypter = AES.new(key, ASE.MOD_CBC, iv)
|
||||
neededpad = 16 - (len(value) % 16)
|
||||
pad = chr(neededpad) * neededpad
|
||||
value = value + pad
|
||||
cryptval = crypter.encrypt(value)
|
||||
hmac = HMAC.new(integritykey, cryptval, SHA256).digest()
|
||||
return (iv, cryptval, hmac)
|
||||
|
||||
|
||||
class NodeAttribs(object):
|
||||
def __init__(self, nodes=[], attributes=[], tenant=0):
|
||||
self._nodelist = collecitons.dequeue(nodes)
|
||||
|
139
confluent/cryptutils.py
Normal file
139
confluent/cryptutils.py
Normal file
@ -0,0 +1,139 @@
|
||||
# IBM(c) 2013
|
||||
|
||||
# This module provides cryptographic convenience functions, largely to be
|
||||
# used by config.py to protect/unlock configuration as appropriopriate.
|
||||
# The default behavior provides no meaningful protection, all encrypted
|
||||
# values are linked to a master key that is stored in the clear.
|
||||
# meanigful protection comes when the user elects to protect the key
|
||||
# by passphrase and optionally TPM
|
||||
|
||||
import array
|
||||
import math
|
||||
import os
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import HMAC
|
||||
from Crypto.Hash import SHA256
|
||||
|
||||
_masterkey = None
|
||||
_masterintegritykey = None
|
||||
|
||||
|
||||
|
||||
def unlock_config_keys(passphrase=None):
|
||||
_init_masterkey(passphrase)
|
||||
|
||||
|
||||
def _pbkdf2(passphrase, salt, iterations, size):
|
||||
blocks = int(math.ceil(size/32.0)) # Hardcoded to SHA256 behavior
|
||||
retkey = ""
|
||||
for block in xrange(blocks):
|
||||
citerations = iterations
|
||||
tsalt = salt + chr(block)
|
||||
currval = HMAC.new(passphrase, tsalt, SHA256).digest()
|
||||
currarray = array.array('L',currval)
|
||||
while citerations > 1:
|
||||
currval = HMAC.new(passphrase, currval).digest()
|
||||
nextarray = array.array('L',currval)
|
||||
for index in range(len(nextarray)):
|
||||
currarray[index] = currarray[index] ^ nextarray[index]
|
||||
currval = currarray.tostring()
|
||||
currarray = nextarray
|
||||
citerations = citerations - 1
|
||||
retkey += currval
|
||||
return retkey[:size]
|
||||
|
||||
|
||||
def _derive_keys(passphrase, salt):
|
||||
tmpkey = _pbkdf2(passphrase, salt, 50000, 32)
|
||||
finalkey = _pbkdf2(tmpkey, salt, 50000, 96)
|
||||
return (finalkey[:32],finalkey[32:])
|
||||
|
||||
|
||||
def _get_protected_key(keydict, passphrase):
|
||||
if keydict['unencryptedvalue']:
|
||||
return keydict['unencryptedvalue']
|
||||
# TODO(jbjohnso): check for TPM sealing
|
||||
if 'passphraseprotected' in keydict:
|
||||
if passphrase is None:
|
||||
raise Exception("Passphrase protected secret requires passhrase")
|
||||
for pp in keydict['passphraseprotected']:
|
||||
salt = pp[0]
|
||||
privkey, integkey = _derive_keys(passphrase, salt)
|
||||
return _decrypt_value(pp[1:], key=privkey, integritykey=integkey)
|
||||
else:
|
||||
raise Exception("No available decryption key")
|
||||
|
||||
|
||||
def _format_key(key, passphrase=None):
|
||||
if passphrase is not None:
|
||||
salt = os.urandom(32)
|
||||
privkey, integkey = _derive_keys(passphrase, salt)
|
||||
cval = _crypt_value(key, key=privkey, integritykey=integkey)
|
||||
return {"passphraseprotected": cval}
|
||||
else:
|
||||
return {"unencryptedvalue": key}
|
||||
|
||||
|
||||
def _init_masterkey(passphrase=None):
|
||||
if 'master_privacy_key' in _cfgstore['globals']:
|
||||
_masterkey = _get_protected_key(
|
||||
_cfgstore['globals']['master_privacy_key'],
|
||||
passphrase=passphrase)
|
||||
else:
|
||||
_masterkey = os.urandom(32)
|
||||
_cfgstore['globals']['master_privacy_key'] = _format_key(_masterkey,
|
||||
passphrase=passphrase)
|
||||
if 'master_integrity_key' in _cfgstore['globals']:
|
||||
_masterintegritykey = _get_protected_key(
|
||||
_cfgstore['globals']['master_integrity_key'],
|
||||
passphrase=passphrase
|
||||
)
|
||||
else:
|
||||
_masterintegritykey = os.urandom(64)
|
||||
_cfgstore['globals']['master_integrity_key'] = _format_key(
|
||||
_masterintegritykey,
|
||||
passphrase=passphrase
|
||||
)
|
||||
|
||||
|
||||
|
||||
def _decrypt_value(cryptvalue,
|
||||
key=_masterkey,
|
||||
integritykey=_masterintegritykey):
|
||||
iv, cipherdata, hmac = cryptvalue
|
||||
if _masterkey is None or _masterintegritykey is None:
|
||||
_init_masterkey()
|
||||
check_hmac = HMAC.new(_masterintegritykey, cryptvalue, SHA256).digest()
|
||||
if hmac != check_hmac:
|
||||
raise Exception("bad HMAC value on crypted value")
|
||||
decrypter = AES.new(_masterkey, AES.MODE_CBC, iv)
|
||||
value = decrypter.decrypt(cryptvalue)
|
||||
padsize = ord(value[-1])
|
||||
pad = value[-padsize:]
|
||||
# Note that I cannot grasp what could be done with a subliminal
|
||||
# channel in padding in this case, but check the padding anyway
|
||||
for padbyte in pad:
|
||||
if ord(padbyte) != padsize:
|
||||
raise Exception("bad padding in encrypted value")
|
||||
return value[0:-padsize]
|
||||
|
||||
|
||||
def _crypt_value(value,
|
||||
key=_masterkey,
|
||||
integritykey=_masterintegritykey):
|
||||
# encrypt given value
|
||||
# PKCS7 is the padding scheme to employ, if no padded needed, pad with 16
|
||||
# check HMAC prior to attempting decrypt
|
||||
if key is None or integritykey is None:
|
||||
_init_masterkey()
|
||||
key=_masterkey
|
||||
integritykey=_masterintegritykey
|
||||
iv = os.urandom(16)
|
||||
crypter = AES.new(key, ASE.MOD_CBC, iv)
|
||||
neededpad = 16 - (len(value) % 16)
|
||||
pad = chr(neededpad) * neededpad
|
||||
value = value + pad
|
||||
cryptval = crypter.encrypt(value)
|
||||
hmac = HMAC.new(integritykey, cryptval, SHA256).digest()
|
||||
return (iv, cryptval, hmac)
|
Loading…
x
Reference in New Issue
Block a user