Created
August 16, 2011 04:55
-
-
Save ShimmerFairy/1148462 to your computer and use it in GitHub Desktop.
SHA1 calculator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use v6; | |
module Digest::SHA::One:auth<lue>:version<0>; | |
# This sub takes a string and calculates its SHA-1 hash | |
our sub calculate_sha1(Str $input) is export { | |
my $message = $input; | |
if ($message.bytes * 8).Num >= (2**64.Num) { | |
# checks if number of bits in $message is more than 2**64 bits | |
# Num used 'cos default type Int is signed | |
fail "The string you provided is {$message.bytes/(1024**6)} EiB, which exceeds the length limit (2 EiB) for SHA-1."; | |
} | |
# blergh. Buf might be more preferable, but is NYI in nom. So, | |
# things are modified on a bit level! | |
# on the plus side, the C<* 8> in ($message.bytes * 8) isn't needed! | |
$message = $message.split('')».ord».fmt('%08b').join(''); | |
if $message.bytes % 512 > 0 { # is the message size (in bits) a multiple of 512? If not, we pad! | |
# now each byte of the string is a bit of the original. * 8 isn't needed! | |
my $origlength = ($message.bytes).fmt('%064b'); # length of string used at end of padding. Must be 8 B (64 b) long | |
my $lastblocksize = $message.bytes % 512; # how large is the last block of data? | |
# Start padding! | |
$message ~= '1'; # first, pad with a single 1. | |
$message ~= ('0' xx ($lastblocksize - 65)); # pad with 0's until we get to where the original length is stored. | |
$message ~= $origlength; # final 64 bits are the length of the original message. | |
fail "Something in the padding process went wrong. Can't continue." if $message.bytes % 512 > 0; | |
} | |
# Time for calculating the hash! | |
# Not really. First we must define some things. | |
# This sub simply performs some bitwise operations based on what 'round' we're on | |
sub function(Int $t where 0..79, Int $b, Int $c, Int $d) { # various operations done by throughout the 80 rounds | |
# Int[uint32] for $b, $c, and $d would probably avoid this next line. | |
fail "Arguments not 32-bit words" if ($b | $c | $d) > 0xFFFFFFFF; | |
# calculate, based on which round we're on. | |
my $result; | |
given $t { | |
when 0..19 { | |
$result = ($b +& $c) +| (($b +^ 0xFFFFFFFF) +& $d); | |
} | |
when 20..39 { | |
$result = $b +^ $c +^ $d; | |
} | |
when 40..59 { | |
$result = ($b +& $c) +| ($b +& $d) +| ($b +& $d); | |
} | |
when 60..79 { | |
$result = $b +^ $c +^ $d; | |
} | |
} | |
$result .= fmt('%032b'); | |
return $result; | |
} | |
# Returns a constant | |
sub k($t) { | |
given $t { | |
when 0..19 { | |
return 0x5A827999; | |
} | |
when 20..39 { | |
return 0x6ED9EBA1; | |
} | |
when 40..59 { | |
return 0x8F1BBCDC; | |
} | |
when 60..79 { | |
return 0xCA62C1D6; | |
} | |
} | |
} | |
# Does circular shift on 32-bit word | |
sub circshift($word, $n where 0..^32) { | |
die "The circular shift operation wasn't fed a 32 bit word." if $word > 0xFFFFFFFF; | |
return (($word +< $n) +| ($word +> 32-$n)); | |
} | |
# defining all the variables before the loop to avoid creating them all the time | |
my @M = $message.comb(/<digit>**512/); # get array of 512 bit blocks | |
my @H = 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0; # initialize the H's buffer! | |
my @ABCDE; # The other buffer (come back, user-defined indexing!) | |
my @W; # this is where the split-up @M elements go, must be done in loop. | |
my $temp; | |
for 0..^@M.elems { # Process the blocks | |
@W = ("0b" «~» @M[$_].comb(/<digit>**32/))».Int; # separate the words | |
die "An error occured while calculating the hash" if @W.elems != 16; # sanity check | |
@ABCDE = @H; # set each of the five buffers (A, B, C, D, E) to the H values in buffer (H0, H1...H5, respectively) | |
for 0..79 { # Process the words! | |
# the rest of @W is generated | |
if 16..79 { | |
@W.push(circshift((@W[$_-3] +^ @W[$_-8] +^ @W[$_-14] +^ @W[$_-16]),1)); # Blame the NSA, not me! | |
} | |
$temp = circshift(@ABCDE[0],5) + function($_, @ABCDE[1], @ABCDE[2], @ABCDE[3]) + @ABCDE[4] + @W[$_] + k($_); | |
@ABCDE[4] = @ABCDE[3]; | |
@ABCDE[3] = @ABCDE[2]; | |
@ABCDE[2] = circshift(@ABCDE[1],30); | |
@ABCDE[1] = @ABCDE[0]; | |
@ABCDE[0] = $temp; | |
} | |
@H = @H «+» @ABCDE; | |
} | |
# now, to concatenate all the @H elems | |
return [~] @H».fmt('%04X'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment