Last active
November 27, 2024 23:24
-
-
Save Qix-/eaa6b90f4f50a9aefc66c4f871e8f1e0 to your computer and use it in GitHub Desktop.
Safe cURL - pipe your cURL-obtained scripts into this and pass it a sha256 to verify against. Comes with a pure-bash sha256 implementation.
This file contains hidden or 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 | |
# Usage: curl https://some-site-with-potential-mitm.com/script.sh | scurl $verified_sha256_digest_of_script | |
# Released into the Public Domain. | |
# Written by Josh Junon ([email protected]) <github.com/qix-> | |
# Original SHA256 implementation in C by Brad Conte ([email protected]) <https://github.com/B-Con/crypto-algorithms> | |
# Ported to (almost) pure Bash by Josh Junon | |
# Inspired by this tweet: https://twitter.com/homakov/status/920943366816305152 | |
set -e | |
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) | |
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[@]} | |
} | |
if [ -z "${1}" ]; then | |
echo "No sha256 digest provided - aborting." >&2 | |
exit 2 | |
fi | |
script="$(cat)" | |
computed_hash= | |
if command -v openssh &>/dev/null; then | |
computed_hash="$((openssl dgst -sha256 | rev | cut -d' ' -f1 | rev) <<< "${script}")" | |
elif command -v shasum &>/dev/null; then | |
computed_hash="$(shasum -pa 256 <<< "${script}" | cut -d' ' -f1)" | |
elif command -v sha256sum &>/dev/null; then | |
computed_hash="$(sha256sum <<< "${script}" | cut -d' ' -f1)" | |
else | |
computed_hash="$(____sha256 <<< "${script}")" | |
fi | |
if [ "$computed_hash" != "${1}" ]; then | |
echo "Provided sha256 digest and digest computed by the script do not match - aborting!" >&2 | |
echo " Expected digest: ${1}" | |
echo " Computed digest: ${computed_hash}" | |
exit 3 | |
fi | |
bash <<< "${script}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment