Skip to content
This repository was archived by the owner on May 9, 2020. It is now read-only.

Commit b8cc53c

Browse files
fpedrinikamilbednarz
authored andcommitted
Py3 support for encrypted databags code
1 parent eafc2f6 commit b8cc53c

File tree

3 files changed

+33
-21
lines changed

3 files changed

+33
-21
lines changed

chef/aes.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import os
2+
import sys
23

34
from ctypes import *
4-
from rsa import _eay, SSLError
5+
from chef.rsa import _eay, SSLError
56

67
c_int_p = POINTER(c_int)
78

@@ -89,7 +90,7 @@ def __init__(self, key, iv, salt='12345678'):
8990
self.key_data = create_string_buffer(key)
9091
self.iv = create_string_buffer(iv)
9192
self.encryptor = self.decryptor = None
92-
self.salt = create_string_buffer(salt)
93+
self.salt = create_string_buffer(salt.encode('utf8'))
9394

9495
self.encryptor = EVP_CIPHER_CTX()
9596
self._init_cipher(byref(self.encryptor), 1)
@@ -105,6 +106,9 @@ def _init_cipher(self, ctypes_cipher, crypt_mode):
105106
EVP_CIPHER_CTX_set_padding(ctypes_cipher, c_int(1))
106107

107108
def _process_data(self, ctypes_cipher, data):
109+
# Guard against str passed in when using python3
110+
if sys.version_info[0] > 2 and isinstance(data, str):
111+
data = data.encode('utf8')
108112
length = c_int(len(data))
109113
buf_length = c_int(length.value + AES_BLOCK_SIZE)
110114
buf = create_string_buffer(buf_length.value)
@@ -123,7 +127,3 @@ def encrypt(self, data):
123127

124128
def decrypt(self, data):
125129
return self._process_data(byref(self.decryptor), data)
126-
127-
128-
129-

chef/encrypted_data_bag_item.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
from chef.exceptions import ChefUnsupportedEncryptionVersionError, ChefDecryptionError
2-
from chef.aes import AES256Cipher
2+
from chef.aes import AES256Cipher, EVP_MAX_IV_LENGTH
33
from chef.utils import json
44
from chef.data_bag import DataBagItem
55

66
import os
7+
import sys
78
import hmac
89
import base64
910
import chef
1011
import hashlib
12+
import binascii
1113
import itertools
14+
import six
15+
from six.moves import filterfalse, zip_longest
16+
1217

1318
class EncryptedDataBagItem(DataBagItem):
1419
SUPPORTED_ENCRYPTION_VERSIONS = (1,2)
@@ -39,10 +44,10 @@ class EncryptorVersion1(object):
3944
VERSION = 1
4045

4146
def __init__(self, key, data):
42-
self.plain_key = key
43-
self.key = hashlib.sha256(key).digest()
47+
self.plain_key = key.encode('utf8')
48+
self.key = hashlib.sha256(key.encode('utf8')).digest()
4449
self.data = data
45-
self.iv = os.urandom(8).encode('hex')
50+
self.iv = binascii.hexlify(os.urandom(int(EVP_MAX_IV_LENGTH/2)))
4651
self.encryptor = AES256Cipher(key=self.key, iv=self.iv)
4752
self.encrypted_data = None
4853

@@ -54,8 +59,8 @@ def encrypt(self):
5459

5560
def to_dict(self):
5661
return {
57-
"encrypted_data": base64.standard_b64encode(self.encrypt()),
58-
"iv": base64.standard_b64encode(self.iv),
62+
"encrypted_data": base64.standard_b64encode(self.encrypt()).decode('utf8'),
63+
"iv": base64.standard_b64encode(self.iv).decode('utf8'),
5964
"version": self.VERSION,
6065
"cipher": "aes-256-cbc"
6166
}
@@ -78,11 +83,11 @@ def _generate_hmac(self):
7883

7984
def to_dict(self):
8085
result = super(EncryptorVersion2, self).to_dict()
81-
result['hmac'] = base64.standard_b64encode(self.hmac)
86+
result['hmac'] = base64.standard_b64encode(self.hmac).decode('utf8')
8287
return result
8388

8489
def get_decryption_version(data):
85-
if data.has_key('version'):
90+
if 'version' in data:
8691
if str(data['version']) in map(str, EncryptedDataBagItem.SUPPORTED_ENCRYPTION_VERSIONS):
8792
return data['version']
8893
else:
@@ -99,7 +104,7 @@ def create_decryptor(key, data):
99104

100105
class DecryptorVersion1(object):
101106
def __init__(self, key, data, iv):
102-
self.key = hashlib.sha256(key).digest()
107+
self.key = hashlib.sha256(key.encode('utf8')).digest()
103108
self.data = base64.standard_b64decode(data)
104109
self.iv = base64.standard_b64decode(iv)
105110
self.decryptor = AES256Cipher(key=self.key, iv=self.iv)
@@ -120,10 +125,16 @@ def __init__(self, key, data, iv, hmac):
120125
self.encoded_data = data
121126

122127
def _validate_hmac(self):
123-
expected_hmac = hmac.new(self.key, self.encoded_data, hashlib.sha256).digest()
128+
encoded_data = self.encoded_data.encode('utf8')
129+
130+
expected_hmac = hmac.new(self.key, encoded_data, hashlib.sha256).digest()
124131
valid = len(expected_hmac) ^ len(self.hmac)
125-
for expected_char, candidate_char in itertools.izip_longest(expected_hmac, self.hmac):
126-
valid |= ord(expected_char) ^ ord(candidate_char)
132+
for expected_char, candidate_char in zip_longest(expected_hmac, self.hmac):
133+
if sys.version_info[0] > 2:
134+
valid |= expected_char ^ candidate_char
135+
else:
136+
valid |= ord(expected_char) ^ ord(candidate_char)
137+
127138
return valid == 0
128139

129140
def decrypt(self):

chef/tests/test_aes.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
class AES256CipherTestCase(ChefTestCase):
1111
def setUp(self):
1212
super(AES256CipherTestCase, self).setUp()
13-
key = hashlib.sha256(open(os.path.join(TEST_ROOT, 'encryption_key')).read()).digest()
13+
enc_key = open(os.path.join(TEST_ROOT, 'encryption_key')).read()
14+
key = hashlib.sha256(enc_key.encode('utf8')).digest()
1415
iv = base64.standard_b64decode('GLVikZLxG0SWYnb68Pr8Ag==\n')
1516
self.cipher = AES256Cipher(key, iv)
1617

1718
def test_encrypt(self):
1819
encrypted_value = self.cipher.encrypt('{"json_wrapper":"secr3t c0d3"}')
19-
self.assertEquals(base64.standard_b64encode(encrypted_value).strip(), "Ym5T8umtSd0wgjDYq1ZDK5dAh6OjgrTxlloGNf2xYhg=")
20+
self.assertEquals(base64.standard_b64encode(encrypted_value).strip(), "Ym5T8umtSd0wgjDYq1ZDK5dAh6OjgrTxlloGNf2xYhg=".encode('utf8'))
2021

2122
def test_decrypt(self):
2223
decrypted_value = self.cipher.decrypt(base64.standard_b64decode('Ym5T8umtSd0wgjDYq1ZDK5dAh6OjgrTxlloGNf2xYhg=\n'))
23-
self.assertEquals(decrypted_value, '{"json_wrapper":"secr3t c0d3"}')
24+
self.assertEquals(decrypted_value, '{"json_wrapper":"secr3t c0d3"}'.encode('utf8'))

0 commit comments

Comments
 (0)