line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Crypt::Random::Source::Strong::Win32; |
2
|
1
|
|
|
1
|
|
47122
|
use 5.008; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
60
|
|
3
|
1
|
|
|
1
|
|
1272
|
use Any::Moose; |
|
1
|
|
|
|
|
46338
|
|
|
1
|
|
|
|
|
7
|
|
4
|
1
|
|
|
1
|
|
1244
|
use Win32; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
use Win32::API; |
6
|
|
|
|
|
|
|
use Win32::API::Type; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
extends qw( |
11
|
|
|
|
|
|
|
Crypt::Random::Source::Strong |
12
|
|
|
|
|
|
|
Crypt::Random::Source::Base |
13
|
|
|
|
|
|
|
); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
has 'rtlgenrand' => (is => 'ro', isa => 'Win32::API', lazy_build => 1); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# For Windows 2000 only. |
18
|
|
|
|
|
|
|
has 'crypt_context' => (is => 'ro', isa => 'Int', lazy_build => 1); |
19
|
|
|
|
|
|
|
has 'cryptacquirecontext' => (is => 'ro', isa => 'Win32::API', |
20
|
|
|
|
|
|
|
lazy_build => 1); |
21
|
|
|
|
|
|
|
has 'cryptgenrandom' => (is => 'ro', isa => 'Win32::API', lazy_build => 1); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# The type of cryptographic service provider we want to use. |
24
|
|
|
|
|
|
|
# This doesn't really matter for our purposes, so we just pick |
25
|
|
|
|
|
|
|
# PROV_RSA_FULL, which seems reasonable. For more info, see |
26
|
|
|
|
|
|
|
# http://msdn.microsoft.com/en-us/library/aa380244(v=VS.85).aspx |
27
|
|
|
|
|
|
|
use constant PROV_RSA_FULL => 1; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Flags for CryptGenRandom: |
30
|
|
|
|
|
|
|
# Don't ever display a UI to the user, just fail if one would be needed. |
31
|
|
|
|
|
|
|
use constant CRYPT_SILENT => 64; |
32
|
|
|
|
|
|
|
# Don't require existing public/private keypairs. |
33
|
|
|
|
|
|
|
use constant CRYPT_VERIFYCONTEXT => 0xF0000000; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# For some reason, BOOLEAN doesn't work properly as a return type with Win32::API. |
36
|
|
|
|
|
|
|
use constant RTLGENRANDOM_PROTO => <
|
37
|
|
|
|
|
|
|
INT SystemFunction036( |
38
|
|
|
|
|
|
|
PVOID RandomBuffer, |
39
|
|
|
|
|
|
|
ULONG RandomBufferLength |
40
|
|
|
|
|
|
|
) |
41
|
|
|
|
|
|
|
END |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
our $IS_WIN2K; |
44
|
|
|
|
|
|
|
BEGIN { |
45
|
|
|
|
|
|
|
my ($major, $minor) = (Win32::GetOSVersion())[1,2]; |
46
|
|
|
|
|
|
|
$IS_WIN2K = ($major == 5 and $minor == 0) ? 1 : 0; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# This should be preferred over other generators, on Windows. |
50
|
|
|
|
|
|
|
sub rank { 10 } |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub available { |
53
|
|
|
|
|
|
|
return 0 if !($^O eq 'MSWin32' or $^O eq 'cygwin'); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
my $major = (Win32::GetOSVersion())[1]; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# Major 5 is Windows 2000 and above. |
58
|
|
|
|
|
|
|
return 0 if $major < 5; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
return 1; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub get { |
64
|
|
|
|
|
|
|
my ($self, $n) = @_; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my $buffer = chr(0) x $n; |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# Win2K requires a slower, bulkier solution. |
69
|
|
|
|
|
|
|
if ($IS_WIN2K) { |
70
|
|
|
|
|
|
|
my $context = $self->crypt_context; |
71
|
|
|
|
|
|
|
my $result = $self->cryptgenrandom->Call($context, $n, $buffer); |
72
|
|
|
|
|
|
|
if (!$result) { |
73
|
|
|
|
|
|
|
die "CryptGenRandom failed: $^E"; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
return $buffer; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
my $result = $self->rtlgenrand->Call($buffer, $n); |
79
|
|
|
|
|
|
|
if (!$result) { |
80
|
|
|
|
|
|
|
die "RtlGenRand failed: $^E"; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
return $buffer; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub _build_rtlgenrand { |
86
|
|
|
|
|
|
|
my $func = Win32::API->new('advapi32', RTLGENRANDOM_PROTO); |
87
|
|
|
|
|
|
|
if (!defined $func) { |
88
|
|
|
|
|
|
|
die "Could not import SystemFunction036: $^E"; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
return $func; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub _build_cryptgenrandom { |
94
|
|
|
|
|
|
|
my $func = Win32::API->new("advapi32", 'CryptGenRandom', 'NNP', 'I'); |
95
|
|
|
|
|
|
|
if (!defined $func) { |
96
|
|
|
|
|
|
|
die "Could not import CryptGenRandom: $^E" |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
return $func; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub _build_cryptacquirecontext { |
102
|
|
|
|
|
|
|
my $func = Win32::API->new("advapi32", 'CryptAcquireContextA', 'PPPNN', 'I'); |
103
|
|
|
|
|
|
|
if (!defined $func) { |
104
|
|
|
|
|
|
|
die "Could not import CryptAcquireContext: $^E" |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
return $func; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _build_crypt_context { |
110
|
|
|
|
|
|
|
my ($self) = @_; |
111
|
|
|
|
|
|
|
my $func = $self->cryptacquirecontext; |
112
|
|
|
|
|
|
|
my $context = chr(0) x Win32::API::Type->sizeof('PULONG'); |
113
|
|
|
|
|
|
|
my $result = $func->Call($context, 0, 0, PROV_RSA_FULL, |
114
|
|
|
|
|
|
|
CRYPT_SILENT | CRYPT_VERIFYCONTEXT); |
115
|
|
|
|
|
|
|
my $pack_type = Win32::API::Type::packing('PULONG'); |
116
|
|
|
|
|
|
|
$context = unpack($pack_type, $context); |
117
|
|
|
|
|
|
|
if (!$result) { |
118
|
|
|
|
|
|
|
die "CryptAcquireContext failed: $^E"; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
return $context; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
__PACKAGE__ |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
__END__ |