Skip to content

Instantly share code, notes, and snippets.

@ogarrett
Created April 25, 2013 14:06
Show Gist options
  • Save ogarrett/5459969 to your computer and use it in GitHub Desktop.
Save ogarrett/5459969 to your computer and use it in GitHub Desktop.
libHMAC: TrafficScript library to calculate HMAC hashes

This Riverbed TrafficScript library implements the HMAC/SHA1 and HMAC/MD5 calculations.

For more details and usage instructions, check out https://splash.riverbed.com/docs/DOC-1610

Tags: #Stingray #TrafficScript #HMAC #splash.riverbed.com

# Riverbed TrafficScript HMAC library
#
# Function exports:
# MD5( key, data )
# SHA1( key, data )
sub MD5( $key, $data ) {
$blocksize = 64; # MD5 blocksize
$s00_64 =
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
$s5c_64 =
"\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c" .
"\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c" .
"\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c" .
"\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c";
$s36_64 =
"\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36" .
"\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36" .
"\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36" .
"\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36";
if( string.length( $key ) > $blocksize ) $key = string.hashMD5( $key );
if( string.length( $key ) < $blocksize ) $key = string.replaceBytes( $s00_64, $key, 0 );
$o_key_pad = string_xor( $s5c_64, $key );
$i_key_pad = string_xor( $s36_64, $key );
$h = string.hashMD5( $o_key_pad . string.hashMD5( $i_key_pad . $data ));
return $h;
}
sub SHA1( $key, $data ) {
$blocksize = 64; # SHA1 blocksize
$s00_64 =
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
$s5c_64 =
"\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c" .
"\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c" .
"\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c" .
"\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c";
$s36_64 =
"\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36" .
"\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36" .
"\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36" .
"\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36\x36";
if( string.length( $key ) > $blocksize ) $key = string.hashSHA1( $key );
if( string.length( $key ) < $blocksize ) $key = string.replaceBytes( $s00_64, $key, 0 );
$o_key_pad = string_xor( $s5c_64, $key );
$i_key_pad = string_xor( $s36_64, $key );
$h = string.hashSHA1( $o_key_pad . string.hashSHA1( $i_key_pad . $data ));
return $h;
}
sub string_xor( $a, $b ) {
$r = "";
while( string.length( $a ) ) {
$a1 = string.left( $a, 1 ); $a = string.skip( $a, 1 );
$b1 = string.left( $b, 1 ); $b = string.skip( $b, 1 );
$r = $r . chr( ord( $a1 ) ^ ord ( $b1 ) );
}
return $r;
}
# Performance and correctness tests for libHMAC.rts
#
# Apply this rule to an HTTP virtual server and submit a request to run these tests
import libHMAC.rts as hmac;
# Correctness tests
$r = "Test cases from http://tools.ietf.org/html/draft-cheng-hmac-test-cases-00:\n\n";
$r .= testcorrectness( 1, "MD5",
"0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"Hi There",
"0x9294727a3638bb1c13f48ef8158bfc9d" );
$r .= testcorrectness( 2, "MD5",
"Jefe",
"what do ya want for nothing?",
"0x750c783e6ab0b503eaa86e310a5db738" );
$a = ""; for( $i = 0; $i < 50; $i++ ) $a .= "\xdd";
$r .= testcorrectness( 3, "MD5",
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
$a,
"0x56be34521d144c88dbb8c733f0e8b3f6" );
$a = ""; for( $i = 0; $i < 50; $i++ ) $a .= "\xcd";
$r .= testcorrectness( 4, "MD5",
"0x0102030405060708090a0b0c0d0e0f10111213141516171819",
$a,
"0x697eaf0aca3a3aea3a75164746ffaa79" );
$r .= testcorrectness( 5, "MD5",
"0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
"Test With Truncation",
"0x56461ef2342edc00f9bab995690efd4c" );
$a = ""; for( $i = 0; $i < 80; $i++ ) $a .= "\xaa";
$r .= testcorrectness( 6, "MD5",
$a,
"Test Using Larger Than Block-Size Key - Hash Key First",
"0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd" );
$r .= testcorrectness( 7, "MD5",
$a,
"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
"0x6f630fad67cda0ee1fb1f562db3aa53e" );
$r .= testcorrectness( 1, "SHA1",
"0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"Hi There",
"0xb617318655057264e28bc0b6fb378c8ef146be00" );
$r .= testcorrectness( 2, "SHA1",
"Jefe",
"what do ya want for nothing?",
"0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79" );
$a = ""; for( $i = 0; $i < 50; $i++ ) $a .= "\xdd";
$r .= testcorrectness( 3, "SHA1",
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
$a,
"0x125d7342b9ac11cd91a39af48aa17b4f63f175d3" );
$a = ""; for( $i = 0; $i < 50; $i++ ) $a .= "\xcd";
$r .= testcorrectness( 4, "SHA1",
"0x0102030405060708090a0b0c0d0e0f10111213141516171819",
$a,
"0x4c9007f4026250c6bc8414f9bf50c86c2d7235da" );
$r .= testcorrectness( 5, "SHA1",
"0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
"Test With Truncation",
"0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04" );
$a = ""; for( $i = 0; $i < 80; $i++ ) $a .= "\xaa";
$r .= testcorrectness( 6, "SHA1",
$a,
"Test Using Larger Than Block-Size Key - Hash Key First",
"0xaa4ae5e15272d00e95705637ce8a3b55ed402112" );
$r .= testcorrectness( 7, "SHA1",
$a,
"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
"0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91" );
$r .= "\nPerformance tests (running on single core):\n\n";
$r .= testperformance( "MD5" );
$r .= testperformance( "SHA1" );
http.sendResponse( 200, "text/plain", $r, "" );
#---------------------------------
sub testcorrectness( $num, $method, $k, $d, $h ) {
if( string.startsWith( $k, "0x" )) $k = string.hexdecode( string.skip( $k, 2 ));
if( string.startsWith( $d, "0x" )) $d = string.hexdecode( string.skip( $d, 2 ));
if( string.startsWith( $h, "0x" )) $h = string.hexdecode( string.skip( $h, 2 ));
$r = "Test case #".$num.":";
if( $method == "MD5" ) {
$r .= " Testing HMAC-MD5... ";
if( hmac.MD5( $k, $d ) == $h ) {
$r .= "passed\n";
} else {
$r .= "failed\n";
}
}
if( $method == "SHA1" ) {
$r .= " Testing HMAC-SHA1... ";
if( hmac.SHA1( $k, $d ) == $h ) {
$r .= "passed\n";
} else {
$r .= "failed\n";
}
}
return $r;
}
sub testperformance( $method ) {
$k = "This is my key";
$d = "This is the data";
$r = "";
$r .= "Testing performance for HMAC-".$method."\n";
# How long do 1000 hash operations take?
$start = sys.time.highres();
if( $method == "MD5" ) {
for( $i = 0; $i < 1000; $i++ ) hmac.MD5( $k, $d );
} else if( $method == "SHA1" ) {
for( $i = 0; $i < 1000; $i++ ) hmac.SHA1( $k, $d );
}
$elapsed = sys.time.highres() - $start;
$r .= " 1000 operations took ".$elapsed."s\n";
# Estimate how many operations we can perform in 5 seconds
$count = math.rint( 5*1000/$elapsed );
$start = sys.time.highres();
if( $method == "MD5" ) {
for( $i = 0; $i < $count; $i++ ) hmac.MD5( $k, $d );
} else if( $method == "SHA1" ) {
for( $i = 0; $i < $count; $i++ ) hmac.SHA1( $k, $d );
}
$elapsed = sys.time.highres() - $start;
$r .= " ".$count." operations took ".$elapsed." s\n";
$r .= " Estimated rate: " . ( $count / $elapsed ) . " HMAC-".$method."/s per core\n\n";
return $r;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment