build:wafsamba: Remove unnecessary parameters to cmd_and_log
[samba.git] / third_party / waf / waflib / extras / dpapi.py
1 #! /usr/bin/env python
2 # encoding: utf-8
3 # Matt Clarkson, 2012
4
5 '''
6 DPAPI access library (http://msdn.microsoft.com/en-us/library/ms995355.aspx)
7 This file uses code originally created by Crusher Joe:
8 http://article.gmane.org/gmane.comp.python.ctypes/420
9 And modified by Wayne Koorts:
10 http://stackoverflow.com/questions/463832/using-dpapi-with-python
11 '''
12
13 from ctypes import windll, byref, cdll, Structure, POINTER, c_char, c_buffer
14 from ctypes.wintypes import DWORD
15 from waflib.Configure import conf
16
17 LocalFree = windll.kernel32.LocalFree
18 memcpy = cdll.msvcrt.memcpy
19 CryptProtectData = windll.crypt32.CryptProtectData
20 CryptUnprotectData = windll.crypt32.CryptUnprotectData
21 CRYPTPROTECT_UI_FORBIDDEN = 0x01
22 try:
23         extra_entropy = 'cl;ad13 \0al;323kjd #(adl;k$#ajsd'.encode('ascii')
24 except AttributeError:
25         extra_entropy = 'cl;ad13 \0al;323kjd #(adl;k$#ajsd'
26
27 class DATA_BLOB(Structure):
28         _fields_ = [
29                 ('cbData', DWORD),
30                 ('pbData', POINTER(c_char))
31         ]
32
33 def get_data(blob_out):
34         cbData = int(blob_out.cbData)
35         pbData = blob_out.pbData
36         buffer = c_buffer(cbData)
37         memcpy(buffer, pbData, cbData)
38         LocalFree(pbData);
39         return buffer.raw
40
41 @conf
42 def dpapi_encrypt_data(self, input_bytes, entropy = extra_entropy):
43         '''
44         Encrypts data and returns byte string
45
46         :param input_bytes: The data to be encrypted
47         :type input_bytes: String or Bytes
48         :param entropy: Extra entropy to add to the encryption process (optional)
49         :type entropy: String or Bytes
50         '''
51         if not isinstance(input_bytes, bytes) or not isinstance(entropy, bytes):
52                 self.fatal('The inputs to dpapi must be bytes')
53         buffer_in      = c_buffer(input_bytes, len(input_bytes))
54         buffer_entropy = c_buffer(entropy, len(entropy))
55         blob_in        = DATA_BLOB(len(input_bytes), buffer_in)
56         blob_entropy   = DATA_BLOB(len(entropy), buffer_entropy)
57         blob_out       = DATA_BLOB()
58
59         if CryptProtectData(byref(blob_in), 'python_data', byref(blob_entropy),
60                 None, None, CRYPTPROTECT_UI_FORBIDDEN, byref(blob_out)):
61                 return get_data(blob_out)
62         else:
63                 self.fatal('Failed to decrypt data')
64
65 @conf
66 def dpapi_decrypt_data(self, encrypted_bytes, entropy = extra_entropy):
67         '''
68         Decrypts data and returns byte string
69
70         :param encrypted_bytes: The encrypted data
71         :type encrypted_bytes: Bytes
72         :param entropy: Extra entropy to add to the encryption process (optional)
73         :type entropy: String or Bytes
74         '''
75         if not isinstance(encrypted_bytes, bytes) or not isinstance(entropy, bytes):
76                 self.fatal('The inputs to dpapi must be bytes')
77         buffer_in      = c_buffer(encrypted_bytes, len(encrypted_bytes))
78         buffer_entropy = c_buffer(entropy, len(entropy))
79         blob_in        = DATA_BLOB(len(encrypted_bytes), buffer_in)
80         blob_entropy   = DATA_BLOB(len(entropy), buffer_entropy)
81         blob_out       = DATA_BLOB()
82         if CryptUnprotectData(byref(blob_in), None, byref(blob_entropy), None,
83                 None, CRYPTPROTECT_UI_FORBIDDEN, byref(blob_out)):
84                 return get_data(blob_out)
85         else:
86                 self.fatal('Failed to decrypt data')