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

# Content
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 use Crypt::Twofish;
30 use MIME::Base64;
31
32 use Net::FCP::Util;
33
34 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 =item my $key = new_from_data Net::FCP::Key::CHK $metadata, $data;
49
50 Generate a CHK from the given data and metadata strings.
51
52 =cut
53
54 sub new_from_data {
55 my ($class, $metadata, $data) = @_;
56
57 $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 }
79
80 sub set_data {
81 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
88 my $d = new Digest::SHA1;
89 $d->add ($plaintext);
90 $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
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 }
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
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
204 1;
205