Profile of /home/micha/Projekt/spreadsheet-parsexlsx/lib/Spreadsheet/ParseXLSX/Decryptor/Agile.pm

← Index
NYTProf Performance Profile «line view»
For t/bug-md-11.t
Run on Fri Mar 8 13:27:24 2024
Reported on Fri Mar 8 13:30:23 2024

Filename | /home/micha/Projekt/spreadsheet-parsexlsx/lib/Spreadsheet/ParseXLSX/Decryptor/Agile.pm
Statements | Executed 7 statements in 371µs

Subroutines
Calls | P | F | Exclusive Time | Inclusive Time | Subroutine
--- | --- | --- | --- | --- | ---
1 | 1 | 1 | 11µs | 12µs | Spreadsheet::ParseXLSX::Decryptor::Agile::::BEGIN@3Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@3
1 | 1 | 1 | 3µs | 48µs | Spreadsheet::ParseXLSX::Decryptor::Agile::::BEGIN@10Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@10
1 | 1 | 1 | 3µs | 19µs | Spreadsheet::ParseXLSX::Decryptor::Agile::::BEGIN@4Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@4
0 | 0 | 0 | 0s | 0s | Spreadsheet::ParseXLSX::Decryptor::Agile::::_generateDecryptionKeySpreadsheet::ParseXLSX::Decryptor::Agile::_generateDecryptionKey
0 | 0 | 0 | 0s | 0s | Spreadsheet::ParseXLSX::Decryptor::Agile::::_generateInitializationVectorSpreadsheet::ParseXLSX::Decryptor::Agile::_generateInitializationVector
0 | 0 | 0 | 0s | 0s | Spreadsheet::ParseXLSX::Decryptor::Agile::::decryptSpreadsheet::ParseXLSX::Decryptor::Agile::decrypt
0 | 0 | 0 | 0s | 0s | Spreadsheet::ParseXLSX::Decryptor::Agile::::decryptFileSpreadsheet::ParseXLSX::Decryptor::Agile::decryptFile
0 | 0 | 0 | 0s | 0s | Spreadsheet::ParseXLSX::Decryptor::Agile::::verifyPasswordSpreadsheet::ParseXLSX::Decryptor::Agile::verifyPassword

Call graph for these subroutines as a Graphviz dot language file.

Line | State ments | Time on line | Calls | Time in subs | Code
--- | --- | --- | --- | --- | ---
1 |  |  |  |  | package Spreadsheet::ParseXLSX::Decryptor::Agile;
2 |  |  |  |  |
3 | 2 | 17µs | 2 | 14µs | # spent 12µs (11+2) within Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@3 which was called: # once (11µs+2µs) by Spreadsheet::ParseXLSX::Decryptor::BEGIN@19 at line 3 use strict; # spent 12µs making 1 call to Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@3 # spent 2µs making 1 call to strict::import
4 | 2 | 21µs | 2 | 35µs | # spent 19µs (3+16) within Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@4 which was called: # once (3µs+16µs) by Spreadsheet::ParseXLSX::Decryptor::BEGIN@19 at line 4 use warnings; # spent 19µs making 1 call to Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@4 # spent 16µs making 1 call to warnings::import
5 |  |  |  |  |
6 |  |  |  |  | # VERSION
7 |  |  |  |  |
8 |  |  |  |  | # ABSTRACT: decryptor for files of version 4.4
9 |  |  |  |  |
10 | 2 | 331µs | 2 | 93µs | # spent 48µs (3+45) within Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@10 which was called: # once (3µs+45µs) by Spreadsheet::ParseXLSX::Decryptor::BEGIN@19 at line 10 use base 'Spreadsheet::ParseXLSX::Decryptor'; # spent 48µs making 1 call to Spreadsheet::ParseXLSX::Decryptor::Agile::BEGIN@10 # spent 45µs making 1 call to base::import
11 |  |  |  |  |
12 |  |  |  |  | sub decrypt {
13 |  |  |  |  | my $self = shift;
14 |  |  |  |  | my ($encryptedValue, $blockKey) = @_;
15 |  |  |  |  |
16 |  |  |  |  | my $key = $self->_generateDecryptionKey($blockKey);
17 |  |  |  |  | my $iv = $self->_generateInitializationVector('', $self->{blockSize});
18 |  |  |  |  | my $cbc = Crypt::Mode::CBC->new($self->{cipherAlgorithm}, 0);
19 |  |  |  |  | return $cbc->decrypt($encryptedValue, $key, $iv);
20 |  |  |  |  | }
21 |  |  |  |  |
22 |  |  |  |  | sub _generateDecryptionKey {
23 |  |  |  |  | my $self = shift;
24 |  |  |  |  | my ($blockKey) = @_;
25 |  |  |  |  |
26 |  |  |  |  | my $hash;
27 |  |  |  |  |
28 |  |  |  |  | unless ($self->{pregeneratedKey}) {
29 |  |  |  |  | $hash = $self->{hashProc}->($self->{salt} . Encode::encode('UTF-16LE', $self->{password}));
30 |  |  |  |  | for (my $i = 0 ; $i < $self->{spinCount} ; $i++) {
31 |  |  |  |  | $hash = $self->{hashProc}->(pack('L<', $i) . $hash);
32 |  |  |  |  | }
33 |  |  |  |  | $self->{pregeneratedKey} = $hash;
34 |  |  |  |  | }
35 |  |  |  |  |
36 |  |  |  |  | $hash = $self->{hashProc}->($self->{pregeneratedKey} . $blockKey);
37 |  |  |  |  |
38 |  |  |  |  | if (length($hash) > $self->{keyLength}) {
39 |  |  |  |  | $hash = substr($hash, 0, $self->{keyLength});
40 |  |  |  |  | } elsif (length($hash) < $self->{keyLength}) {
41 |  |  |  |  | $hash .= "\x36" x ($self->{keyLength} - length($hash));
42 |  |  |  |  | }
43 |  |  |  |  | return $hash;
44 |  |  |  |  | }
45 |  |  |  |  |
46 |  |  |  |  | sub _generateInitializationVector {
47 |  |  |  |  | my $self = shift;
48 |  |  |  |  | my ($blockKey, $blockSize) = @_;
49 |  |  |  |  |
50 |  |  |  |  | my $iv;
51 |  |  |  |  | if ($blockKey) {
52 |  |  |  |  | $iv = $self->{hashProc}->($self->{salt} . $blockKey);
53 |  |  |  |  | } else {
54 |  |  |  |  | $iv = $self->{salt};
55 |  |  |  |  | }
56 |  |  |  |  |
57 |  |  |  |  | if (length($iv) > $blockSize) {
58 |  |  |  |  | $iv = substr($iv, 0, $blockSize);
59 |  |  |  |  | } elsif (length($iv) < $blockSize) {
60 |  |  |  |  | $iv = $iv . ("\x36" x ($blockSize - length($iv)));
61 |  |  |  |  | }
62 |  |  |  |  |
63 |  |  |  |  | return $iv;
64 |  |  |  |  | }
65 |  |  |  |  |
66 |  |  |  |  | sub decryptFile {
67 |  |  |  |  | my $self = shift;
68 |  |  |  |  | my ($inFile, $outFile, $bufferLength, $key, $fileSize) = @_;
69 |  |  |  |  |
70 |  |  |  |  | my $cbc = Crypt::Mode::CBC->new($self->{cipherAlgorithm}, 0);
71 |  |  |  |  |
72 |  |  |  |  | my $inbuf;
73 |  |  |  |  | my $i = 0;
74 |  |  |  |  |
75 |  |  |  |  | while (($fileSize > 0) && (my $inlen = $inFile->read($inbuf, $bufferLength))) {
76 |  |  |  |  | my $blockId = pack('L<', $i);
77 |  |  |  |  |
78 |  |  |  |  | my $iv = $self->_generateInitializationVector($blockId, $self->{blockSize});
79 |  |  |  |  |
80 |  |  |  |  | if ($inlen < $bufferLength) {
81 |  |  |  |  | $inbuf .= "\x00" x ($bufferLength - $inlen);
82 |  |  |  |  | }
83 |  |  |  |  |
84 |  |  |  |  | my $outbuf = $cbc->decrypt($inbuf, $key, $iv);
85 |  |  |  |  | if ($fileSize < $inlen) {
86 |  |  |  |  | $inlen = $fileSize;
87 |  |  |  |  | }
88 |  |  |  |  |
89 |  |  |  |  | $outFile->write($outbuf, $inlen);
90 |  |  |  |  | $i++;
91 |  |  |  |  | $fileSize -= $inlen;
92 |  |  |  |  | }
93 |  |  |  |  | }
94 |  |  |  |  |
95 |  |  |  |  | sub verifyPassword {
96 |  |  |  |  | my $self = shift;
97 |  |  |  |  | my ($encryptedVerifier, $encryptedVerifierHash, $hashSize) = @_;
98 |  |  |  |  |
99 |  |  |  |  | my $encryptedVerifierHash0 = $self->{hashProc}->($self->decrypt($encryptedVerifier, "\xfe\xa7\xd2\x76\x3b\x4b\x9e\x79"));
100 |  |  |  |  | $encryptedVerifierHash = $self->decrypt($encryptedVerifierHash, "\xd7\xaa\x0f\x6d\x30\x61\x34\x4e");
101 |  |  |  |  | $encryptedVerifierHash0 = substr($encryptedVerifierHash0, 0, $hashSize);
102 |  |  |  |  | $encryptedVerifierHash = substr($encryptedVerifierHash, 0, $hashSize);
103 |  |  |  |  |
104 |  |  |  |  | die "Wrong password: $self" unless ($encryptedVerifierHash0 eq $encryptedVerifierHash);
105 |  |  |  |  | }
106 |  |  |  |  |
107 |  |  |  |  | =begin Pod::Coverage
108 |  |  |  |  |
109 |  |  |  |  | decrypt
110 |  |  |  |  | decryptFile
111 |  |  |  |  | verifyPassword
112 |  |  |  |  |
113 |  |  |  |  | =end Pod::Coverage
114 |  |  |  |  |
115 |  |  |  |  | =cut
116 |  |  |  |  |
117 | 1 | 2µs |  |  | 1;