File Coverage

blib/lib/Crypt/PWSafe3.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             #
2             # Copyright (c) 2011-2016 T.v.Dein .
3             #
4             # Licensed under the terms of the Artistic License 2.0
5             # see: http://www.perlfoundation.org/artistic_license_2_0
6             #
7             # Implements:
8             # http://passwordsafe.svn.sourceforge.net/viewvc/passwordsafe/trunk/pwsafe/pwsafe/docs/formatV3.txt?revision=2139
9              
10             package Crypt::PWSafe3;
11              
12 1     1   56701 use strict;
  1         1  
  1         25  
13              
14 1     1   3 use Config;
  1         1  
  1         33  
15              
16 1     1   402 use Carp::Heavy;
  1         100  
  1         22  
17 1     1   4 use Carp;
  1         1  
  1         47  
18              
19 1     1   183 use Crypt::CBC;
  0            
  0            
20             use Crypt::ECB;
21             use Crypt::Twofish;
22             use Digest::HMAC;
23             use Digest::SHA;
24             use Crypt::Random qw( makerandom );
25             use Data::UUID;
26             use File::Copy qw(copy move);
27             use File::Temp;
28             use File::Spec;
29             use FileHandle;
30             use Data::Dumper;
31             use Exporter ();
32             use vars qw(@ISA @EXPORT);
33              
34             $Crypt::PWSafe3::VERSION = '1.22';
35              
36             use Crypt::PWSafe3::Field;
37             use Crypt::PWSafe3::HeaderField;
38             use Crypt::PWSafe3::Record;
39             use Crypt::PWSafe3::SHA256;
40             use Crypt::PWSafe3::PasswordPolicy;
41              
42             require 5.10.0;
43              
44             #
45             # check which random source to use.
46             # install a wrapper closure around the
47             # one we found.
48             BEGIN {
49             eval {
50             require Bytes::Random::Secure;
51             Bytes::Random::Secure->import("random_bytes");
52             };
53             if ($@) {
54             # well, didn' work, use slow function
55             eval { require Crypt::Random; };# qw( makerandom ); };
56             if ($@) {
57             croak "Could not find either Crypt::Random or Bytes::Random::Secure. Install one of them and retry!";
58             }
59             else {
60             *Crypt::PWSafe3::random = sub {
61             my($this, $len) = @_;
62             my $bits = makerandom(Size => 256, Strength => 1);
63             return substr($bits, 0, $len);
64             };
65             }
66             }
67             else {
68             # good. use the faster one
69             *Crypt::PWSafe3::random = sub {
70             my($this, $len) = @_;
71             return random_bytes($len);
72             };
73             }
74             }
75              
76             my @fields = qw(tag salt iter shaps b1 b2 b3 b4 keyk file program
77             keyl iv hmac header strechedpw password whoami);
78             foreach my $field (@fields) {
79             eval qq(
80             *Crypt::PWSafe3::$field = sub {
81             my(\$this, \$arg) = \@_;
82             if (\$arg) {
83             return \$this->{$field} = \$arg;
84             }
85             else {
86             return \$this->{$field};
87             }
88             }
89             );
90             }
91              
92             sub new {
93             #
94             # new vault object
95             my($this, %param) = @_;
96             my $class = ref($this) || $this;
97             my $self = \%param; # file, password, whoami, program, create
98             bless($self, $class);
99              
100             # sanity checks
101             if (! exists $self->{whoami}) {
102             $self->{whoami} = $ENV{USER};
103             }
104              
105             if (! exists $self->{program}) {
106             $self->{program} = $0;
107             }
108              
109             if (! exists $self->{password}) {
110             croak 'Parameter password is required';
111             }
112              
113             if (! exists $self->{create}) {
114             $self->{create} = 1;
115             }
116              
117             if (! exists $self->{file}) {
118             $self->{file} = '';
119             $self->create();
120             }
121             else {
122             if (! -s $self->{file} || ! -r $self->{file}) {
123             if ($self->{create}) {
124             $self->create();
125             }
126             else {
127             croak "PWSafe3 file $self->{file} does not exist or is not readable";
128             }
129             }
130             else {
131             $self->read();
132             }
133             }
134              
135             $self->{modified} = 0;
136              
137             return $self;
138             }
139              
140             sub stretchpw {
141             #
142             # generate the streched password hash
143             #
144             # algorithm is described here:
145             # [KEYSTRETCH Section 4.1] http://www.schneier.com/paper-low-entropy.pdf
146             my ($this, $passwd) = @_;
147             my $sha = Digest::SHA->new('SHA-256');
148             $sha->reset();
149             $sha->add( ( $passwd, $this->salt) );
150             my $stretched = $sha->digest();
151             foreach (1 .. $this->iter) {
152             $sha->reset();
153             $sha->add( ( $stretched) );
154             $stretched = $sha->digest();
155             }
156             $passwd = 0 x 64;
157             return $stretched;
158             }
159              
160             sub create {
161             #
162             # create an empty vault without writing to disk
163             my($this) = @_;
164              
165             # default header fields
166             $this->tag('PWS3');
167             $this->salt($this->random(32));
168             $this->iter(2048);
169              
170             # the streched pw
171             $this->strechedpw($this->stretchpw($this->password()));
172              
173             # generate hash of the streched pw
174             my $sha = Digest::SHA->new('SHA-256');
175             $sha->reset();
176             $sha->add( ( $this->strechedpw() ) );
177             $this->shaps( $sha->digest() );
178              
179             # encrypt b1 .. b4
180             my $crypt = Crypt::ECB->new;
181             $crypt->padding('none');
182             $crypt->cipher('Twofish');
183             $crypt->key( $this->strechedpw() );
184             $this->b1( $crypt->encrypt( $this->random(16) ) );
185             $this->b2( $crypt->encrypt( $this->random(16) ) );
186             $this->b3( $crypt->encrypt( $this->random(16) ) );
187             $this->b4( $crypt->encrypt( $this->random(16) ) );
188              
189             # create key k + l
190             $this->keyk( $crypt->decrypt( $this->b1() ) . $crypt->decrypt( $this->b2() ));
191             $this->keyl( $crypt->decrypt( $this->b3() ) . $crypt->decrypt( $this->b4() ));
192              
193             # create IV
194             $this->iv( $this->random(16) );
195              
196             # create hmac'er and cipher for actual encryption
197             $this->{hmacer} = Digest::HMAC->new($this->keyl, "Crypt::PWSafe3::SHA256");
198             $this->{cipher} = Crypt::CBC->new(
199             -key => $this->keyk,
200             -iv => $this->iv,
201             -cipher => 'Twofish',
202             -header => 'none',
203             -padding => 'null',
204             -literal_key => 1,
205             -keysize => 32,
206             -blocksize => 16
207             );
208              
209             # empty for now
210             $this->hmac( $this->{hmacer}->digest() );
211             }
212              
213             sub read {
214             #
215             # read and decrypt an existing vault file
216             my($this) = @_;
217              
218             my $file = $this->file();
219             my $fd = FileHandle->new($file, 'r') or croak "Could not open $file for reading: $!";
220             $fd->binmode();
221             $this->{fd} = $fd;
222              
223             $this->tag( $this->readbytes(4) );
224             if ($this->tag ne 'PWS3') {
225             croak "Not a PasswordSave V3 file!";
226             }
227              
228             $this->salt( $this->readbytes(32) );
229             $this->iter( unpack("L<", $this->readbytes(4) ) );
230              
231             $this->strechedpw($this->stretchpw($this->password()));
232              
233             my $sha = Digest::SHA->new(256);
234             $sha->reset();
235             $sha->add( ( $this->strechedpw() ) );
236             $this->shaps( $sha->digest() );
237              
238             my $fileshaps = $this->readbytes(32);
239             if ($fileshaps ne $this->shaps) {
240             croak "Wrong password!";
241             }
242              
243             $this->b1( $this->readbytes(16) );
244             $this->b2( $this->readbytes(16) );
245             $this->b3( $this->readbytes(16) );
246             $this->b4( $this->readbytes(16) );
247              
248             my $crypt = Crypt::ECB->new;
249             $crypt->padding('none');
250             $crypt->cipher('Twofish') || die $crypt->errstring;
251             $crypt->key( $this->strechedpw() );
252              
253             $this->keyk($crypt->decrypt($this->b1) . $crypt->decrypt($this->b2));
254             $this->keyl($crypt->decrypt($this->b3) . $crypt->decrypt($this->b4));
255              
256             $this->iv( $this->readbytes(16) );
257              
258             # create hmac'er and cipher for actual encryption
259             $this->{hmacer} = Digest::HMAC->new($this->keyl, "Crypt::PWSafe3::SHA256");
260             $this->{cipher} = Crypt::CBC->new(
261             -key => $this->keyk,
262             -iv => $this->iv,
263             -cipher => 'Twofish',
264             -header => 'none',
265             -padding => 'null',
266             -literal_key => 1,
267             -keysize => 32,
268             -blocksize => 16
269             );
270              
271             # read db header fields
272             $this->{header} = {};
273             while (1) {
274             my $field = $this->readfield('header');
275             if (! $field) {
276             last;
277             }
278             if ($field->type == 0xff) {
279             last;
280             }
281             $this->addheader($field);
282             $this->hmacer($field->raw);
283             }
284              
285             # read db records
286             my $record = Crypt::PWSafe3::Record->new(super => $this);
287             $this->{record} = {};
288             while (1) {
289             my $field = $this->readfield();
290             if (! $field) {
291             last;
292             }
293             if ($field->type == 0xff) {
294             $this->addrecord($record);
295             $record = Crypt::PWSafe3::Record->new(super => $this);
296             }
297             else {
298             $record->addfield($field);
299             $this->hmacer($field->raw);
300             }
301             }
302              
303             # read and check file hmac
304             $this->hmac( $this->readbytes(32) );
305             my $calcmac = $this->{hmacer}->digest();
306             if ($calcmac ne $this->hmac) {
307             croak "File integrity check failed, invalid HMAC";
308             }
309              
310             $this->{fd}->close() or croak "Could not close $file: $!";
311             }
312              
313             sub untaint {
314             #
315             # untaint path's
316             my ($this, $path) = @_;
317             if($path =~ /([\w\-\/\\\.:]+\z)/) {
318             return $1;
319             }
320             else {
321             # fail, return unchanged
322             return $path;
323             }
324             }
325              
326             sub save {
327             #
328             # write data to the vault file
329             my($this, %param) = @_;
330             my($file, $passwd);
331              
332             if (! exists $param{file}) {
333             $file = $this->file;
334             }
335             else {
336             $file = $param{file}
337             }
338             if (! exists $param{passwd}) {
339             $passwd = $this->password;
340             }
341             else {
342             $passwd = $param{passwd}
343             }
344              
345             if (! $this->{modified}) {
346             return;
347             }
348              
349             my $lastsave = Crypt::PWSafe3::HeaderField->new(type => 0x04, value => time);
350             my $whatsaved = Crypt::PWSafe3::HeaderField->new(type => 0x06, value => $this->{program});
351             my $whosaved = Crypt::PWSafe3::HeaderField->new(type => 0x05, value => $this->{whoami});
352             $this->addheader($lastsave);
353             $this->addheader($whatsaved);
354             $this->addheader($whosaved);
355              
356             # open a temp vault file, first we try it in the same directory as the target vault file
357             my $tmpdir;
358             if (File::Spec->file_name_is_absolute($file)) {
359             my ($volume, $directories, undef) = File::Spec->splitpath($file);
360             $tmpdir = File::Spec->catdir($volume, $directories);
361             }
362             else {
363             my ($volume, $directories, undef) = File::Spec->splitpath(File::Spec->rel2abs($file));
364             $tmpdir = File::Spec->abs2rel(File::Spec->catdir($volume, $directories));
365             }
366              
367             my $fd;
368             if (-w $tmpdir) {
369             $fd = File::Temp->new(TEMPLATE => '.vaultXXXXXXXX', DIR => $tmpdir, EXLOCK => 0) or croak "Could not open tmpfile: $!\n";
370             }
371             else {
372             # well, then we'll use one in the tmp dir of the system
373             $fd = File::Temp->new(TEMPLATE => '.vaultXXXXXXXX', TMPDIR => 1, EXLOCK => 0) or croak "Could not open tmpfile: $!\n";
374             }
375             my $tmpfile = "$fd";
376              
377             $this->{fd} = $fd;
378              
379             $this->writebytes($this->tag);
380             $this->writebytes($this->salt);
381             $this->writebytes(pack("L<", $this->iter));
382              
383             $this->strechedpw($this->stretchpw($passwd));
384              
385             # line 472
386             my $sha = Digest::SHA->new(256);
387             $sha->reset();
388             $sha->add( ( $this->strechedpw() ) );
389             $this->shaps( $sha->digest() );
390              
391             $this->writebytes($this->shaps);
392             $this->writebytes($this->b1);
393             $this->writebytes($this->b2);
394             $this->writebytes($this->b3);
395             $this->writebytes($this->b4);
396              
397             my $crypt = Crypt::ECB->new;
398             $crypt->padding('none');
399             $crypt->cipher('Twofish');
400             $crypt->key( $this->strechedpw() );
401              
402             $this->keyk($crypt->decrypt($this->b1) . $crypt->decrypt($this->b2));
403             $this->keyl($crypt->decrypt($this->b3) . $crypt->decrypt($this->b4));
404              
405             $this->writebytes($this->iv);
406              
407             $this->{hmacer} = Digest::HMAC->new($this->keyl, "Crypt::PWSafe3::SHA256");
408             $this->{cipher} = Crypt::CBC->new(
409             -key => $this->keyk,
410             -iv => $this->iv,
411             -cipher => 'Twofish',
412             -header => 'none',
413             -padding => 'null',
414             -literal_key => 1,
415             -keysize => 32,
416             -blocksize => 16
417             );
418              
419             my $eof = Crypt::PWSafe3::HeaderField->new(type => 0xff, value => '');
420              
421             foreach my $type (keys %{$this->{header}}) {
422             $this->writefield($this->{header}->{$type});
423             $this->hmacer($this->{header}->{$type}->{raw});
424             }
425             $this->writefield($eof);
426             $this->hmacer($eof->{raw});
427              
428             $eof = Crypt::PWSafe3::Field->new(type => 0xff, value => '');
429              
430             foreach my $uuid (keys %{$this->{record}}) {
431             my $record = $this->{record}->{$uuid};
432             foreach my $type (keys %{$record->{field}}) {
433             $this->writefield($record->{field}->{$type});
434             $this->hmacer($record->{field}->{$type}->{raw});
435             }
436             $this->writefield($eof);
437             $this->hmacer($eof->{raw});
438             }
439              
440             $this->writefield(Crypt::PWSafe3::Field->new(type => 'none', raw => 0));
441              
442             $this->hmac( $this->{hmacer}->digest() );
443             $this->writebytes($this->hmac);
444             if ($Config{d_fsync}) {
445             $this->{fd}->sync() or croak "Could not fsync: $!";
446             }
447             $this->{fd}->close() or croak "Could not close tmpfile: $!";
448              
449             # now try to read it in again to check if it
450             # is valid what we created
451             eval {
452             my $vault = Crypt::PWSafe3->new(file => $tmpfile, create => 0, password => $passwd);
453             };
454             if ($@) {
455             unlink $tmpfile;
456             croak "File integrity check failed ($@)";
457             }
458             else {
459             # well, seems to be ok :)
460             move($tmpfile, $file) or croak "Could not move $tmpfile to $file: $!";
461             }
462             }
463              
464             sub writefield {
465             #
466             # write a field to vault file
467             my($this, $field) = @_;
468              
469             if ($field->type eq 'none') {
470             $this->writebytes("PWS3-EOFPWS3-EOF");
471             return;
472             }
473              
474             my $len = pack("L<", $field->len);
475             my $type = pack("C", $field->type);
476             my $raw = $field->raw;
477              
478             # Assemble TLV block and pad to 16-byte boundary
479             my $data = $len . $type . $raw;
480              
481             if (length($data) % 16 != 0) {
482             # too small or too large, padding required
483             my $padcount = 16 - (length($data) % 16);
484             $data .= $this->random($padcount);
485             }
486              
487             if (length($data) > 16) {
488             my $crypt;
489             while (1) {
490             my $part = substr($data, 0, 16);
491             $crypt .= $this->encrypt($part);
492             if (length($data) <= 16) {
493             last;
494             }
495             else {
496             $data = substr($data, 16);
497             }
498             }
499             $this->writebytes($crypt);
500             }
501             else {
502             $this->writebytes($this->encrypt($data));
503             }
504             }
505              
506             sub getrecord {
507             #
508             # return the given record
509             my($this, $uuid) = @_;
510             if (exists $this->{record}->{$uuid}) {
511             return $this->{record}->{$uuid};
512             }
513             else {
514             return 0;
515             }
516             }
517              
518             sub getrecords {
519             #
520             # return all records we've got as a copy
521             my ($this) = @_;
522             return map { $this->{record}->{$_} } keys %{$this->{record}};
523             }
524              
525             sub looprecord {
526             #
527             # return a list of uuid's of all records
528             my ($this) = @_;
529             return keys %{$this->{record}};
530             }
531              
532             sub modifyrecord {
533             #
534             # modify a record identified by the given uuid
535             my($this, $uuid, %fields) = @_;
536              
537             if (! exists $this->{record}->{$uuid}) {
538             croak "No record with uuid $uuid found!";
539             }
540              
541             foreach my $field (keys %fields) {
542             $this->{record}->{$uuid}->modifyfield($field, $fields{$field});
543             }
544              
545             # mark vault as modified
546             $this->markmodified();
547             }
548              
549             sub deleterecord {
550             #
551             # delete a record identified by the given uuid, if present
552             # returns 1 if record was actually removed, 0 if it was not present
553             my($this, $uuid) = @_;
554              
555             if (! exists $this->{record}->{$uuid}) {
556             return 0;
557             }
558              
559             delete $this->{record}->{$uuid};
560              
561             # mark vault as modified
562             $this->markmodified();
563              
564             return 1;
565             }
566              
567              
568             sub markmodified {
569             #
570             # mark the vault as modified by setting the appropriate header fields
571             my($this) = @_;
572             my $lastmod = Crypt::PWSafe3::HeaderField->new(
573             name => "lastsavetime",
574             value => time
575             );
576             my $who = Crypt::PWSafe3::HeaderField->new(
577             name => "wholastsaved",
578             value => $this->{whoami}
579             );
580             $this->addheader($lastmod);
581             $this->addheader($who);
582             $this->{modified} = 1;
583             }
584              
585             sub newrecord {
586             #
587             # add a new record to an existing vault
588             my($this, %fields) = @_;
589             my $record = Crypt::PWSafe3::Record->new();
590             foreach my $field (keys %fields) {
591             $record->modifyfield($field, $fields{$field});
592             }
593             $this->markmodified();
594             $this->addrecord($record);
595             $this->{records}->{$record->uuid}->{super} = $this;
596             return $record->uuid;
597             }
598              
599             sub addrecord {
600             #
601             # add a record object to record hash
602             my($this, $record) = @_;
603             $this->{record}->{ $record->uuid } = $record;
604             }
605              
606             sub addheader {
607             #
608             # add a header field to header hash
609             my($this, $field) = @_;
610             $this->{header}->{ $field->name } = $field;
611             }
612              
613              
614             sub readfield {
615             #
616             # read and return a field object of the vault
617             my($this, $header) = @_;
618             my $data = $this->readbytes(16);
619             if (! $data or length($data) < 16) {
620             croak "EOF encountered when parsing record field";
621             }
622             if ($data eq "PWS3-EOFPWS3-EOF") {
623             return 0;
624             }
625              
626             $data = $this->decrypt($data);
627              
628             my $len = unpack("L<", substr($data, 0, 4));
629             my $type = unpack("C", substr($data, 4, 1));
630             my $raw = substr($data, 5);
631              
632             if ($len > 11) {
633             my $step = int(($len+4) / 16);
634             for (1 .. $step) {
635             my $data = $this->readbytes(16);
636             if (! $data or length($data) < 16) {
637             croak "EOF encountered when parsing record field";
638             }
639             $raw .= $this->decrypt($data);
640             }
641             }
642             $raw = substr($raw, 0, $len);
643             if ($header) {
644             return Crypt::PWSafe3::HeaderField->new(type => $type, raw => $raw);
645             }
646             else {
647             return Crypt::PWSafe3::Field->new(type => $type, raw => $raw);
648             }
649             }
650              
651             sub decrypt {
652             #
653             # helper, decrypt a string
654             my ($this, $data) = @_;
655             my $clear = $this->{cipher}->decrypt($data);
656             $this->{cipher}->iv($data);
657             return $clear;
658             }
659              
660             sub encrypt {
661             #
662             # helper, encrypt a string
663             my ($this, $data) = @_;
664             my $raw = $this->{cipher}->encrypt($data);
665             if (length($raw) > 16) {
666             # we use only the last 16byte block as next iv
667             # if data is more than 1 blocks then Crypt::CBC
668             # has already updated the iv for the inner blocks
669             $raw = substr($raw, -16, 16);
670             }
671             $this->{cipher}->iv($raw);
672             return $raw;
673             }
674              
675             sub hmacer {
676             #
677             # helper, hmac generator
678             my($this, $data) = @_;
679              
680             $this->{hmacer}->add($data);
681             }
682              
683             sub readbytes {
684             #
685             # helper, reads number of bytes
686             my ($this, $size) = @_;
687             my $buffer;
688             my ($package, $filename, $line) = caller;
689              
690             my $got = $this->{fd}->sysread($buffer, $size);
691             if ($got == $size) {
692             $this->{sum} += $got;
693             return $buffer;
694             }
695             else {
696             return 0;
697             }
698             }
699              
700             sub writebytes {
701             #
702             # helper, reads number of bytes
703             my ($this, $bytes) = @_;
704             my $got = $this->{fd}->syswrite($bytes);
705             if ($got) {
706             return $got;
707             }
708             else {
709             croak "Could not write to $this->{file}: $!";
710             }
711             }
712              
713              
714             sub getheader {
715             #
716             # return a header object
717             my($this, $name) = @_;
718             if (exists $this->{header}->{$name}) {
719             return $this->{header}->{$name};
720             }
721             else {
722             croak "Unknown header $name";
723             }
724             }
725              
726              
727              
728              
729             =head1 NAME
730              
731             Crypt::PWSafe3 - Read and write Passwordsafe v3 files
732              
733             =head1 SYNOPSIS
734              
735             use Crypt::PWSafe3;
736             my $vault = Crypt::PWSafe3->new(file => 'filename.psafe3', password => 'somesecret');
737            
738             # fetch all database records
739             my @records = $vault->getrecords();
740             foreach my $record (@records) {
741             print $record->uuid;
742             print $record->title;
743             print $record->passwd;
744             # see Crypt::PWSafe3::Record for more details on accessing records
745             }
746              
747             # same as above but don't detach records from vault
748             foreach my $uuid ($vault->looprecord) {
749             # either change a record
750             $vault->modifyrecord($uuid, passwd => 'p1');
751              
752             # or just access it directly
753             print $vault->{record}->{$uuid}->title;
754             }
755              
756             # add a new record
757             $vault->newrecord(user => 'u1', passwd => 'p1', title => 't1');
758              
759             # modify an existing record
760             $vault->modifyrecord($uuid, passwd => 'p1');
761              
762             # replace a record (aka edit it)
763             my $record = $vault->getrecord($uuid);
764             $record->title('t2');
765             $record->passwd('foobar');
766             $vault->addrecord($record);
767              
768             # mark the vault as modified (not required if
769             # changes were done with ::modifyrecord()
770             $vault->markmodified();
771              
772             # save the vault
773             $vault->save();
774              
775             # save it under another name using another password
776             $vault->save(file => 'another.pwsafe3', passwd => 'blah');
777              
778             # access database headers
779             print $vault->getheader('wholastsaved')->value();
780             print scalar localtime($vault->getheader('lastsavetime')->value());
781              
782             # add/replace a database header
783             my $h = Crypt::PWSafe3::HeaderField->new(name => 'savedonhost', value => 'localhost');
784             $vault->addheader($h);
785              
786             =head1 DESCRIPTION
787              
788             Crypt::PWSafe3 provides read and write access to password
789             database files created by Password Safe V3 (and up) available at
790             http://passwordsafe.sf.net.
791              
792             =head1 METHODS
793              
794             =head2 B
795              
796             The new() method creates a new Crypt::PWSafe3 object. Any parameters
797             must be given as hash parameters.
798              
799             my $vault = Crypt::PWSafe3->new(
800             file => 'vault.psafe3',
801             password => 'secret',
802             whoami => 'user1',
803             program => 'mypwtool v1',
804             create => 0, # or 1
805             );
806              
807             Mandatory parameters:
808              
809             =over
810              
811             =item B
812              
813             Specifies the password safe (v3) file. If it exists
814             it will be read in. Otherwise it will be created
815             if you call B.
816              
817             =item B
818              
819             The password required to decrypt the password safe file.
820              
821             =back
822              
823             Optional parameters:
824              
825             =over
826              
827             =item B
828              
829             Specifies the user who saves the password safe file.
830             If omitted the environment variable USER will be used
831             when calling B.
832              
833             =item B
834              
835             Specifies which program saved the password safe file.
836             If omitted, the content of the perl variable $0 will
837             be used, which contains the name of the current running
838             script.
839              
840             =item B
841              
842             If set to 0, B will fail if the file doesn't exist,
843             otherwise it will try to create it. Enabled by default.
844              
845             =back
846              
847             The optional parameters will become header fields of
848             the password safe file. You can manually set/override
849             more headers. See section L for
850             more details.
851              
852             =head2 B
853              
854             Returns a list of all records found in the password
855             safe file. Each element is an B
856             object.
857              
858             A record object is identified by its B value,
859             which is a unique identifier. You can access the uuid by:
860              
861             $record->uuid
862              
863             Accessing other record properties works the same. For
864             more details, refer to L.
865              
866             B: record objects returned by getrecords() are
867             still associated with the L object. So,
868             if you modify a field of such a record, the change will
869             be populated back into the vault. Of course you'd still
870             need to save it.
871              
872             Sample:
873              
874             foreach my $rec ($vault->getrecords) {
875             $rec->note('blah fasel');
876             }
877             $vault->save();
878              
879             However, it's also possible to use the B
880             method, see below.
881              
882             =head2 B
883              
884             Returns a list of UUIDs of all known records. You can
885             use this list to iterate over the records without
886             copying them and optionally changing them in place.
887              
888             Example:
889              
890             foreach my $uuid ($vault->looprecord) {
891             # either change a record
892             $vault->modifyrecord($uuid, passwd => 'p1');
893              
894             # or just access it directly
895             print $vault->{record}->{$uuid}->title;
896             }
897              
898              
899             =head2 B
900              
901             Modifies the record identified by the given UUID using
902             the values of the supplied parameter hash.
903              
904             Example:
905              
906             $vault->modifyrecord($uuid, passwd => 'p1');
907              
908             The parameter hash may contain any valid record field
909             type with according values. Refer to L
910             for details about available fields.
911              
912             =head2 B
913              
914             Create a new record. The UUID of the record will be generated
915             automatically. Refer to L
916             for details about available fields.
917              
918             =head2 B
919              
920             Add a record to the vault. The record must be an
921             L object.
922              
923             =head2 B
924              
925             Delete the record identified by the given UUID.
926              
927             =head2 B
928              
929             Save the current password safe vault back to disk.
930              
931             If not otherwise specified, use the same file and
932             password as we used to open it initially. If the
933             file doesn't exist it will be created.
934              
935             You may specify another filename and password here
936             by using a parameter hash.
937              
938             Example:
939              
940             $vault->save(file => 'anotherfile.psafe3', passwd => 'foo');
941              
942             Please note, that the vault will be written to a
943             temporary file first, then this temporary file
944             will be read in and if that works, it will be
945             moved over the destination file. This way the original
946             file persists if the written database gets corrupted
947             by some unknown reason (a bug for instance).
948              
949              
950             =head2 B
951              
952             Returns a raw B object.
953             Refer to L for details
954             how to access it.
955              
956             =head2 B
957              
958             Adds a header field to the password safe database. The
959             object parameter must be an B
960             object.
961              
962             If the header already exists it will be replaced.
963              
964             Refer to L for details
965             how to create new ones
966             .
967              
968             =head1 AUTHOR
969              
970             T.v.Dein
971              
972             =head1 BUGS
973              
974             Report bugs to
975             http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Crypt-PWSafe3.
976              
977              
978             =head1 SEE ALSO
979              
980             Subclasses:
981              
982             L
983             L
984             L
985              
986             Password Safe Homepage:
987             L
988              
989             Another (read-only) perl module:
990             L
991              
992             A python port of Password Safe:
993             L
994             Many thanks to Christoph Sommer, his python library
995             inspired me a lot and in fact most of the concepts
996             in this module are his ideas ported to perl.
997              
998             =head1 COPYRIGHT
999              
1000             Copyright (c) 2011-2016 by T.v.Dein .
1001              
1002             =head1 LICENSE
1003              
1004             This program is free software; you can redistribute it
1005             and/or modify it under the same terms of the Artistic
1006             License 2.0, see: L
1007              
1008             =head1 VERSION
1009              
1010             Crypt::PWSafe3 Version 1.22.
1011              
1012             =cut
1013              
1014              
1015              
1016              
1017             1;
1018