Last active
February 15, 2025 07:24
-
-
Save Qix-/affef08b50686e54e1f2ca18f97a6ff7 to your computer and use it in GitHub Desktop.
SHA256 in (mostly) pure Bash script
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
#!/usr/bin/env bash | |
# Released into the Public Domain. | |
# | |
# Original implementation in C by Brad Conte ([email protected]) <https://github.com/B-Con/crypto-algorithms> | |
# Ported to Bash (lol) by Josh Junon ([email protected]) <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 |
Danke <3
👏
This is some clean Bash
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
It's beautiful. <3