ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-FCP/FCP/Key/CHK.pm
Revision: 1.2
Committed: Sun Oct 12 12:40:00 2003 UTC (22 years, 11 months ago) by root
Branch: MAIN
Changes since 1.1: +98 -29 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     Net::FCP::Key::CHK - manage CHK keys.
4    
5     =head1 SYNOPSIS
6    
7     use Net::FCP::Key::CHK;
8    
9     my $key = new Net::FCP::Key::CHK;
10     my $key = new_from_uri Net::FCP::Key::CHK $uri;
11     my $key = new_from_data Net::FCP::Key::CHK $data, $metadata;
12     ... more to come
13    
14    
15     =head1 DESCRIPTION
16    
17     =back
18    
19     =head2 THE Net::FCP::Key::CHK CLASS
20    
21     =over 4
22    
23     =cut
24    
25     package Net::FCP::Key::CHK;
26    
27     use Carp;
28     use Digest::SHA1;
29 root 1.2 use Crypt::Twofish;
30 root 1.1 use MIME::Base64;
31    
32 root 1.2 use Net::FCP::Util;
33    
34 root 1.1 no warnings;
35    
36     =item my $key = new Net::FCP::Key::CHK;
37    
38     Don't use :)
39    
40     =cut
41    
42     sub new {
43     my $class = shift;
44    
45     bless { }, $class;
46     }
47    
48 root 1.2 =item my $key = new_from_data Net::FCP::Key::CHK $metadata, $data;
49 root 1.1
50     Generate a CHK from the given data and metadata strings.
51    
52     =cut
53    
54     sub new_from_data {
55 root 1.2 my ($class, $metadata, $data) = @_;
56 root 1.1
57 root 1.2 $class->new->set_data ($metadata, $data);
58     }
59    
60     sub rolling_hashpad($$) {
61     my $d = Digest::SHA1->new->add ($_[0]);
62     my $pad = "";
63    
64     while ($_[1] > length $_[0]) {
65     my $dig = $d->digest_noreset;
66     $d->add ($dig);
67     $pad .= $dig;
68     $_[0] .= $pad;
69     }
70    
71     substr $_[0], $_[1], length $_[0], "";
72     }
73    
74     sub encode_number($) {
75     my $num = pack "N", $_[0];
76     $num =~ s/^\x00+//;
77     pack "n a*", length $num, $num;
78 root 1.1 }
79    
80     sub set_data {
81 root 1.2 my ($self, $metadata, $data) = @_;
82    
83     my $total_len = (length $metadata) + (length $data);
84     my $padded_len = 1 << Net::FCP::Util::log2 $total_len, 10;
85    
86     my $plaintext = "$metadata$data";
87 root 1.1
88     my $d = new Digest::SHA1;
89 root 1.2 $d->add ($plaintext);
90 root 1.1 $d = $d->digest;
91    
92     # only works for 128 bit keys
93     my $k = new Digest::SHA1;
94     $k->add ("\x00" x 1);
95     $k->add ($d);
96 root 1.2
97     my $hash = substr +(my $x=$k->digest), 0, 16; # extract leading 128 bit
98    
99     my $buf = "";
100    
101     $buf .= pack "n a20", 20, Digest::SHA1::sha1 $hash;
102    
103     $buf .= encode_number $total_len;
104     $buf .= encode_number length $metadata;
105    
106     $buf .= "\x00\x00";
107    
108     rolling_hashpad $buf, 1 << Net::FCP::Util::log2 length $buf;
109    
110     my $pcfbc = new Crypt::Twofish $hash;
111     my $pcfbr = "\x00" x 16;
112     my $pcfb = 16;
113    
114     my $pcfb_enc = sub {
115     if ($pcfb == 16) {
116     $pcfb = 0;
117     $pcfbr = $pcfbc->encrypt ($pcfbr);
118     }
119     (substr $pcfbr, $pcfb++, 1) ^= $_[0];
120     };
121    
122     $buf = join "", map $pcfb_enc->($_), split //, $buf;
123    
124     my $senc = unpack "H*", $buf;
125    
126     rolling_hashpad $plaintext, $padded_len;
127    
128     $plaintext = join "", map $pcfb_enc->($_), split //, $plaintext;
129    
130     my $partsize = $padded_len > 16384 ? $padded_len >> 7 : $padded_len;
131     $partsize = 16384 if $partsize < 16384; # up to 4MB
132    
133     my $dig = "";
134     for (my $ofs = ($padded_len-1) - ($padded_len-1) % $partsize; $ofs >= 0; $ofs -= $partsize) {
135     $dig = Digest::SHA1::sha1 substr ($plaintext, $ofs, $partsize) . $dig;
136     }
137    
138     my $sini = unpack "H*", $dig;
139    
140     my $s = sprintf
141     "Document-header\xfe%s\xff"
142     . "Initial-digest\xfe%s\xff"
143     . "Part-size\xfe%x\xff"
144     . "Symmetric-cipher\xfe%s\xff",
145     $senc, $sini, $partsize, "Twofish";
146    
147     warn "$s\n";
148    
149     $s = Net::FCP::Util::encode_base64 +(Digest::SHA1::sha1 $s) . (pack "C", Net::FCP::Util::log2 $padded_len) . "\x03\x02";
150     print "$s\n";
151    
152    
153     $self;
154 root 1.1 }
155    
156     =item $size = $key->size
157    
158     Returns the size of the data (in bytes).
159    
160     =cut
161    
162     =item $digest = $key->digest
163    
164     Return the store digest/hash.
165    
166     =cut
167    
168     =item $keynum = $key->keynumber
169    
170     Returns the keynumber (version?)
171    
172     =cut
173    
174     =item $chk = $key->chk
175    
176     Return the full CHK.
177    
178     =cut
179    
180     =back
181    
182     =head1 SEE ALSO
183    
184     L<Net::FCP>.
185    
186     =head1 BUGS
187    
188     Not heavily tested.
189    
190     =head1 AUTHOR
191    
192     Marc Lehmann <pcg@goof.com>
193     http://www.goof.com/pcg/marc/
194    
195     =cut
196 root 1.2
197     my $data = do { local $/; <> };
198     my $metadata = substr $data, 0, 0x3f, "";
199     #my $metadata = substr $data, 0, 0x28, "";
200    
201     my $key = Net::FCP::Key::CHK->new_from_data ($metadata, $data);
202     #use Net::FCP; my $fcp = new Net::FCP; warn $fcp->generate_chk ($metadata, $data);
203 root 1.1
204     1;
205