Commit 2f838d7a authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki

introduce AES cipher for much stronger encryption. the old implementation...

introduce AES cipher for much stronger encryption. the old implementation (Cesar cipher) is still kept for backward compatibility, but it is recommended to switch to AES cipher.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@43825 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 11351205
......@@ -55,6 +55,70 @@ from Products.ERP5Security.ERP5UserManager import ERP5UserManager,\
SUPER_USER,\
_AuthenticationFailure
from Crypto.Cipher import AES
from base64 import b16decode, b16encode
class AESCipher:
mode = AES.MODE_CFB
def __init__(self, encryption_key):
# AES key must be either 16, 24, or 32 bytes long
self.encryption_key = encryption_key.ljust(32)[:32]
def encrypt(self, login):
encryptor = AES.new(self.encryption_key, self.mode)
return b16encode(encryptor.encrypt(login.ljust(((len(login)-1)/16+1)*16)))
def decrypt(self, crypted_login):
decryptor = AES.new(self.encryption_key, self.mode)
return decryptor.decrypt(b16decode(crypted_login)).rstrip()
# This cipher is weak. Do not use.
class CesarCipher:
block_length = 3
def __init__(self, encryption_key):
self.encryption_key = encryption_key
self.encrypted_key = self.transformKey(self.encryption_key);
def transformKey(self,key):
"""Transform the key to number for encryption"""
encrypt_key = []
for letter in key:
encrypt_key.append(ord(letter))
return encrypt_key
def encrypt(self, login):
crypted_login = ''
key_length = len(self.encrypted_key)
for i in range(0,len(login)):
delta = i % key_length
crypted_letter = str(ord(login[i]) + self.encrypted_key[delta])
#ord is the inverse of chr() for 8-bit (1111 1111 = 256)
#so crypted_letter max id 512
#we ajust lenght to be able to decrypt by block
crypted_letter = crypted_letter.rjust(self.block_length, '0')
crypted_login += crypted_letter
return crypted_login
def decrypt(self, crypted_login):
login = ''
#check lenght of the string
clogin_length = len(crypted_login)
if clogin_length % self.block_length != 0:
raise ValueError, "Lenght is not good"
#decrypt block per block
position = 0
key_length = len(self.encrypted_key)
for block in range(0, clogin_length, self.block_length):
delta = position % key_length
crypted_letter = crypted_login[block:block + self.block_length]
crypted_letter = int(crypted_letter) - self.encrypted_key[delta]
letter = chr(crypted_letter)
login += letter
position += 1
return login
class ILoginEncryptionPlugin(Interface):
"""Contract for possible ERP5 Key Auth Plugin"""
......@@ -70,12 +134,14 @@ manage_addERP5KeyAuthPluginForm = PageTemplateFile(
'www/ERP5Security_addERP5KeyAuthPlugin', globals(),
__name__='manage_addERP5KeyAuthPluginForm')
def addERP5KeyAuthPlugin(dispatcher, id,title=None,\
encryption_key='',cookie_name='',\
def addERP5KeyAuthPlugin(dispatcher, id, title=None,\
encryption_key='', cipher='AES', cookie_name='',\
default_cookie_name='',REQUEST=None):
""" Add a ERP5KeyAuthPlugin to a Pluggable Auth Service. """
plugin = ERP5KeyAuthPlugin( id, title,encryption_key,cookie_name,default_cookie_name)
plugin = ERP5KeyAuthPlugin(id=id, title=title, encryption_key=encryption_key,
cipher=cipher, cookie_name=cookie_name,
default_cookie_name=default_cookie_name)
dispatcher._setObject(plugin.getId(), plugin)
if REQUEST is not None:
......@@ -103,11 +169,9 @@ class ERP5KeyAuthPlugin(ERP5UserManager, CookieAuthHelper):
meta_type = "ERP5 Key Authentication"
login_path = 'login_form'
security = ClassSecurityInfo()
block_length = 3
cookie_name = "__ac_key"
default_cookie_name = "__ac"
encryption_key = ''
encrypted_key = ''
manage_options = ( ( { 'label': 'Edit',
'action': 'manage_editERP5KeyAuthPluginForm', }
......@@ -127,7 +191,8 @@ class ERP5KeyAuthPlugin(ERP5UserManager, CookieAuthHelper):
+ CookieAuthHelper._properties[:]
)
def __init__(self, id, title=None, encryption_key='', cookie_name='', default_cookie_name=''):
def __init__(self, id, title=None, encryption_key='', cipher='AES',
cookie_name='', default_cookie_name=''):
#Check parameters
if cookie_name is None or cookie_name == '':
cookie_name = id
......@@ -142,56 +207,27 @@ class ERP5KeyAuthPlugin(ERP5UserManager, CookieAuthHelper):
self.cookie_name = cookie_name
self.default_cookie_name = default_cookie_name
self.encryption_key = encryption_key
self.encrypted_key = self.transformKey(self.encryption_key);
self.cipher = cipher
def _getCipher(self):
# If self.cipher does not exist, we use CesarCipher only for
# backward compatibility.
return getattr(self, 'cipher', 'Cesar')
################################
# ILoginEncryptionPlugin #
################################
security.declarePrivate('transformKey')
def transformKey(self,key):
"""Transform the key to number for encryption"""
encrypt_key = []
for letter in key:
encrypt_key.append(ord(letter))
return encrypt_key
security.declarePublic('encrypt')
def encrypt(self,login):
"""Encrypt the login"""
crypted_login = ''
key_length = len(self.encrypted_key)
for i in range(0,len(login)):
delta = i % key_length
crypted_letter = str(ord(login[i]) + self.encrypted_key[delta])
#ord is the inverse of chr() for 8-bit (1111 1111 = 256)
#so crypted_letter max id 512
#we ajust lenght to be able to decrypt by block
crypted_letter = crypted_letter.rjust(self.block_length, '0')
crypted_login += crypted_letter
return crypted_login
cipher = globals()['%sCipher' % self._getCipher()](self.encryption_key)
return cipher.encrypt(login)
security.declarePrivate('decrypt')
def decrypt(self, crypted_login):
"""Decrypt string and return the login"""
login = ''
#check lenght of the string
clogin_length = len(crypted_login)
if clogin_length % self.block_length != 0:
raise ValueError, "Lenght is not good"
#decrypt block per block
position = 0
key_length = len(self.encrypted_key)
for block in range(0, clogin_length, self.block_length):
delta = position % key_length
crypted_letter = crypted_login[block:block + self.block_length]
crypted_letter = int(crypted_letter) - self.encrypted_key[delta]
letter = chr(crypted_letter)
login += letter
position += 1
return login
cipher = globals()['%sCipher' % self._getCipher()](self.encryption_key)
return cipher.decrypt(crypted_login)
####################################
#ILoginPasswordHostExtractionPlugin#
......@@ -360,7 +396,8 @@ class ERP5KeyAuthPlugin(ERP5UserManager, CookieAuthHelper):
__name__='manage_editERP5KeyAuthPluginForm' )
security.declareProtected( ManageUsers, 'manage_editKeyAuthPlugin' )
def manage_editKeyAuthPlugin(self, encryption_key,cookie_name,default_cookie_name, RESPONSE=None):
def manage_editKeyAuthPlugin(self, encryption_key, cipher, cookie_name,
default_cookie_name, RESPONSE=None):
"""Edit the object"""
error_message = ''
......@@ -373,7 +410,12 @@ class ERP5KeyAuthPlugin(ERP5UserManager, CookieAuthHelper):
error_message += 'Invalid key value '
else:
self.encryption_key = encryption_key
self.encrypted_key = self.transformKey(self.encryption_key);
#Save cipher
if cipher == '' or cipher is None:
error_message += 'Invalid cipher value '
else:
self.cipher = cipher
#Save cookie name
if cookie_name == '' or cookie_name is None:
......
......@@ -36,6 +36,20 @@
<input type="text" name="encryption_key" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Cipher
</div>
</td>
<td align="left" valign="top">
<select name="cipher">
<tal:block tal:repeat="c python:[('AES', 'AES'), ('Cesar', 'Cesar (DO NOT USE)')]">
<option value="value" tal:attributes="value python:c[0]" tal:content="python:c[1]" />
</tal:block>
</select>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -8,6 +8,7 @@
<form action="manage_editKeyAuthPlugin" method="POST">
<table tal:define="encryption_key request/encryption_key|context/encryption_key|string:;
cipher request/cipher|context/cipher|string:Cesar;
default_cookie_name request/default_cookie_name|context/default_cookie_name|string:;
cookie_name request/cookie_name|context/cookie_name|string:;">
......@@ -18,6 +19,20 @@
tal:attributes="value encryption_key;" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Cipher
</div>
</td>
<td align="left" valign="top">
<select name="cipher">
<tal:block tal:repeat="c python:[('AES', 'AES'), ('Cesar', 'Cesar (DO NOT USE)')]">
<option value="value" tal:attributes="value python:c[0]; selected python:c[0]==cipher" tal:content="python:c[1]" />
</tal:block>
</select>
</td>
</tr>
<tr>
<td> Cookie Name </td>
<td>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment