Skip to content

Instantly share code, notes, and snippets.

@Qix-
Last active July 10, 2023 10:00
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Qix-/affef08b50686e54e1f2ca18f97a6ff7 to your computer and use it in GitHub Desktop.
Save Qix-/affef08b50686e54e1f2ca18f97a6ff7 to your computer and use it in GitHub Desktop.
SHA256 in (mostly) pure Bash script
#!/usr/bin/env bash
# Released into the Public Domain.
#
# Original implementation in C by Brad Conte (brad@bradconte.com) <https://github.com/B-Con/crypto-algorithms>
# Ported to Bash (lol) by Josh Junon (josh@junon.me) <https://github.com/qix->
#
# Yes, it's absolutely as slow as it looks.
#
# The only external dependency it has is on a utility called `od`,
# located around line 125. You're more than welcome to replace it with `xxd`
# or some other utility that converts binary to ASCII decimal representation.
function sha256 {
typeset -a k
typeset -a data
typeset -a rhash
typeset -a bitlen
typeset -a state
typeset -i datalen
k=($((0x428a2f98)) $((0x71374491)) $((0xb5c0fbcf)) $((0xe9b5dba5)) $((0x3956c25b)) $((0x59f111f1)) $((0x923f82a4)) $((0xab1c5ed5)) \
$((0xd807aa98)) $((0x12835b01)) $((0x243185be)) $((0x550c7dc3)) $((0x72be5d74)) $((0x80deb1fe)) $((0x9bdc06a7)) $((0xc19bf174)) \
$((0xe49b69c1)) $((0xefbe4786)) $((0x0fc19dc6)) $((0x240ca1cc)) $((0x2de92c6f)) $((0x4a7484aa)) $((0x5cb0a9dc)) $((0x76f988da)) \
$((0x983e5152)) $((0xa831c66d)) $((0xb00327c8)) $((0xbf597fc7)) $((0xc6e00bf3)) $((0xd5a79147)) $((0x06ca6351)) $((0x14292967)) \
$((0x27b70a85)) $((0x2e1b2138)) $((0x4d2c6dfc)) $((0x53380d13)) $((0x650a7354)) $((0x766a0abb)) $((0x81c2c92e)) $((0x92722c85)) \
$((0xa2bfe8a1)) $((0xa81a664b)) $((0xc24b8b70)) $((0xc76c51a3)) $((0xd192e819)) $((0xd6990624)) $((0xf40e3585)) $((0x106aa070)) \
$((0x19a4c116)) $((0x1e376c08)) $((0x2748774c)) $((0x34b0bcb5)) $((0x391c0cb3)) $((0x4ed8aa4a)) $((0x5b9cca4f)) $((0x682e6ff3)) \
$((0x748f82ee)) $((0x78a5636f)) $((0x84c87814)) $((0x8cc70208)) $((0x90befffa)) $((0xa4506ceb)) $((0xbef9a3f7)) $((0xc67178f2)))
local data=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
local rhash=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
local datalen=0
local bitlen=(0 0)
local state=($((0x6a09e667)) $((0xbb67ae85)) $((0x3c6ef372)) $((0xa54ff53a)) $((0x510e527f)) $((0x9b05688c)) $((0x1f83d9ab)) $((0x5be0cd19)))
function dbl_int_add {
if [ ${bitlen[0]} -gt $(( 0xffffffff - ${1} )) ]; then
bitlen[1]=$(( ${bitlen[1]} + 1 ))
fi
bitlen[0]=$(( ${bitlen[0]} + ${1} ))
}
function rotright {
echo $(( ((${1} >> ${2}) | (${1} << (32 - ${2}))) & 0xFFFFFFFF ))
}
function ch {
echo $(( (${1} & ${2}) ^ ($(not32 ${1}) & ${3}) ))
}
function maj {
echo $(( (${1} & ${2}) ^ (${1} & ${3}) ^ (${2} & ${3}) ))
}
function ep0 {
echo $(( $(rotright ${1} 2) ^ $(rotright ${1} 13) ^ $(rotright ${1} 22) ))
}
function ep1 {
echo $(( $(rotright ${1} 6) ^ $(rotright ${1} 11) ^ $(rotright ${1} 25) ))
}
function sig0 {
echo $(( $(rotright ${1} 7) ^ $(rotright ${1} 18) ^ (${1} >> 3) ))
}
function sig1 {
echo $(( $(rotright ${1} 17) ^ $(rotright ${1} 19) ^ (${1} >> 10) ))
}
function b32 {
echo $(( ${1} & 0xFFFFFFFF ))
}
function not32 {
b32 $(( ~${1} ))
}
function sha256_transform {
declare -a m
m=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
for i in `seq 0 15`; do
local j=$(($i * 4))
m[$i]=$(b32 $(( (${data[$j]} << 24) | (${data[$(($j + 1))]} << 16) | (${data[$(($j + 2))]} << 8) | ${data[$(($j + 3))]} )))
done
for i in `seq 16 63`; do
m[$i]=$(b32 $(( $(sig1 ${m[$(($i - 2))]}) + ${m[$(($i - 7))]} + $(sig0 ${m[$(($i - 15))]}) + ${m[$(($i - 16))]} )))
done
local a=${state[0]}
local b=${state[1]}
local c=${state[2]}
local d=${state[3]}
local e=${state[4]}
local f=${state[5]}
local g=${state[6]}
local h=${state[7]}
for i in `seq 0 63`; do
local t1=$(b32 $(( $h + $(ep1 $e) + $(ch $e $f $g) + ${k[$i]} + ${m[$i]} )))
local t2=$(b32 $(( $(ep0 $a) + $(maj $a $b $c) )))
h=$g
g=$f
f=$e
e=$(b32 $(( $d + $t1 )))
d=$c
c=$b
b=$a
a=$(b32 $(( $t1 + $t2 )))
done
state[0]=$(b32 $(( ${state[0]} + $a )))
state[1]=$(b32 $(( ${state[1]} + $b )))
state[2]=$(b32 $(( ${state[2]} + $c )))
state[3]=$(b32 $(( ${state[3]} + $d )))
state[4]=$(b32 $(( ${state[4]} + $e )))
state[5]=$(b32 $(( ${state[5]} + $f )))
state[6]=$(b32 $(( ${state[6]} + $g )))
state[7]=$(b32 $(( ${state[7]} + $h )))
}
while read line; do
for byte in $line; do
data[$datalen]=$byte
datalen=$(( $datalen + 1 ))
if [ $datalen -eq 64 ]; then
sha256_transform
dbl_int_add 512
datalen=0
fi
done
done < <(od -An -t d1) # Replace the call to `od` with your favorite
# binary -> ASCII dec converter here (e.g. xxd)
local i=$datalen
if [ $datalen -lt 56 ]; then
data[$i]=$(( 0x80 ))
i=$(( $i + 1 ))
while [ $i -lt 56 ]; do
data[$i]=0
i=$(( $i + 1 ))
done
else
data[$i]=$(( 0x80 ))
i=$(( $i + 1 ))
while [ $i -lt 64 ]; do
data[$i]=0
i=$(( $i + 1 ))
done
sha256_transform
for j in `seq 0 55`; do
data[$j]=0
done
fi
dbl_int_add $(( $datalen * 8 ))
data[63]=$(( ${bitlen[0]} & 0xFF ))
data[62]=$(( (${bitlen[0]} >> 8) & 0xFF ))
data[61]=$(( (${bitlen[0]} >> 16) & 0xFF ))
data[60]=$(( (${bitlen[0]} >> 24) & 0xFF ))
data[59]=$(( ${bitlen[1]} & 0xFF ))
data[58]=$(( (${bitlen[1]} >> 8) & 0xFF ))
data[57]=$(( (${bitlen[1]} >> 16) & 0xFF ))
data[56]=$(( (${bitlen[1]} >> 24) & 0xFF ))
sha256_transform
for j in `seq 0 3`; do
rhash[$j]=$(( (${state[0]} >> (24 - $j * 8)) & 0xff ))
rhash[$(( $j + 4 ))]=$(( (${state[1]} >> (24 - $j * 8)) & 0xff ))
rhash[$(( $j + 8 ))]=$(( (${state[2]} >> (24 - $j * 8)) & 0xff ))
rhash[$(( $j + 12 ))]=$(( (${state[3]} >> (24 - $j * 8)) & 0xff ))
rhash[$(( $j + 16 ))]=$(( (${state[4]} >> (24 - $j * 8)) & 0xff ))
rhash[$(( $j + 20 ))]=$(( (${state[5]} >> (24 - $j * 8)) & 0xff ))
rhash[$(( $j + 24 ))]=$(( (${state[6]} >> (24 - $j * 8)) & 0xff ))
rhash[$(( $j + 28 ))]=$(( (${state[7]} >> (24 - $j * 8)) & 0xff ))
done
printf "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" ${rhash[@]}
}
sha256
@dirmeier
Copy link

It's beautiful. <3

@Qix-
Copy link
Author

Qix- commented Oct 20, 2017

Danke <3

@pinouchon
Copy link

pinouchon commented Oct 20, 2017

This link was made for these kind of gists I suppose...

image

@BrandonRomano
Copy link

BrandonRomano commented Oct 20, 2017

👏

This is some clean Bash

@legionus
Copy link

you can replace od by:

export LANG=C

odbash()
{
	local c x
	while IFS= read -r -n 1 -d '' c; do
		printf -v x "%d" "'$c"
		printf '%4d' $(( $x & 0xff ))
	done
	printf '\n'
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment