Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Example use of MD5: making a MAC

by saucepan (Scribe)
on Jan 10, 2001 at 11:19 UTC ( [id://50889]=note: print w/replies, xml ) Need Help??


in reply to Using MD5 and the theory behind it

Here's a concrete example of using MD5 to create a message authentication code.

Say you are writing a CGI script that plays a game with the user. You want to keep score, and give a prize of some kind to the first player who wins 100 games.

You could keep a list of players and their scores on the server, but this is complex and costly if there are a very large number of players (or a large number of them playing at once), and you don't want to waste server side storage on the vast majority of users who are expected to play two or three games and then give up.

It would be nice if you could keep their current score in a cookie, but then what is to stop someone from editing their cookies.txt file and setting their score to 99? This is where the MAC comes in:

use Digest::MD5; # Given a message and key, returns a message authentication code # with the following properties relevant to our example: # - a 22-character string that may contain + / 0-9 a-z A-Z # - any given message and key will always produce the same MAC # - if you don't know the key, it's very hard to guess it # even if you have a message, its MAC, and this source code # - if you have a message, its MAC, and even the key, it's # very hard to find a different message with the same MAC # - even a tiny change to a message, including adding on to # the end of it, will produce a very different MAC sub compute_mac { my ($message, $key) = @_; Digest::MD5::md5_base64($key, Digest::MD5::md5($key, $message)); } # Load a secret key string from somewhere safe my $secret = 'skS>DrF1d:R-6<g8qmm7@Ml}?JQD1C'; # Ensures that an integer score is decorated with it's MAC sub authenticated_score { my $score = shift; my $mac = compute_mac(int($score), $secret); "$score/$mac"; }
The authenticated_score() sub can be used to decorate a score with a code that's dependent upon both the score and your secret string. Just before you give out a score cookie to a player, run it through authenticated_score() to add the MAC:

use CGI; use CGI::Cookie; my $score = 1; $score = authenticated_score($score); my $cookie = CGI::Cookie->new(-name => 'score', -value => $score); print header(-cookie=>$cookie);
Now, when someone presents a score cookie, you can check the MAC to see whether the score is one you handed out or an impostor:

my %cookies = CGI::Cookie->fetch; $score = $cookies{score}->value; # Eliminate any score that's been tampered with $score = 0 unless $score eq authenticated_score($score);
Of course, a real program would probably want to do things in a different order:

my %cookies = CGI::Cookie->fetch; my $score = $cookies{score}->value; $score = 0 unless $score eq authenticated_score($score); # (play game here, adding 1 to $score if this is a win) log_winner() if $score >= 100; $score = authenticated_score($score); my $cookie = CGI::Cookie->new(-name => 'score', -value => $score); print header(-cookie=>$cookie); # (send the rest of your HTML to the player.)
Hmm, this turned out to be kind of long for a comment. But I spent so long on it I'm going to post it anyway, right after I mention that in a real program you might want to use CGI::EncryptForm instead of doing all this work yourself. :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://50889]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (2)
As of 2024-04-26 01:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found