随着计算机安全受到越来越多的挑战,本博客新开辟一个分类,python安全开发。
本文是安全开发的第一篇文章,主要讨论如何使用DPAPI保护隐私数据。
关于DPAPI在windows官网有详细的介绍,原文链接http://msdn.microsoft.com/en-us/library/ms995355.aspx , 但是文章已经不再更新。笔者认为这仍是一个较好的保证数据安全的方法,所以在现在流行的操作系统win7和win10上进行了测试,幸运的是这套数据保护机制仍然可以正常的运行。至于DPAPI的原理,在官网原文中有详细的介绍,本文不再赘述。
下面的代码是DPAPI的python实现,仅供参考。
In [3]:
#! /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
源代码出处 https://code.google.com/p/waf/waflib/extras/dpapi.py
本文引用了源代码,为演示作了少量修改 https://wanzhouyi.github.io
'''
from ctypes import windll, byref, cdll, Structure, POINTER, c_char, c_buffer
from ctypes.wintypes import DWORD
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
def dpapi_encrypt_data(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):
print('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:
print('Failed to decrypt data')
def dpapi_decrypt_data(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):
print('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:
print('Failed to decrypt data')
if __name__ == '__main__':
encrypted_data=dpapi_encrypt_data("abc".encode())
print(encrypted_data)
decrypted_data=dpapi_decrypt_data(encrypted_data)
print(decrypted_data.decode())