ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-FCP/FCP/Key/CHK.pm
Revision: 1.8
Committed: Thu Mar 3 17:31:26 2005 UTC (21 years, 6 months ago) by root
Branch: MAIN
CVS Tags: rel-1_1, rel-1_0, rel-1_2, HEAD
Changes since 1.7: +1 -1 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 =head2 THE Net::FCP::Key::CHK CLASS
18
19 =over 4
20
21 =cut
22
23 package Net::FCP::Key::CHK;
24
25 use Carp;
26 use Digest::SHA1;
27 use MIME::Base64;
28
29 use Crypt::Rijndael;
30 use Crypt::Twofish;
31
32 use Net::FCP::Util;
33
34 no warnings;
35
36 =item my $key = new Net::FCP::Key::CHK;
37
38 Heavily under development, 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[, $cipher];
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, $cipher) = @_;
56
57 $class->new->set_data ($metadata, $data, $cipher);
58 }
59
60 sub rolling_hashpad($$$) {
61 my $sha1 = $_[1];
62 my $pad = "";
63 my $dig;
64
65 while ($_[2] > length $_[0]) {
66 $sha1->add ($dig = $sha1->digest_noreset);
67 $pad .= $dig;
68 $_[0] .= $pad;
69 }
70
71 substr $_[0], $_[2], 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, $cipher) = @_;
82
83 $cipher ||= "Twofish";
84
85 my $cipher_class = "Crypt::$cipher";
86
87 $cipher_class->blocksize == 16 or die "only ciphers with a blocksize of 128 bits are supported";
88
89 my $total_len = (length $metadata) + (length $data);
90 my $padded_log = Net::FCP::Util::log2 $total_len, 10;
91 my $padded_len = 1 << $padded_log;
92
93 my $plaintext = "$metadata$data";
94
95 # crypto key (hash) generation. this is an iterative
96 # algorithm, but it is "unrolled" here for the
97 # common keysize of 16 bytes.
98 my $data_sha1 = Digest::SHA1->new->add ($plaintext);
99
100 # only works for 128 bit keys
101 my $k = new Digest::SHA1;
102 $k->add ("\x00" x 1);
103 $k->add ($data_sha1->clone->digest);
104
105 my $hash = substr $k->digest, 0, 16; # extract leading 128 bit
106
107 my $buf = "";
108
109 $buf .= pack "n a20", 20, Digest::SHA1::sha1 $hash;
110
111 $buf .= encode_number $total_len;
112 $buf .= encode_number length $metadata;
113
114 $buf .= "\x00\x00";
115
116 rolling_hashpad $buf, Digest::SHA1->new->add ($buf), 1 << Net::FCP::Util::log2 length $buf;
117
118 my $pcfb_cipher = $cipher_class->new ($hash);
119 my $pcfb_reg = "\x00" x 16;
120
121 my $pcfb_enc = sub {
122 my $length = length $_[0];
123 my $enc = "";
124 for (my $i = 0; $i < $length; $i += 16) {
125 $enc .= $pcfb_reg = $pcfb_cipher->encrypt ($pcfb_reg) ^ substr $_[0], $i, 16;
126 }
127 $enc;
128 };
129
130 # buf length must be multiple of 16
131 $buf = $pcfb_enc->($buf);
132
133 my $senc = unpack "H*", $buf;
134
135 rolling_hashpad $plaintext, $data_sha1, $padded_len;
136
137 # plaintext length must be a multiple of 16, too
138 $plaintext = $pcfb_enc->($plaintext);
139
140 my $partsize = $padded_len < 16384 ? $padded_len
141 : $padded_len < 16384 << 7 ? 16384
142 : $padded_len >> 7; # 2MB
143
144 my $dig = "";
145 for (my $ofs = ($padded_len-1) - ($padded_len-1) % $partsize; $ofs >= 0; $ofs -= $partsize) {
146 $dig = Digest::SHA1::sha1 substr ($plaintext, $ofs, $partsize) . $dig;
147 }
148
149 my $sini = unpack "H*", $dig;
150
151 my $route = sprintf
152 "Document-header\xfe%s\xff"
153 . "Initial-digest\xfe%s\xff"
154 . "Part-size\xfe%x\xff"
155 . "Symmetric-cipher\xfe%s\xff",
156 $senc, $sini, $partsize, $cipher;
157
158 $route = Net::FCP::Util::encode_base64 +(Digest::SHA1::sha1 $route) . (pack "C", $padded_log) . "\x03\x02";
159 $hash = Net::FCP::Util::encode_base64 $hash;
160
161 return "freenet:CHK\@$route,$hash";
162 $self;
163 }
164
165 =item $size = $key->size
166
167 Returns the size of the data (in bytes).
168
169 =cut
170
171 =item $digest = $key->digest
172
173 Return the store digest/hash.
174
175 =cut
176
177 =item $keynum = $key->keynumber
178
179 Returns the keynumber (version?)
180
181 =cut
182
183 =item $chk = $key->chk
184
185 Return the full CHK.
186
187 =cut
188
189 =back
190
191 =head1 SEE ALSO
192
193 L<Net::FCP>.
194
195 =head1 BUGS
196
197 Not heavily tested.
198
199 =head1 AUTHOR
200
201 Marc Lehmann <schmorp@schmorp.de>
202 http://home.schmorp.de/
203
204 =cut
205
206 1;
207