File Coverage

blib/lib/Win32/CryptData.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Win32::CryptData;
2            
3 1     1   6206 use 5.006;
  1         3  
  1         36  
4 1     1   6 use strict;
  1         2  
  1         29  
5 1     1   5 use Carp;
  1         5  
  1         67  
6            
7 1     1   1577 use Win32;
  0            
  0            
8             use Win32::API '0.20';
9            
10             require Exporter;
11            
12             our @ISA = qw(Exporter);
13            
14             # Items to export into callers namespace by default. Note: do not export
15             # names by default without a very good reason. Use EXPORT_OK instead.
16             # Do not simply export all your public functions/methods/constants.
17            
18             # This allows declaration use Win32::IPHelper ':all';
19             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
20             # will save memory.
21             our %EXPORT_TAGS = (
22             'all' => [ qw( CryptProtectData CryptUnprotectData CRYPTPROTECT_PROMPT_ON_UNPROTECT CRYPTPROTECT_PROMPT_ON_PROTECT CRYPTPROTECT_PROMPT_STRONG CRYPTPROTECT_UI_FORBIDDEN CRYPTPROTECT_LOCAL_MACHINE CRYPTPROTECT_AUDIT CRYPTPROTECT_VERIFY_PROTECTION ) ],
23             'flags' => [ qw( CRYPTPROTECT_PROMPT_ON_UNPROTECT CRYPTPROTECT_PROMPT_ON_PROTECT CRYPTPROTECT_PROMPT_STRONG CRYPTPROTECT_UI_FORBIDDEN CRYPTPROTECT_LOCAL_MACHINE CRYPTPROTECT_AUDIT CRYPTPROTECT_VERIFY_PROTECTION ) ]
24             );
25            
26             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
27            
28             our @EXPORT = qw();
29            
30             our $VERSION = '0.02';
31            
32             my $CryptProtectData = new Win32::API ('Crypt32', 'CryptProtectData', ['P', 'P', 'P', 'P', 'P', 'N', 'P'], 'N') or croak 'can\'t find CryptProtectData() function';
33             my $CryptUnprotectData = new Win32::API ('Crypt32', 'CryptUnprotectData', ['P', 'P', 'P', 'P', 'P', 'N', 'P'], 'N') or croak 'can\'t find CryptUnprotectData() function';
34             my $LocalFree = new Win32::API ('Kernel32', 'LocalFree', ['N'], 'N') or croak 'can\'t find LocalFree() function';
35            
36             #############
37             # Constants #
38             #############
39             # $dwPromptFlags
40             use constant CRYPTPROTECT_PROMPT_ON_UNPROTECT => 0x1;
41             use constant CRYPTPROTECT_PROMPT_ON_PROTECT => 0x2;
42             #use constant CRYPTPROTECT_PROMPT_RESERVED => 0x4; # reserved, do not use.
43             use constant CRYPTPROTECT_PROMPT_STRONG => 0x8;
44            
45             # $dwFlags
46             use constant CRYPTPROTECT_UI_FORBIDDEN => 0x1;
47             use constant CRYPTPROTECT_LOCAL_MACHINE => 0x4;
48             use constant CRYPTPROTECT_AUDIT => 0x10;
49             use constant CRYPTPROTECT_VERIFY_PROTECTION => 0x40;
50            
51             our $DEBUG = 0;
52            
53             #################################
54             # PUBLIC Functions (exportable) #
55             #################################
56            
57             #######################################################################
58             # Win32::CryptData::CryptProtectData()
59             #
60             # The CryptProtectData function performs encryption on the data in a
61             # DATA_BLOB structure. Typically, only a user with the same logon
62             # credential as the encrypter can decrypt the data. In addition, the
63             # encryption and decryption usually must be done on the same computer.
64             #
65             #######################################################################
66             # Usage:
67             # $ret = CryptProtectData(\$pDataIn, \$szDataDescr, \$pOptionalEntropy, \$pvReserved, \%pPromptStruct, $dwFlags, \$pDataOut);
68             #
69             # Output:
70             # $ret = 1 for success, undef for failure
71             #
72             # Input:
73             # \$pDataIn = Pointer to the plaintext string to be encrypted
74             # \$szDataDescr = String with a readable description of the data to be encrypted
75             # \$pOptionalEntropy = Pointer to a password or other additional entropy used to encrypt the data
76             # \$pvReserved = reserved, must be set to undef
77             # \%pPromptStruct = Pointer to a hash that provides information about where and when prompts are to be displayed
78             # PromptFlags => one or more of the following values:
79             # CRYPTPROTECT_PROMPT_ON_PROTECT = This flag is used to provide the prompt for the protect phase
80             # CRYPTPROTECT_PROMPT_ON_UNPROTECT = This flag can be combined with CRYPTPROTECT_PROMPT_ON_PROTECT to enforce the UI (user interface) policy of the caller
81             # CRYPTPROTECT_PROMPT_STRONG = This flag forces user to provide an encryption password
82             # hwndApp => handle of the parent window if needed modal behaviour
83             # Prompt => caption for the prompt
84             # $dwFlags = The following flag values are defined:
85             # CRYPTPROTECT_LOCAL_MACHINE = When this flag is set, it associates the data encrypted with the current computer instead of with an individual user
86             # CRYPTPROTECT_UI_FORBIDDEN = This flag is used for remote situations where presenting a user interface (UI) is not an option
87             # CRYPTPROTECT_AUDIT = This flag generates an audit on protect and unprotect operations
88             # CRYPTPROTECT_VERIFY_PROTECTION = This flag verifies the protection of a protected string
89             #
90             # Output:
91             # \$pDataOut = Pointer to the string that receives the encrypted data
92             #
93             #######################################################################
94             # function CryptProtectData
95             #
96             # The CryptProtectData function performs encryption on the data in a DATA_BLOB structure
97             #
98             # BOOL WINAPI CryptProtectData(
99             # DATA_BLOB* pDataIn,
100             # LPCWSTR szDataDescr,
101             # DATA_BLOB* pOptionalEntropy,
102             # PVOID pvReserved,
103             # CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
104             # DWORD dwFlags,
105             # DATA_BLOB* pDataOut
106             # );
107             #
108             #######################################################################
109             sub CryptProtectData
110             {
111             if(scalar(@_) ne 7)
112             {
113             croak 'Usage: CryptProtectData(\\\$pDataIn, \\\$szDataDescr, \\\$pOptionalEntropy, \\\$pvReserved, \\\%pPromptStruct, \$dwFlags, \\\$pDataOut)';
114             }
115            
116             my $DataIn = shift;
117             my $szDataDescr = _ToUnicodeSz(${shift()});
118             my $OptionalEntropy = shift;
119             my $pvReserved = pack("L", shift);
120             my %PromptStruct = %{ shift() };
121            
122             my $dwFlags = shift || 0;
123            
124             my $DataOut = shift;
125            
126             my $pDataOut = pack("LL", 0x0, 0x0);
127            
128             my $pDataIn = pack("LL", length($$DataIn), unpack("L!", pack("P", $$DataIn)));
129             my $pOptionalEntropy = pack("LL", length($$OptionalEntropy)+1, unpack("L!", pack("P", $$OptionalEntropy)));
130             my $szPrompt = _ToUnicodeSz($PromptStruct{'Prompt'});
131             my $pPromptStruct = pack("L4",
132             16,
133             $PromptStruct{'PromptFlags'} || 0,
134             $PromptStruct{'hwndApp'} || 0,
135             unpack("L!", pack("P", $szPrompt))
136             );
137            
138             if($CryptProtectData->Call($pDataIn, $szDataDescr, $pOptionalEntropy, $pvReserved, $pPromptStruct, $dwFlags, $pDataOut))
139             {
140             my($len, $ptr) = unpack("LL", $pDataOut);
141             $$DataOut = unpack('P'.$len, pack('L!', $ptr));
142            
143             $LocalFree->Call($ptr) and warn "Cannot LocalFree() pDataOut buffer: $^E";
144            
145             return 1;
146             }
147             }
148            
149             #######################################################################
150             # Win32::CryptData::CryptUnprotectData()
151             #
152             # The CryptUnprotectData function decrypts and does an integrity check
153             # of the data in a DATA_BLOB structure. Usually, only a user with the
154             # same logon credentials as the encrypter can decrypt the data.
155             #
156             #######################################################################
157             # Usage:
158             # $ret = CryptUnprotectData(\$pDataIn, \$szDataDescr, \$pOptionalEntropy, \$pvReserved, \%pPromptStruct, $dwFlags, \$pDataOut);
159             #
160             # Output:
161             # $ret = 1 for success, undef for failure
162             #
163             # Input:
164             # \$pDataIn = Pointer to the plaintext string to be decrypted
165             # \$pOptionalEntropy = Pointer to a password or other additional entropy used to encrypt the data
166             # \$pvReserved = reserved, must be set to undef
167             # \%pPromptStruct = Pointer to a hash that provides information about where and when prompts are to be displayed
168             # PromptFlags => one or more of the following values:
169             # CRYPTPROTECT_PROMPT_ON_PROTECT = This flag is used to provide the prompt for the protect phase
170             # CRYPTPROTECT_PROMPT_ON_UNPROTECT = This flag can be combined with CRYPTPROTECT_PROMPT_ON_PROTECT to enforce the UI (user interface) policy of the caller
171             # CRYPTPROTECT_PROMPT_STRONG = This flag forces user to provide an encryption password
172             # hwndApp => handle of the parent window if needed modal behaviour
173             # Prompt => caption for the prompt
174             # $dwFlags = The following flag values are defined:
175             # CRYPTPROTECT_UI_FORBIDDEN = This flag is used for remote situations where presenting a user interface (UI) is not an option
176             #
177             # Output:
178             # \$szDataDescr = String with a readable description of the data to be encrypted
179             # \$pDataOut = Pointer to the string that receives the encrypted data
180             #
181             #######################################################################
182             # function CryptUnprotectData
183             #
184             # The CryptUnprotectData function decrypts and does an integrity check of the data in a DATA_BLOB structure
185             #
186             # BOOL WINAPI CryptUnprotectData(
187             # DATA_BLOB* pDataIn,
188             # LPWSTR* ppszDataDescr,
189             # DATA_BLOB* pOptionalEntropy,
190             # PVOID pvReserved,
191             # CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
192             # DWORD dwFlags,
193             # DATA_BLOB* pDataOut
194             # );
195             #
196             #######################################################################
197             sub CryptUnprotectData
198             {
199             if(scalar(@_) ne 7)
200             {
201             croak 'Usage: CryptUnprotectData(\\\$pDataIn, \\\$szDataDescr, \\\$pOptionalEntropy, \\\$pvReserved, \\\$pPromptStruct, \$dwFlags, \\\$pDataOut)';
202             }
203            
204             my $DataIn = shift;
205             my $szDataDescr = shift;
206             my $pszDataDescr = pack('L', 0);
207             my $OptionalEntropy = shift;
208             my $pvReserved = pack('L', shift);
209             my %PromptStruct = %{ shift() };
210            
211             my $dwFlags = shift || 0;
212            
213             my $DataOut = shift;
214            
215             my $pDataOut = pack('LL', 0, 0);
216            
217             my $pDataIn = pack('LL', length($$DataIn)+1, unpack('L!', pack('P', $$DataIn)));
218             my $pOptionalEntropy = pack('LL', length($$OptionalEntropy)+1, unpack('L!', pack('P', $$OptionalEntropy)));
219             my $szPrompt = _ToUnicodeSz($PromptStruct{'Prompt'});
220             my $pPromptStruct = pack('L4',
221             16,
222             $PromptStruct{'PromptFlags'} || 0,
223             $PromptStruct{'hwndApp'} || 0,
224             unpack('L!', pack('P', $szPrompt))
225             );
226            
227             if($CryptUnprotectData->Call($pDataIn, $pszDataDescr, $pOptionalEntropy, $pvReserved, $pPromptStruct, $dwFlags, $pDataOut))
228             {
229             my($len, $ptr) = unpack('LL', $pDataOut);
230             $$DataOut = unpack('P'.$len, pack('L!', $ptr));
231            
232             $LocalFree->Call($ptr) and warn "Cannot LocalFree() pDataOut buffer: $^E";
233            
234             my $i = 0;
235             do {
236             $i += 2;
237             $$szDataDescr = unpack('P'.$i, $pszDataDescr);
238             }
239             while(substr($$szDataDescr, -2) ne "\0\0");
240            
241             $$szDataDescr = _FromUnicode($$szDataDescr);
242             $LocalFree->Call(unpack('L', $pszDataDescr)) and warn "Cannot LocalFree() pszDataDescr buffer: $^E";
243            
244             return 1;
245             }
246             }
247            
248             #######################################################################
249             # WCHAR = _ToUnicodeChar(string)
250             # converts a perl string in a 16-bit (pseudo) unicode string
251             #######################################################################
252             sub _ToUnicodeChar
253             {
254             my $string = shift or return(undef);
255            
256             $string =~ s/(.)/$1\x00/sg;
257            
258             return $string;
259             }
260            
261            
262             #######################################################################
263             # WSTR = _ToUnicodeSz(string)
264             # converts a perl string in a null-terminated 16-bit (pseudo) unicode string
265             #######################################################################
266             sub _ToUnicodeSz
267             {
268             my $string = shift or return(undef);
269            
270             return _ToUnicodeChar($string."\x00");
271             }
272            
273            
274             #######################################################################
275             # string = _FromUnicode(WSTR)
276             # converts a null-terminated 16-bit unicode string into a regular perl string
277             #######################################################################
278             sub _FromUnicode
279             {
280             my $string = shift or return(undef);
281            
282             $string = unpack("Z*", pack( "C*", unpack("S*", $string)));
283            
284             return($string);
285             }
286            
287            
288             1;
289             __END__