summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorTobi Oetiker <tobi@oetiker.ch>2008-03-18 09:10:40 +0100
committerTobi Oetiker <tobi@oetiker.ch>2008-03-18 09:10:40 +0100
commita002bbdae7018d7c23f857780074ef00e3e6f31e (patch)
tree977aceaed2d4bb1a73b47695a4d1653567d74e2f /lib
parentefe9d8dafd6a8bc5845eae3b4dbc172ad68aa187 (diff)
downloadsmokeping-a002bbdae7018d7c23f857780074ef00e3e6f31e.tar.gz
smokeping-a002bbdae7018d7c23f857780074ef00e3e6f31e.tar.xz
switch to HMAC digest to avert extension attack
Diffstat (limited to 'lib')
-rw-r--r--lib/Digest/HMAC.pm111
-rw-r--r--lib/Digest/HMAC_MD5.pm71
-rw-r--r--lib/Digest/HMAC_SHA1.pm71
-rw-r--r--lib/Smokeping/Master.pm6
-rw-r--r--lib/Smokeping/Slave.pm6
5 files changed, 259 insertions, 6 deletions
diff --git a/lib/Digest/HMAC.pm b/lib/Digest/HMAC.pm
new file mode 100644
index 0000000..e2e6b60
--- /dev/null
+++ b/lib/Digest/HMAC.pm
@@ -0,0 +1,111 @@
+package Digest::HMAC;
+$VERSION = "1.01";
+
+use strict;
+
+# OO interface
+
+sub new
+{
+ my($class, $key, $hasher, $block_size) = @_;
+ $block_size ||= 64;
+ $key = $hasher->new->add($key)->digest if length($key) > $block_size;
+
+ my $self = bless {}, $class;
+ $self->{k_ipad} = $key ^ (chr(0x36) x $block_size);
+ $self->{k_opad} = $key ^ (chr(0x5c) x $block_size);
+ $self->{hasher} = $hasher->new->add($self->{k_ipad});
+ $self;
+}
+
+sub reset
+{
+ my $self = shift;
+ $self->{hasher}->reset->add($self->{k_ipad});
+ $self;
+}
+
+sub add { my $self = shift; $self->{hasher}->add(@_); $self; }
+sub addfile { my $self = shift; $self->{hasher}->addfile(@_); $self; }
+
+sub _digest
+{
+ my $self = shift;
+ my $inner_digest = $self->{hasher}->digest;
+ $self->{hasher}->reset->add($self->{k_opad}, $inner_digest);
+}
+
+sub digest { shift->_digest->digest; }
+sub hexdigest { shift->_digest->hexdigest; }
+sub b64digest { shift->_digest->b64digest; }
+
+
+# Functional interface
+
+require Exporter;
+*import = \&Exporter::import;
+use vars qw(@EXPORT_OK);
+@EXPORT_OK = qw(hmac hmac_hex);
+
+sub hmac
+{
+ my($data, $key, $hash_func, $block_size) = @_;
+ $block_size ||= 64;
+ $key = &$hash_func($key) if length($key) > $block_size;
+
+ my $k_ipad = $key ^ (chr(0x36) x $block_size);
+ my $k_opad = $key ^ (chr(0x5c) x $block_size);
+
+ &$hash_func($k_opad, &$hash_func($k_ipad, $data));
+}
+
+sub hmac_hex { unpack("H*", &hmac); }
+
+1;
+
+__END__
+
+=head1 NAME
+
+Digest::HMAC - Keyed-Hashing for Message Authentication
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::HMAC qw(hmac hmac_hex);
+ $digest = hmac($data, $key, \&myhash);
+ print hmac_hex($data, $key, \&myhash);
+
+ # OO style
+ use Digest::HMAC;
+ $hmac = Digest::HMAC->new($key, "Digest::MyHash");
+
+ $hmac->add($data);
+ $hmac->addfile(*FILE);
+
+ $digest = $hmac->digest;
+ $digest = $hmac->hexdigest;
+ $digest = $hmac->b64digest;
+
+=head1 DESCRIPTION
+
+HMAC is used for message integrity checks between two parties that
+share a secret key, and works in combination with some other Digest
+algorithm, usually MD5 or SHA-1. The HMAC mechanism is described in
+RFC 2104.
+
+HMAC follow the common C<Digest::> interface, but the constructor
+takes the secret key and the name of some other simple C<Digest::>
+as argument.
+
+=head1 SEE ALSO
+
+L<Digest::HMAC_MD5>, L<Digest::HMAC_SHA1>
+
+RFC 2104
+
+=head1 AUTHORS
+
+Graham Barr <gbarr@ti.com>, Gisle Aas <gisle@aas.no>
+
+=cut
diff --git a/lib/Digest/HMAC_MD5.pm b/lib/Digest/HMAC_MD5.pm
new file mode 100644
index 0000000..6efa0a1
--- /dev/null
+++ b/lib/Digest/HMAC_MD5.pm
@@ -0,0 +1,71 @@
+package Digest::HMAC_MD5;
+$VERSION="1.01";
+
+use strict;
+use Digest::MD5 qw(md5);
+use Digest::HMAC qw(hmac);
+
+# OO interface
+use vars qw(@ISA);
+@ISA=qw(Digest::HMAC);
+sub new
+{
+ my $class = shift;
+ $class->SUPER::new($_[0], "Digest::MD5", 64);
+}
+
+# Functional interface
+require Exporter;
+*import = \&Exporter::import;
+use vars qw(@EXPORT_OK);
+@EXPORT_OK=qw(hmac_md5 hmac_md5_hex);
+
+sub hmac_md5
+{
+ hmac($_[0], $_[1], \&md5, 64);
+}
+
+sub hmac_md5_hex
+{
+ unpack("H*", &hmac_md5)
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Digest::HMAC_MD5 - Keyed-Hashing for Message Authentication
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::HMAC_MD5 qw(hmac_md5 hmac_md5_hex);
+ $digest = hmac_md5($data, $key);
+ print hmac_md5_hex($data, $key);
+
+ # OO style
+ use Digest::HMAC_MD5;
+ $hmac = Digest::HMAC_MD5->new($key);
+
+ $hmac->add($data);
+ $hmac->addfile(*FILE);
+
+ $digest = $hmac->digest;
+ $digest = $hmac->hexdigest;
+ $digest = $hmac->b64digest;
+
+=head1 DESCRIPTION
+
+This module provide HMAC-MD5 hashing.
+
+=head1 SEE ALSO
+
+L<Digest::HMAC>, L<Digest::MD5>, L<Digest::HMAC_SHA1>
+
+=head1 AUTHOR
+
+Gisle Aas <gisle@aas.no>
+
+=cut
diff --git a/lib/Digest/HMAC_SHA1.pm b/lib/Digest/HMAC_SHA1.pm
new file mode 100644
index 0000000..fadfb40
--- /dev/null
+++ b/lib/Digest/HMAC_SHA1.pm
@@ -0,0 +1,71 @@
+package Digest::HMAC_SHA1;
+$VERSION="1.01";
+
+use strict;
+use Digest::SHA1 qw(sha1);
+use Digest::HMAC qw(hmac);
+
+# OO interface
+use vars qw(@ISA);
+@ISA=qw(Digest::HMAC);
+sub new
+{
+ my $class = shift;
+ $class->SUPER::new($_[0], "Digest::SHA1", 64);
+}
+
+# Functional interface
+require Exporter;
+*import = \&Exporter::import;
+use vars qw(@EXPORT_OK);
+@EXPORT_OK=qw(hmac_sha1 hmac_sha1_hex);
+
+sub hmac_sha1
+{
+ hmac($_[0], $_[1], \&sha1, 64);
+}
+
+sub hmac_sha1_hex
+{
+ unpack("H*", &hmac_sha1)
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Digest::HMAC_SHA1 - Keyed-Hashing for Message Authentication
+
+=head1 SYNOPSIS
+
+ # Functional style
+ use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
+ $digest = hmac_sha1($data, $key);
+ print hmac_sha1_hex($data, $key);
+
+ # OO style
+ use Digest::HMAC_SHA1;
+ $hmac = Digest::HMAC_SHA1->new($key);
+
+ $hmac->add($data);
+ $hmac->addfile(*FILE);
+
+ $digest = $hmac->digest;
+ $digest = $hmac->hexdigest;
+ $digest = $hmac->b64digest;
+
+=head1 DESCRIPTION
+
+This module provide HMAC-SHA-1 hashing.
+
+=head1 SEE ALSO
+
+L<Digest::HMAC>, L<Digest::SHA1>, L<Digest::HMAC_MD5>
+
+=head1 AUTHOR
+
+Gisle Aas <gisle@aas.no>
+
+=cut
diff --git a/lib/Smokeping/Master.pm b/lib/Smokeping/Master.pm
index 6fbdcbf..bb06921 100644
--- a/lib/Smokeping/Master.pm
+++ b/lib/Smokeping/Master.pm
@@ -5,7 +5,7 @@ use Storable qw(nstore dclone retrieve);
use strict;
use warnings;
use Fcntl qw(:flock);
-use Digest::MD5 qw(md5_base64);
+use Digest::MD5 qw(hmac_md5_hex);
=head1 NAME
@@ -225,7 +225,7 @@ sub answer_slave {
return;
}
# lets make sure the we share a secret
- if (md5_base64($secret.$data) eq $key){
+ if (hmac_md5_hex($data,$secret) eq $key){
save_updates $cfg, $slave, $data;
} else {
print "Content-Type: text/plain\n\n";
@@ -237,7 +237,7 @@ sub answer_slave {
my $config = extract_config $cfg, $slave;
if ($config){
print "Content-Type: application/smokeping-config\n";
- print "Key: ".md5_base64($secret.$config)."\n\n";
+ print "Key: ".hmac_md5_hex($config,$secret)."\n\n";
print $config;
} else {
print "Content-Type: text/plain\n\n";
diff --git a/lib/Smokeping/Slave.pm b/lib/Smokeping/Slave.pm
index 0747860..e0e6127 100644
--- a/lib/Smokeping/Slave.pm
+++ b/lib/Smokeping/Slave.pm
@@ -4,7 +4,7 @@ use warnings;
use strict;
use Data::Dumper;
use Storable qw(nstore retrieve);
-use Digest::MD5 qw(md5_base64);
+use Digest::HMAC_MD5 qw(hmac_md5_hex);
use LWP::UserAgent;
use Safe;
use Smokeping;
@@ -80,7 +80,7 @@ sub submit_results {
Content_Type => 'form-data',
Content => [
slave => $slave_cfg->{slave_name},
- key => md5_base64($slave_cfg->{shared_secret}.$data_dump),
+ key => hmac_md5_hex($data_dump,$slave_cfg->{shared_secret}),
data => $data_dump,
config_time => $cfg->{__last} || 0,
],
@@ -93,7 +93,7 @@ sub submit_results {
Smokeping::do_debuglog("Sent data to Server. Server said $data");
return undef;
};
- if (md5_base64($slave_cfg->{shared_secret}.$data) ne $key){
+ if (hmac_md5_hex($data,$slave_cfg->{shared_secret}) ne $key){
warn "WARNING $slave_cfg->{master_url} sent data with wrong key";
return undef;
}