summaryrefslogtreecommitdiffstats
path: root/extras/dpapi.py
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2019-03-17 17:31:05 +0100
committerDavid Robillard <d@drobilla.net>2019-03-17 17:31:05 +0100
commit406f89271452fdb573c7e28113b1ed08ff2b4eda (patch)
treed2dcbaf61f3749f73dc7a5e10d3fc6cd5e6e129a /extras/dpapi.py
parent7983a5aae615290d04fd43cbc2752f8cf4a46d10 (diff)
downloadsuil-406f89271452fdb573c7e28113b1ed08ff2b4eda.tar.gz
suil-406f89271452fdb573c7e28113b1ed08ff2b4eda.tar.bz2
suil-406f89271452fdb573c7e28113b1ed08ff2b4eda.zip
Squashed 'waflib/' changes from 915dcb1..e7a29b6
e7a29b6 Upgrade to waf 2.0.15 8280f9d Add command for running executables from the build directory 8073c1a Make make_simple_dox() safe in case of exception 70d03b8 Avoid use of global counter hacks for configuration display b7d689a Rewrite test framework 94deadf Automatically add options and move add_flags() to options context f4259ee Reduce system include path noise 927b608 Automatically display configuration header c44b8f3 Set line justification from a constant in the wscript a48e26f Automatically detect if wscript has a test hook ef66724 Save runtime variables in the environment 63bcbcd Clean up TestContext b1d9505 Add ExecutionContext for setting runtime environment 387c1df Add show_diff() and test_file_equals() utilities 29d4d29 Fix in-tree library paths 9fde01f Add custom configuration context 6d3612f Add lib_path_name constant git-subtree-dir: waflib git-subtree-split: e7a29b6b9b2f842314244c23c14d8f8f560904e1
Diffstat (limited to 'extras/dpapi.py')
-rw-r--r--extras/dpapi.py87
1 files changed, 87 insertions, 0 deletions
diff --git a/extras/dpapi.py b/extras/dpapi.py
new file mode 100644
index 0000000..b94d482
--- /dev/null
+++ b/extras/dpapi.py
@@ -0,0 +1,87 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Matt Clarkson, 2012
+
+'''
+DPAPI access library (http://msdn.microsoft.com/en-us/library/ms995355.aspx)
+This file uses code originally created by Crusher Joe:
+http://article.gmane.org/gmane.comp.python.ctypes/420
+And modified by Wayne Koorts:
+http://stackoverflow.com/questions/463832/using-dpapi-with-python
+'''
+
+from ctypes import windll, byref, cdll, Structure, POINTER, c_char, c_buffer
+from ctypes.wintypes import DWORD
+from waflib.Configure import conf
+
+LocalFree = windll.kernel32.LocalFree
+memcpy = cdll.msvcrt.memcpy
+CryptProtectData = windll.crypt32.CryptProtectData
+CryptUnprotectData = windll.crypt32.CryptUnprotectData
+CRYPTPROTECT_UI_FORBIDDEN = 0x01
+try:
+ extra_entropy = 'cl;ad13 \0al;323kjd #(adl;k$#ajsd'.encode('ascii')
+except AttributeError:
+ extra_entropy = 'cl;ad13 \0al;323kjd #(adl;k$#ajsd'
+
+class DATA_BLOB(Structure):
+ _fields_ = [
+ ('cbData', DWORD),
+ ('pbData', POINTER(c_char))
+ ]
+
+def get_data(blob_out):
+ cbData = int(blob_out.cbData)
+ pbData = blob_out.pbData
+ buffer = c_buffer(cbData)
+ memcpy(buffer, pbData, cbData)
+ LocalFree(pbData)
+ return buffer.raw
+
+@conf
+def dpapi_encrypt_data(self, input_bytes, entropy = extra_entropy):
+ '''
+ Encrypts data and returns byte string
+
+ :param input_bytes: The data to be encrypted
+ :type input_bytes: String or Bytes
+ :param entropy: Extra entropy to add to the encryption process (optional)
+ :type entropy: String or Bytes
+ '''
+ if not isinstance(input_bytes, bytes) or not isinstance(entropy, bytes):
+ self.fatal('The inputs to dpapi must be bytes')
+ buffer_in = c_buffer(input_bytes, len(input_bytes))
+ buffer_entropy = c_buffer(entropy, len(entropy))
+ blob_in = DATA_BLOB(len(input_bytes), buffer_in)
+ blob_entropy = DATA_BLOB(len(entropy), buffer_entropy)
+ blob_out = DATA_BLOB()
+
+ if CryptProtectData(byref(blob_in), 'python_data', byref(blob_entropy),
+ None, None, CRYPTPROTECT_UI_FORBIDDEN, byref(blob_out)):
+ return get_data(blob_out)
+ else:
+ self.fatal('Failed to decrypt data')
+
+@conf
+def dpapi_decrypt_data(self, encrypted_bytes, entropy = extra_entropy):
+ '''
+ Decrypts data and returns byte string
+
+ :param encrypted_bytes: The encrypted data
+ :type encrypted_bytes: Bytes
+ :param entropy: Extra entropy to add to the encryption process (optional)
+ :type entropy: String or Bytes
+ '''
+ if not isinstance(encrypted_bytes, bytes) or not isinstance(entropy, bytes):
+ self.fatal('The inputs to dpapi must be bytes')
+ buffer_in = c_buffer(encrypted_bytes, len(encrypted_bytes))
+ buffer_entropy = c_buffer(entropy, len(entropy))
+ blob_in = DATA_BLOB(len(encrypted_bytes), buffer_in)
+ blob_entropy = DATA_BLOB(len(entropy), buffer_entropy)
+ blob_out = DATA_BLOB()
+ if CryptUnprotectData(byref(blob_in), None, byref(blob_entropy), None,
+ None, CRYPTPROTECT_UI_FORBIDDEN, byref(blob_out)):
+ return get_data(blob_out)
+ else:
+ self.fatal('Failed to decrypt data')
+