Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
ansible
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
ansible
Commits
8a253bf5
Commit
8a253bf5
authored
Feb 24, 2014
by
jctanner
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6151 from jctanner/vault_rewrite
Vault rewrite, pass 1
parents
e999881f
9c9f15ac
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
221 additions
and
332 deletions
+221
-332
bin/ansible-vault
+30
-26
lib/ansible/utils/__init__.py
+6
-5
lib/ansible/utils/vault.py
+185
-301
No files found.
bin/ansible-vault
View file @
8a253bf5
...
@@ -20,13 +20,13 @@
...
@@ -20,13 +20,13 @@
# example playbook to bootstrap this script in the examples/ dir which
# example playbook to bootstrap this script in the examples/ dir which
# installs ansible and sets it up to run on cron.
# installs ansible and sets it up to run on cron.
import
os
import
sys
import
sys
import
traceback
import
traceback
from
ansible
import
utils
from
ansible
import
utils
from
ansible
import
errors
from
ansible
import
errors
from
ansible.utils.vault
import
*
from
ansible.utils.vault
import
VaultEditor
from
ansible.utils.vault
import
Vault
from
optparse
import
OptionParser
from
optparse
import
OptionParser
...
@@ -100,32 +100,30 @@ def get_opt(options, k, defval=""):
...
@@ -100,32 +100,30 @@ def get_opt(options, k, defval=""):
# Command functions
# Command functions
#-------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------
def
_get_vault
(
filename
,
options
,
password
):
this_vault
=
Vault
()
this_vault
.
filename
=
filename
this_vault
.
vault_password
=
password
this_vault
.
password
=
password
return
this_vault
def
execute_create
(
args
,
options
,
parser
):
def
execute_create
(
args
,
options
,
parser
):
if
len
(
args
)
>
1
:
if
len
(
args
)
>
1
:
raise
errors
.
AnsibleError
(
"create does not accept more than one filename"
)
raise
errors
.
AnsibleError
(
"'create' does not accept more than one filename"
)
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
,
confirm_vault
=
True
)
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
,
confirm_vault
=
True
)
this_vault
=
_get_vault
(
args
[
0
],
options
,
password
)
cipher
=
'AES'
if
not
hasattr
(
options
,
'cipher'
):
if
hasattr
(
options
,
'cipher'
):
this_vault
.
cipher
=
'AES'
cipher
=
options
.
cipher
this_vault
.
create
()
this_editor
=
VaultEditor
(
cipher
,
password
,
args
[
0
])
this_editor
.
create_file
()
def
execute_decrypt
(
args
,
options
,
parser
):
def
execute_decrypt
(
args
,
options
,
parser
):
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
)
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
)
cipher
=
'AES'
if
hasattr
(
options
,
'cipher'
):
cipher
=
options
.
cipher
for
f
in
args
:
for
f
in
args
:
this_
vault
=
_get_vault
(
f
,
options
,
password
)
this_
editor
=
VaultEditor
(
cipher
,
password
,
f
)
this_
vault
.
decrypt
()
this_
editor
.
decrypt_file
()
print
"Decryption successful"
print
"Decryption successful"
...
@@ -136,29 +134,35 @@ def execute_edit(args, options, parser):
...
@@ -136,29 +134,35 @@ def execute_edit(args, options, parser):
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
)
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
)
cipher
=
None
for
f
in
args
:
for
f
in
args
:
this_
vault
=
_get_vault
(
f
,
options
,
password
)
this_
editor
=
VaultEditor
(
cipher
,
password
,
f
)
this_
vault
.
edit
()
this_
editor
.
edit_file
()
def
execute_encrypt
(
args
,
options
,
parser
):
def
execute_encrypt
(
args
,
options
,
parser
):
if
len
(
args
)
>
1
:
raise
errors
.
AnsibleError
(
"'create' does not accept more than one filename"
)
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
,
confirm_vault
=
True
)
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
,
confirm_vault
=
True
)
cipher
=
'AES'
if
hasattr
(
options
,
'cipher'
):
cipher
=
options
.
cipher
for
f
in
args
:
for
f
in
args
:
this_vault
=
_get_vault
(
f
,
options
,
password
)
this_editor
=
VaultEditor
(
cipher
,
password
,
f
)
if
not
hasattr
(
options
,
'cipher'
):
this_editor
.
encrypt_file
()
this_vault
.
cipher
=
'AES'
this_vault
.
encrypt
()
print
"Encryption successful"
print
"Encryption successful"
def
execute_rekey
(
args
,
options
,
parser
):
def
execute_rekey
(
args
,
options
,
parser
):
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
,
ask_new_vault_pass
=
True
,
confirm_new
=
True
)
password
,
new_password
=
utils
.
ask_vault_passwords
(
ask_vault_pass
=
True
,
ask_new_vault_pass
=
True
,
confirm_new
=
True
)
cipher
=
None
for
f
in
args
:
for
f
in
args
:
this_
vault
=
_get_vault
(
f
,
options
,
password
)
this_
editor
=
VaultEditor
(
cipher
,
password
,
f
)
this_
vault
.
rekey
(
new_password
)
this_
editor
.
rekey_file
(
new_password
)
print
"Rekey successful"
print
"Rekey successful"
...
...
lib/ansible/utils/__init__.py
View file @
8a253bf5
...
@@ -43,7 +43,8 @@ import getpass
...
@@ -43,7 +43,8 @@ import getpass
import
sys
import
sys
import
textwrap
import
textwrap
import
vault
#import vault
from
vault
import
VaultLib
VERBOSITY
=
0
VERBOSITY
=
0
...
@@ -501,15 +502,15 @@ def parse_yaml_from_file(path, vault_password=None):
...
@@ -501,15 +502,15 @@ def parse_yaml_from_file(path, vault_password=None):
data
=
None
data
=
None
#VAULT
if
vault
.
is_encrypted
(
path
):
data
=
vault
.
decrypt
(
path
,
vault_password
)
else
:
try
:
try
:
data
=
open
(
path
)
.
read
()
data
=
open
(
path
)
.
read
()
except
IOError
:
except
IOError
:
raise
errors
.
AnsibleError
(
"file could not read:
%
s"
%
path
)
raise
errors
.
AnsibleError
(
"file could not read:
%
s"
%
path
)
vault
=
VaultLib
(
password
=
vault_password
)
if
vault
.
is_encrypted
(
data
):
data
=
vault
.
decrypt
(
data
)
try
:
try
:
return
parse_yaml
(
data
)
return
parse_yaml
(
data
)
except
yaml
.
YAMLError
,
exc
:
except
yaml
.
YAMLError
,
exc
:
...
...
lib/ansible/utils/vault.py
View file @
8a253bf5
...
@@ -32,101 +32,122 @@ from ansible import constants as C
...
@@ -32,101 +32,122 @@ from ansible import constants as C
# AES IMPORTS
# AES IMPORTS
try
:
try
:
from
Crypto.Cipher
import
AES
as
AES
_
from
Crypto.Cipher
import
AES
as
AES
HAS_AES
=
True
HAS_AES
=
True
except
ImportError
:
except
ImportError
:
HAS_AES
=
False
HAS_AES
=
False
HEADER
=
'$ANSIBLE_VAULT'
HEADER
=
'$ANSIBLE_VAULT'
CIPHER_WHITELIST
=
[
'AES'
]
def
is_encrypted
(
filename
):
class
VaultLib
(
object
):
'''
def
__init__
(
self
,
password
):
Check a file for the encrypted header and return True or False
self
.
password
=
password
self
.
cipher_name
=
None
The first line should start with the header
self
.
version
=
'1.0'
defined by the global HEADER. If true, we
assume this is a properly encrypted file.
'''
# read first line of the file
with
open
(
filename
)
as
f
:
try
:
head
=
f
.
next
()
except
StopIteration
:
# empty file, so not encrypted
return
False
if
head
.
startswith
(
HEADER
):
def
is_encrypted
(
self
,
data
):
if
data
.
startswith
(
HEADER
):
return
True
return
True
else
:
else
:
return
False
return
False
def
decrypt
(
filename
,
password
):
def
encrypt
(
self
,
data
):
'''
if
self
.
is_encrypted
(
data
):
Return a decrypted string of the contents in an encrypted file
raise
errors
.
AnsibleError
(
"data is already encrypted"
)
This is used by the yaml loading code in ansible
if
'Vault'
+
self
.
cipher_name
in
globals
()
and
self
.
cipher_name
in
CIPHER_WHITELIST
:
to automatically determine the encryption type
cipher
=
globals
()[
'Vault'
+
self
.
cipher_name
]
and return a plaintext string of the unencrypted
this_cipher
=
cipher
()
data.
else
:
'''
raise
errors
.
AnsibleError
(
"
%
s cipher could not be found"
%
self
.
cipher_name
)
# combine sha + data
this_sha
=
sha256
(
data
)
.
hexdigest
()
tmp_data
=
this_sha
+
"
\n
"
+
data
# encrypt sha + data
tmp_data
=
this_cipher
.
encrypt
(
tmp_data
,
self
.
password
)
# add header
tmp_data
=
self
.
_add_headers_and_hexify_encrypted_data
(
tmp_data
)
return
tmp_data
def
decrypt
(
self
,
data
):
if
self
.
password
is
None
:
raise
errors
.
AnsibleError
(
"A vault password must be specified to decrypt data"
)
if
not
self
.
is_encrypted
(
data
):
raise
errors
.
AnsibleError
(
"data is not encrypted"
)
# clean out header, hex and sha
data
=
self
.
_split_headers_and_get_unhexified_data
(
data
)
# create the cipher object
if
'Vault'
+
self
.
cipher_name
in
globals
()
and
self
.
cipher_name
in
CIPHER_WHITELIST
:
cipher
=
globals
()[
'Vault'
+
self
.
cipher_name
]
this_cipher
=
cipher
()
else
:
raise
errors
.
AnsibleError
(
"
%
s cipher could not be found"
%
self
.
cipher_name
)
if
password
is
None
:
# try to unencrypt data
raise
errors
.
AnsibleError
(
"A vault password must be specified to decrypt
%
s"
%
filename
)
data
=
this_cipher
.
decrypt
(
data
,
self
.
password
)
V
=
Vault
(
filename
=
filename
,
vault_password
=
password
)
# split out sha and verify decryption
return_data
=
V
.
_decrypt_to_string
()
split_data
=
data
.
split
(
"
\n
"
)
this_sha
=
split_data
[
0
]
this_data
=
'
\n
'
.
join
(
split_data
[
1
:])
test_sha
=
sha256
(
this_data
)
.
hexdigest
()
if
this_sha
!=
test_sha
:
raise
errors
.
AnsibleError
(
"Decryption failed"
)
if
not
V
.
_verify_decryption
(
return_data
):
return
this_data
raise
errors
.
AnsibleError
(
"Decryption of
%
s failed"
%
filename
)
this_sha
,
return_data
=
V
.
_strip_sha
(
return_data
)
def
_add_headers_and_hexify_encrypted_data
(
self
,
data
):
return
return_data
.
strip
()
# combine header and hexlified encrypted data in 80 char columns
tmpdata
=
hexlify
(
data
)
tmpdata
=
[
tmpdata
[
i
:
i
+
80
]
for
i
in
range
(
0
,
len
(
tmpdata
),
80
)]
class
Vault
(
object
):
if
not
self
.
cipher_name
:
def
__init__
(
self
,
filename
=
None
,
cipher
=
None
,
vault_password
=
None
):
raise
errors
.
AnsibleError
(
"the cipher must be set before adding a header"
)
self
.
filename
=
filename
self
.
vault_password
=
vault_password
self
.
cipher
=
cipher
self
.
version
=
'1.0'
###############
dirty_data
=
HEADER
+
";"
+
str
(
self
.
version
)
+
";"
+
self
.
cipher_name
+
"
\n
"
# PUBLIC
for
l
in
tmpdata
:
###############
dirty_data
+=
l
+
'
\n
'
def
eval_header
(
self
):
return
dirty_data
""" Read first line of the file and parse header """
# read first line
def
_split_headers_and_get_unhexified_data
(
self
,
data
):
with
open
(
self
.
filename
)
as
f
:
# used by decrypt
#head=[f.next() for x in xrange(1)]
head
=
f
.
next
()
t
his_version
=
None
t
mpdata
=
data
.
split
(
'
\n
'
)
t
his_cipher
=
None
t
mpheader
=
tmpdata
[
0
]
.
strip
()
.
split
(
';'
)
# split segments
self
.
version
=
str
(
tmpheader
[
1
]
.
strip
())
if
len
(
head
.
split
(
';'
))
==
3
:
self
.
cipher_name
=
str
(
tmpheader
[
2
]
.
strip
())
this_version
=
head
.
split
(
';'
)[
1
]
.
strip
()
clean_data
=
''
.
join
(
tmpdata
[
1
:])
this_cipher
=
head
.
split
(
';'
)[
2
]
.
strip
()
else
:
# strip out newline, join, unhex
raise
errors
.
AnsibleError
(
"
%
s has an invalid header"
%
self
.
filename
)
clean_data
=
[
x
.
strip
()
for
x
in
clean_data
]
clean_data
=
unhexlify
(
''
.
join
(
clean_data
))
# validate acceptable version
this_version
=
float
(
this_version
)
return
clean_data
if
this_version
<
C
.
VAULT_VERSION_MIN
or
this_version
>
C
.
VAULT_VERSION_MAX
:
raise
errors
.
AnsibleError
(
"
%
s must have a version between
%
s and
%
s "
%
(
self
.
filename
,
class
VaultEditor
(
object
):
C
.
VAULT_VERSION_MIN
,
# uses helper methods for write_file(self, filename, data)
C
.
VAULT_VERSION_MAX
))
# to write a file so that code isn't duplicated for simple
# set properties
# file I/O, ditto read_file(self, filename) and launch_editor(self, filename)
self
.
cipher
=
this_cipher
# ... "Don't Repeat Yourself", etc.
self
.
version
=
this_version
def
__init__
(
self
,
cipher_name
,
password
,
filename
):
def
create
(
self
):
# instantiates a member variable for VaultLib
self
.
cipher_name
=
cipher_name
self
.
password
=
password
self
.
filename
=
filename
def
create_file
(
self
):
""" create a new encrypted file """
""" create a new encrypted file """
if
os
.
path
.
isfile
(
self
.
filename
):
if
os
.
path
.
isfile
(
self
.
filename
):
...
@@ -135,250 +156,100 @@ class Vault(object):
...
@@ -135,250 +156,100 @@ class Vault(object):
# drop the user into vim on file
# drop the user into vim on file
EDITOR
=
os
.
environ
.
get
(
'EDITOR'
,
'vim'
)
EDITOR
=
os
.
environ
.
get
(
'EDITOR'
,
'vim'
)
call
([
EDITOR
,
self
.
filename
])
call
([
EDITOR
,
self
.
filename
])
tmpdata
=
self
.
read_data
(
self
.
filename
)
self
.
encrypt
()
this_vault
=
VaultLib
(
self
.
password
)
this_vault
.
cipher_name
=
self
.
cipher_name
def
decrypt
(
self
):
enc_data
=
this_vault
.
encrypt
(
tmpdata
)
""" unencrypt a file inplace """
self
.
write_data
(
enc_data
,
self
.
filename
)
if
not
is_encrypted
(
self
.
filename
):
def
decrypt_file
(
self
):
raise
errors
.
AnsibleError
(
"
%
s is not encrypted"
%
self
.
filename
)
if
not
os
.
path
.
isfile
(
self
.
filename
):
raise
errors
.
AnsibleError
(
"
%
s does not exist"
%
self
.
filename
)
# set cipher based on file header
self
.
eval_header
()
tmpdata
=
self
.
read_data
(
self
.
filename
)
this_vault
=
VaultLib
(
self
.
password
)
# decrypt it
if
this_vault
.
is_encrypted
(
tmpdata
):
data
=
self
.
_decrypt_to_string
()
dec_data
=
this_vault
.
decrypt
(
tmpdata
)
self
.
write_data
(
dec_data
,
self
.
filename
)
# verify sha and then strip it out
else
:
if
not
self
.
_verify_decryption
(
data
):
raise
errors
.
AnsibleError
(
"decryption of
%
s failed"
%
self
.
filename
)
this_sha
,
clean_data
=
self
.
_strip_sha
(
data
)
# write back to original file
f
=
open
(
self
.
filename
,
"wb"
)
f
.
write
(
clean_data
)
f
.
close
()
def
edit
(
self
,
filename
=
None
,
password
=
None
,
cipher
=
None
,
version
=
None
):
if
not
is_encrypted
(
self
.
filename
):
raise
errors
.
AnsibleError
(
"
%
s is not encrypted"
%
self
.
filename
)
raise
errors
.
AnsibleError
(
"
%
s is not encrypted"
%
self
.
filename
)
#decrypt to string
def
edit_file
(
self
):
data
=
self
.
_decrypt_to_string
()
# verify sha and then strip it out
if
not
self
.
_verify_decryption
(
data
):
raise
errors
.
AnsibleError
(
"decryption of
%
s failed"
%
self
.
filename
)
this_sha
,
clean_data
=
self
.
_strip_sha
(
data
)
# rewrite file without sha
# decrypt to tmpfile
_
,
in_path
=
tempfile
.
mkstemp
()
tmpdata
=
self
.
read_data
(
self
.
filename
)
f
=
open
(
in_path
,
"wb"
)
this_vault
=
VaultLib
(
self
.
password
)
tmpdata
=
f
.
write
(
clean_data
)
dec_data
=
this_vault
.
decrypt
(
tmpdata
)
f
.
close
()
_
,
tmp_path
=
tempfile
.
mkstemp
()
self
.
write_data
(
dec_data
,
tmp_path
)
# drop the user into vim on the
unencrypted
tmp file
# drop the user into vim on the tmp file
EDITOR
=
os
.
environ
.
get
(
'EDITOR'
,
'vim'
)
EDITOR
=
os
.
environ
.
get
(
'EDITOR'
,
'vim'
)
call
([
EDITOR
,
in_path
])
call
([
EDITOR
,
tmp_path
])
new_data
=
self
.
read_data
(
tmp_path
)
f
=
open
(
in_path
,
"rb"
)
tmpdata
=
f
.
read
()
# create new vault and set cipher to old
f
.
close
()
new_vault
=
VaultLib
(
self
.
password
)
new_vault
.
cipher_name
=
this_vault
.
cipher_name
self
.
_string_to_encrypted_file
(
tmpdata
,
self
.
filename
)
# encrypt new data a write out to tmp
enc_data
=
new_vault
.
encrypt
(
new_data
)
def
encrypt
(
self
):
self
.
write_data
(
enc_data
,
tmp_path
)
""" encrypt a file inplace """
# shuffle tmp file into place
if
is_encrypted
(
self
.
filename
):
self
.
shuffle_files
(
tmp_path
,
self
.
filename
)
raise
errors
.
AnsibleError
(
"
%
s is already encrypted"
%
self
.
filename
)
def
encrypt_file
(
self
):
#self.eval_header()
if
not
os
.
path
.
isfile
(
self
.
filename
):
self
.
__load_cipher
()
raise
errors
.
AnsibleError
(
"
%
s does not exist"
%
self
.
filename
)
# read data
tmpdata
=
self
.
read_data
(
self
.
filename
)
f
=
open
(
self
.
filename
,
"rb"
)
this_vault
=
VaultLib
(
self
.
password
)
tmpdata
=
f
.
read
()
this_vault
.
cipher_name
=
self
.
cipher_name
f
.
close
()
if
not
this_vault
.
is_encrypted
(
tmpdata
):
enc_data
=
this_vault
.
encrypt
(
tmpdata
)
self
.
_string_to_encrypted_file
(
tmpdata
,
self
.
filename
)
self
.
write_data
(
enc_data
,
self
.
filename
)
def
rekey
(
self
,
newpassword
):
""" unencrypt file then encrypt with new password """
if
not
is_encrypted
(
self
.
filename
):
raise
errors
.
AnsibleError
(
"
%
s is not encrypted"
%
self
.
filename
)
# unencrypt to string with old password
data
=
self
.
_decrypt_to_string
()
# verify sha and then strip it out
if
not
self
.
_verify_decryption
(
data
):
raise
errors
.
AnsibleError
(
"decryption of
%
s failed"
%
self
.
filename
)
this_sha
,
clean_data
=
self
.
_strip_sha
(
data
)
# set password
self
.
vault_password
=
newpassword
self
.
_string_to_encrypted_file
(
clean_data
,
self
.
filename
)
###############
# PRIVATE
###############
def
__load_cipher
(
self
):
"""
Load a cipher class by it's name
This is a lightweight "plugin" implementation to allow
for future support of other cipher types
"""
whitelist
=
[
'AES'
]
if
self
.
cipher
in
whitelist
:
self
.
cipher_obj
=
None
if
self
.
cipher
in
globals
():
this_cipher
=
globals
()[
self
.
cipher
]
self
.
cipher_obj
=
this_cipher
()
else
:
raise
errors
.
AnsibleError
(
"
%
s cipher could not be loaded"
%
self
.
cipher
)
else
:
else
:
raise
errors
.
AnsibleError
(
"
%
s is not an allowed encryption cipher"
%
self
.
cipher
)
raise
errors
.
AnsibleError
(
"
%
s is already encrypted"
%
self
.
filename
)
def
_decrypt_to_string
(
self
):
""" decrypt file to string """
if
not
is_encrypted
(
self
.
filename
):
raise
errors
.
AnsibleError
(
"
%
s is not encrypted"
%
self
.
filename
)
# figure out what this is
self
.
eval_header
()
self
.
__load_cipher
()
# strip out header and unhex the file
clean_stream
=
self
.
_dirty_file_to_clean_file
(
self
.
filename
)
# reset pointer
clean_stream
.
seek
(
0
)
# create a byte stream to hold unencrypted
dst
=
BytesIO
()
# decrypt from src stream to dst stream
self
.
cipher_obj
.
decrypt
(
clean_stream
,
dst
,
self
.
vault_password
)
# read data from the unencrypted stream
data
=
dst
.
read
()
return
data
def
_dirty_file_to_clean_file
(
self
,
dirty_filename
):
def
rekey_file
(
self
,
new_password
):
""" Strip out headers from a file, unhex and write to new file"""
# decrypt
tmpdata
=
self
.
read_data
(
self
.
filename
)
this_vault
=
VaultLib
(
self
.
password
)
dec_data
=
this_vault
.
decrypt
(
tmpdata
)
# create new vault, set cipher to old and password to new
new_vault
=
VaultLib
(
new_password
)
new_vault
.
cipher_name
=
this_vault
.
cipher_name
_
,
in_path
=
tempfile
.
mkstemp
()
# re-encrypt data and re-write file
#_, out_path = tempfile.mkstemp()
enc_data
=
new_vault
.
encrypt
(
dec_data
)
self
.
write_data
(
enc_data
,
self
.
filename
)
# strip header from data, write rest to tmp file
def
read_data
(
self
,
filename
):
f
=
open
(
dirty_
filename
,
"rb"
)
f
=
open
(
filename
,
"rb"
)
tmpdata
=
f
.
read
lines
()
tmpdata
=
f
.
read
()
f
.
close
()
f
.
close
()
return
tmpdata
tmpheader
=
tmpdata
[
0
]
.
strip
()
def
write_data
(
self
,
data
,
filename
):
tmpdata
=
''
.
join
(
tmpdata
[
1
:])
# strip out newline, join, unhex
tmpdata
=
[
x
.
strip
()
for
x
in
tmpdata
]
tmpdata
=
unhexlify
(
''
.
join
(
tmpdata
))
# create and return stream
clean_stream
=
BytesIO
(
tmpdata
)
return
clean_stream
def
_clean_stream_to_dirty_stream
(
self
,
clean_stream
):
# combine header and hexlified encrypted data in 80 char columns
clean_stream
.
seek
(
0
)
tmpdata
=
clean_stream
.
read
()
tmpdata
=
hexlify
(
tmpdata
)
tmpdata
=
[
tmpdata
[
i
:
i
+
80
]
for
i
in
range
(
0
,
len
(
tmpdata
),
80
)]
dirty_data
=
HEADER
+
";"
+
str
(
self
.
version
)
+
";"
+
self
.
cipher
+
"
\n
"
for
l
in
tmpdata
:
dirty_data
+=
l
+
'
\n
'
dirty_stream
=
BytesIO
(
dirty_data
)
return
dirty_stream
def
_string_to_encrypted_file
(
self
,
tmpdata
,
filename
):
""" Write a string of data to a file with the format ...
HEADER;VERSION;CIPHER
HEX(ENCRYPTED(SHA256(STRING)+STRING))
"""
# sha256 the data
this_sha
=
sha256
(
tmpdata
)
.
hexdigest
()
# combine sha + data to tmpfile
tmpdata
=
this_sha
+
"
\n
"
+
tmpdata
src_stream
=
BytesIO
(
tmpdata
)
dst_stream
=
BytesIO
()
# encrypt tmpfile
self
.
cipher_obj
.
encrypt
(
src_stream
,
dst_stream
,
self
.
password
)
# hexlify tmpfile and combine with header
dirty_stream
=
self
.
_clean_stream_to_dirty_stream
(
dst_stream
)
if
os
.
path
.
isfile
(
filename
):
if
os
.
path
.
isfile
(
filename
):
os
.
remove
(
filename
)
os
.
remove
(
filename
)
# write back to original file
dirty_stream
.
seek
(
0
)
f
=
open
(
filename
,
"wb"
)
f
=
open
(
filename
,
"wb"
)
f
.
write
(
d
irty_stream
.
read
()
)
f
.
write
(
d
ata
)
f
.
close
()
f
.
close
()
def
shuffle_files
(
self
,
src
,
dest
):
# overwrite dest with src
if
os
.
path
.
isfile
(
dest
):
os
.
remove
(
dest
)
shutil
.
move
(
src
,
dest
)
def
_verify_decryption
(
self
,
data
):
########################################
# CIPHERS #
""" Split data to sha/data and check the sha """
########################################
# split the sha and other data
this_sha
,
clean_data
=
self
.
_strip_sha
(
data
)
# does the decrypted data match the sha ?
class
VaultAES
(
object
):
clean_sha
=
sha256
(
clean_data
)
.
hexdigest
()
# compare, return result
if
this_sha
==
clean_sha
:
return
True
else
:
return
False
def
_strip_sha
(
self
,
data
):
# is the first line a sha?
lines
=
data
.
split
(
"
\n
"
)
this_sha
=
lines
[
0
]
clean_data
=
'
\n
'
.
join
(
lines
[
1
:])
return
this_sha
,
clean_data
class
AES
(
object
):
# http://stackoverflow.com/a/16761459
# http://stackoverflow.com/a/16761459
...
@@ -400,18 +271,22 @@ class AES(object):
...
@@ -400,18 +271,22 @@ class AES(object):
return
key
,
iv
return
key
,
iv
def
encrypt
(
self
,
in_file
,
out_file
,
password
,
key_length
=
32
):
def
encrypt
(
self
,
data
,
password
,
key_length
=
32
):
""" Read plaintext data from in_file and write encrypted to out_file """
""" Read plaintext data from in_file and write encrypted to out_file """
bs
=
AES_
.
block_size
in_file
=
BytesIO
(
data
)
in_file
.
seek
(
0
)
out_file
=
BytesIO
()
bs
=
AES
.
block_size
# Get a block of random data. EL does not have Crypto.Random.new()
# Get a block of random data. EL does not have Crypto.Random.new()
# so os.urandom is used for cross platform purposes
# so os.urandom is used for cross platform purposes
salt
=
os
.
urandom
(
bs
-
len
(
'Salted__'
))
salt
=
os
.
urandom
(
bs
-
len
(
'Salted__'
))
key
,
iv
=
self
.
aes_derive_key_and_iv
(
password
,
salt
,
key_length
,
bs
)
key
,
iv
=
self
.
aes_derive_key_and_iv
(
password
,
salt
,
key_length
,
bs
)
cipher
=
AES
_
.
new
(
key
,
AES_
.
MODE_CBC
,
iv
)
cipher
=
AES
.
new
(
key
,
AES
.
MODE_CBC
,
iv
)
out_file
.
write
(
'Salted__'
+
salt
)
out_file
.
write
(
'Salted__'
+
salt
)
finished
=
False
finished
=
False
while
not
finished
:
while
not
finished
:
...
@@ -422,16 +297,23 @@ class AES(object):
...
@@ -422,16 +297,23 @@ class AES(object):
finished
=
True
finished
=
True
out_file
.
write
(
cipher
.
encrypt
(
chunk
))
out_file
.
write
(
cipher
.
encrypt
(
chunk
))
def
decrypt
(
self
,
in_file
,
out_file
,
password
,
key_length
=
32
):
out_file
.
seek
(
0
)
return
out_file
.
read
()
def
decrypt
(
self
,
data
,
password
,
key_length
=
32
):
""" Read encrypted data from in_file and write decrypted to out_file """
""" Read encrypted data from in_file and write decrypted to out_file """
# http://stackoverflow.com/a/14989032
# http://stackoverflow.com/a/14989032
bs
=
AES_
.
block_size
in_file
=
BytesIO
(
data
)
in_file
.
seek
(
0
)
out_file
=
BytesIO
()
bs
=
AES
.
block_size
salt
=
in_file
.
read
(
bs
)[
len
(
'Salted__'
):]
salt
=
in_file
.
read
(
bs
)[
len
(
'Salted__'
):]
key
,
iv
=
self
.
aes_derive_key_and_iv
(
password
,
salt
,
key_length
,
bs
)
key
,
iv
=
self
.
aes_derive_key_and_iv
(
password
,
salt
,
key_length
,
bs
)
cipher
=
AES
_
.
new
(
key
,
AES_
.
MODE_CBC
,
iv
)
cipher
=
AES
.
new
(
key
,
AES
.
MODE_CBC
,
iv
)
next_chunk
=
''
next_chunk
=
''
finished
=
False
finished
=
False
...
@@ -444,5 +326,7 @@ class AES(object):
...
@@ -444,5 +326,7 @@ class AES(object):
out_file
.
write
(
chunk
)
out_file
.
write
(
chunk
)
# reset the stream pointer to the beginning
# reset the stream pointer to the beginning
if
hasattr
(
out_file
,
'seek'
):
out_file
.
seek
(
0
)
out_file
.
seek
(
0
)
return
out_file
.
read
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment