2
0
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:
Jarrod Johnson 2013-08-16 17:01:18 -04:00
parent 71e1607b57
commit dc8c9d091c
2 changed files with 139 additions and 122 deletions

View File

@ -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
View 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)