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