Sherbs
Sherbs

Reputation: 37

What is causing my md5 hash to come out incorrectly?

#!/bin/bash

# Program's Purpose: Compute time elapsed between epoch time and current time
# Produce an MD5 hash from that time
# Get code from that hash

# compute time elapsed in seconds between epoch time and current time
#EPOCH=$(date -u -d '2001-02-03 04:05:06' '+%F %H:%M:%S')
#CURRENT=$(date -u -d '2010-06-13 12:55:34' '+%F %H:%M:%S')
# code: dd15
EPOCH=$(date -u -d '1999-12-31 23:59:59' '+%F %H:%M:%S')
CURRENT=$(date -u -d '2013-05-06 07:43:25' '+%F %H:%M:%S')
# interval is time elapsed minus time elapsed % 60

echo $EPOCH
echo $CURRENT
read YEAR1 M1 DAY1 HOUR1 MIN1 SEC1 <<< "${EPOCH//[:-]/ }" 
read YEAR2 M2 DAY2 HOUR2 MIN2 SEC2 <<< "${CURRENT//[:-]/ }"
echo $YEAR1 $M1 $DAY1 $HOUR1 $MIN1 $SEC1 

# date in seconds from 
sec1=$(date -d "$EPOCH" -u +%s)
sec2=$(date -d "$CURRENT" -u +%s)
echo $sec1
echo $sec2

# get the difference from the two times
difference=$((sec2 - sec1))
difference=$((difference - ((difference % 60))))
echo $difference

# get the hash from the time
hash=$(echo -n $difference | md5sum | tr -d '\n')
hash=$(echo -n $hash | md5sum | tr -d '\n')
echo $hash

# creating two strings, one with all of the letters
# the other with all of the numbers
letter=$(echo $hash | sed 's/[0-9]*//g' | cut -c1-2)
echo $letter
num=$(echo $hash | sed 's/[^0-9]*//g')
echo $num
#num=$(echo $num | cut -c1-2)
#echo $num

# getting the last two numbers in reverse order
num1=$(echo ${num: -1})
num=$(echo "${num::-1}")
echo $num
num2=$(echo ${num: -1})
code="$letter$num1$num2"
echo $code

I'm trying to write a program that takes an epoch time and current time, computes the difference in seconds, and then creates a code by doing a double md5 hash on the time in seconds. By what times I have entered in currently, the difference in seconds should be 421, 141, 406, and the 'code' is supposed to be based on 60-second intervals, so the code I'm trying to generate should come from 421, 141, 380.

The resulting hash should be 042876ca07cb2d993601fb40a1525736, but I am getting d49904f9e7e62d0ff16e523d89be08eb. Can anyone tell me what I'm doing wrong exactly?

I read that bash leaves a newline at the end of strings, so I ran echo with -n option to remove that newline, but I am still not getting the preferred results.

Upvotes: 1

Views: 1813

Answers (1)

tripleee
tripleee

Reputation: 189297

The output of md5sum on many platforms is not just the MD5 sum. For example, on a GNU/Linux system, you get

debian$ echo -n 401 | md5sum
816b112c6105b3ebd537828a39af4818  -

Notice that the output has two fields: The actual MD5 sum, followed by two spaces, followed by the input file name (where - stands for standard input).

(By contrast, on OSX, and I would expect most *BSDs, you get

yosemite$ echo -n 401 | md5
816b112c6105b3ebd537828a39af4818

Here, you'll notice that the name of the MD5 utility is different.)

The fix should be simple. I have refactored your code to (a) prefer the portable printf over the less portable echo -n; (b) remove the completely superfluous final tr -d '\n' (newlines are trimmed off the end of the captured variable by the shell already); and (c) fold everything into a single pipeline.

hash=$(printf '%s' "$difference" | md5sum | cut -d ' ' -f 1 | tr -d '\n' |
    md5sum | cut -d ' ' -f 1)
echo "$hash"

For completeness, this code also has proper quoting; it's not strictly necessary here (but it would have been if you really needed to preserve the spacing in the value you originally obtained from md5sum, for example) but omitting quotes is a common newbie problem which should be avoided.

(Capturing a variable just so you can echo it is also a common newbie antipattern; but your code will want to use the variable hash subsequently.)

Repeated code is always a bad smell; maybe provide a function which performs the same job as the *BSD md5 utility;

md5 () { md5sum "$@" | cut -d ' ' -f 1; }
hash=$(printf '%s' "$difference" | md5 | tr -d '\n' | md5)

Upvotes: 2

Related Questions