#!/usr/bin/env python # K4PC Windows specific routines from __future__ import with_statement import sys, os from struct import pack, unpack, unpack_from from ctypes import windll, c_char_p, c_wchar_p, c_uint, POINTER, byref, \ create_unicode_buffer, create_string_buffer, CFUNCTYPE, addressof, \ string_at, Structure, c_void_p, cast import _winreg as winreg MAX_PATH = 255 kernel32 = windll.kernel32 advapi32 = windll.advapi32 crypt32 = windll.crypt32 import traceback # crypto digestroutines import hashlib def MD5(message): ctx = hashlib.md5() ctx.update(message) return ctx.digest() def SHA1(message): ctx = hashlib.sha1() ctx.update(message) return ctx.digest() # simple primes table (<= n) calculator def primes(n): if n==2: return [2] elif n<2: return [] s=range(3,n+1,2) mroot = n ** 0.5 half=(n+1)/2-1 i=0 m=3 while m <= mroot: if s[i]: j=(m*m-3)/2 s[j]=0 while j 0: # get the first item record item = items.pop(0) # the first 32 chars of the first record of a group # is the MD5 hash of the key name encoded by charMap5 keyhash = item[0:32] # the raw keyhash string is also used to create entropy for the actual # CryptProtectData Blob that represents that keys contents entropy = SHA1(keyhash) # the remainder of the first record when decoded with charMap5 # has the ':' split char followed by the string representation # of the number of records that follow # and make up the contents srcnt = decode(item[34:],charMap5) rcnt = int(srcnt) # read and store in rcnt records of data # that make up the contents value edlst = [] for i in xrange(rcnt): item = items.pop(0) edlst.append(item) keyname = "unknown" for name in names: if encodeHash(name,charMap5) == keyhash: keyname = name break if keyname == "unknown": keyname = keyhash # the charMap5 encoded contents data has had a length # of chars (always odd) cut off of the front and moved # to the end to prevent decoding using charMap5 from # working properly, and thereby preventing the ensuing # CryptUnprotectData call from succeeding. # The offset into the charMap5 encoded contents seems to be: # len(contents) - largest prime number less than or equal to int(len(content)/3) # (in other words split "about" 2/3rds of the way through) # move first offsets chars to end to align for decode by charMap5 encdata = "".join(edlst) contlen = len(encdata) noffset = contlen - primes(int(contlen/3))[-1] # now properly split and recombine # by moving noffset chars from the start of the # string to the end of the string pfx = encdata[0:noffset] encdata = encdata[noffset:] encdata = encdata + pfx # decode using Map5 to get the CryptProtect Data encryptedValue = decode(encdata,charMap5) DB[keyname] = CryptUnprotectData(encryptedValue, entropy, 1) cnt = cnt + 1 if cnt == 0: DB = None return DB