34 lines
1.7 KiB
Python
34 lines
1.7 KiB
Python
"""Current-user Windows capability protection; no browser profile crypto state."""
|
|
import base64
|
|
import ctypes
|
|
import sys
|
|
|
|
class Blob(ctypes.Structure):
|
|
_fields_=[('size',ctypes.c_uint32),('data',ctypes.POINTER(ctypes.c_ubyte))]
|
|
|
|
def convert(data,protect):
|
|
crypt=ctypes.WinDLL('crypt32',use_last_error=True)
|
|
kernel=ctypes.WinDLL('kernel32',use_last_error=True)
|
|
allocation=(ctypes.c_ubyte*len(data)).from_buffer_copy(data)
|
|
source=Blob(len(data),allocation);result=Blob()
|
|
function=crypt.CryptProtectData if protect else crypt.CryptUnprotectData
|
|
function.argtypes=[ctypes.POINTER(Blob),ctypes.c_void_p,ctypes.c_void_p,ctypes.c_void_p,ctypes.c_void_p,ctypes.c_uint32,ctypes.POINTER(Blob)]
|
|
function.restype=ctypes.c_int
|
|
# UI_FORBIDDEN; omit LOCAL_MACHINE so only the signed-in Windows user can decrypt.
|
|
if not function(ctypes.byref(source),None,None,None,None,1,ctypes.byref(result)):
|
|
raise ValueError('DPAPI rejected capability')
|
|
kernel.LocalFree.argtypes=[ctypes.c_void_p];kernel.LocalFree.restype=ctypes.c_void_p
|
|
try:return ctypes.string_at(result.data,result.size)
|
|
finally:kernel.LocalFree(result.data)
|
|
|
|
if __name__=='__main__':
|
|
try:
|
|
if sys.platform!='win32' or len(sys.argv)!=2 or sys.argv[1] not in ['protect','unprotect']: raise ValueError()
|
|
data=sys.stdin.buffer.read(32769)
|
|
if not data or len(data)>32768:raise ValueError()
|
|
if sys.argv[1]=='protect':output=base64.b64encode(convert(data,True))
|
|
else:output=convert(base64.b64decode(data,validate=True),False)
|
|
sys.stdout.buffer.write(output)
|
|
except Exception:
|
|
sys.stderr.write('Windows capability protection failed.\n');sys.exit(1)
|