Skip to content

Instantly share code, notes, and snippets.

@nstarke
Last active March 18, 2020 03:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nstarke/eaba741a99049430bdcb74f1b4ebc651 to your computer and use it in GitHub Desktop.
Save nstarke/eaba741a99049430bdcb74f1b4ebc651 to your computer and use it in GitHub Desktop.
Thecus Firmware Decrypt Bash Script
#!/bin/bash
#
# This script takes a Thecus Firmware Image and decrypts it.
# The encryption key is based off of one of the supported
# models, which are listed in the firmware filename. This
# script will try all of the model names in the file name
# and delete any that do not decrypt to a gzip file.
#
# You will need the following c program compiled and passed
# as the second argument for generating the key. A pure bash
# solution is forthcoming.
#
# If you are using this with GNU find use this line:
FILE="$(echo $1 | cut -c3-)"
# If you are running this from the command line itself:
# FILE=$1
EXT="${FILE##*.}"
STRING2KEY=$2
MODELS=$(echo ${FILE%"."$EXT} | tr '_' '\n')
DATA_CHECK=$(file -b $1)
if [ "$DATA_CHECK" != "data" ]; then
cp $1 "$1"".plaintext"
echo "$1 seems not encrypted"
exit 1
fi
check_key() {
MODEL=$1
KEYS=$($STRING2KEY $MODEL)
for KEY in $KEYS
do
OUT_FILE="/tmp/$FILE.$MODEL.$KEY.decrypted"
openssl enc -d -des -in "$FILE" -out "$OUT_FILE" -K "$KEY" -iv 0 -nosalt -nopad 2>/dev/null
DATA_CHECK=$(file -b "$OUT_FILE")
if [[ "$DATA_CHECK" =~ "zip" ]]; then
echo "SUCCESS for $FILE"
mv $OUT_FILE .
# We have decrypted a valid file, no need for further processing.
exit 0
else
rm $OUT_FILE
fi
done
}
for MODEL in $MODELS
do
LEN=$(echo $MODEL | wc -c)
if [ $LEN -gt 3 ] && [ $LEN -le 16 ] && [[ ! -z $MODEL ]]; then
if echo "Thecus x86 64 FW Upgrade" | grep -w $MODEL > /dev/null; then
continue
fi
check_key $MODEL
MODEL_LOW=$(echo $MODEL | tr '[:upper:]' '[:lower:]')
if [ $MODEL_LOW != $MODEL ]; then
check_key $MODEL_LOW
fi
MODEL_SERIES=${MODEL%"series"}
if [ $MODEL_SERIES != $MODEL ]; then
check_key $MODEL_SERIES
fi
MODEL_PRO=${MODEL%"PRO.*"}
if [ $MODEL_PRO != $MODEL ]; then
check_key $MODEL_PRO
fi
MODEL_UPGRADE=${MODEL%"upgrade"}
if [ $MODEL_UPGRADE != $MODEL ]; then
check_key $MODEL_UPGRADE
fi
fi
done
echo "FAILURE for $FILE"
exit 1
/* string2key: String to DES key
* written by Adrian Sai-wah Tam
* Thu Aug 9 17:27:33 HKT 2007
* adapted by nick starke
* Sun Jan 19 12:17:32 CDT 2020
* original source from:
* https://www.adrian.idv.hk/2007-08-08-firmware/
*
* Compile with
* gcc -o string2key string2key.c -lssl -lcrypto
*/
#include <openssl/des.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
DES_cblock key;
int j;
if (argc != 2) {
printf("Synopsis:\n");
printf(" %s [string]\n",argv[0]);
printf("It will give the DES key from string using the OpenSSL's DES_string_to_key()\n");
return 1;
};
DES_string_to_key(argv[1], &key);
for (j=0;j<8;j++) {
printf("%02x",key[j]);
};
printf("\n");
for (j=0;j<16;j++) {
printf("%02x",key[j]);
};
printf("\n");
for (j=0;j<strlen(argv[1]);j++) {
printf("%02x",key[j]);
};};
#!/bin/bash
####
#
# Copyright 2020 Perihelios LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
####
#
# Based on crypto/des/str2key.c from OpenSSL, which is:
#
# Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#
####
# Obtainable from: https://github.com/perihelios/bash-des-string-to-key
####
## Recommended Bash options (for any Bash script, really):
#
# set -e
# set -E
# shopt -s inherit_errexit
# set -o pipefail
DES_string_to_key() {
local str="$1"
local -a plaintextKey
plaintextKey=($(charToArray "$str"))
local -a digestKey=(0 0 0 0 0 0 0 0)
local i
for ((i = 0; i < ${#plaintextKey[@]}; i++)); do
local index=$((i % 8))
local n=${plaintextKey[$i]}
if [[ $((i % 16)) -lt 8 ]]; then
digestKey[$index]=$(((digestKey[index] ^ (n << 1)) & 0xff))
else
n=$(( ((n << 4) & 0xf0) | ((n >> 4) & 0x0f) ))
n=$(( ((n << 2) & 0xcc) | ((n >> 2) & 0x33) ))
n=$(( ((n << 1) & 0xaa) | ((n >> 1) & 0x55) ))
index=$((7 - index))
digestKey[$index]=$((digestKey[index] ^ n));
fi
done
digestKey=($(arrayForceOddParity ${digestKey[@]}))
# OpenSSL's DES_string_to_key calls DES_cbc_cksum, which always pads to block size
# with zeros. The OpenSSL des-cbc command, on the other hand, pads using PKCS#5.
# To use des-cbc while getting results like DES_cbc_cksum, prepad with zeros.
# Note that there will ALWAYS be an extraneous trailing block from des-cbc in this
# case, since PKCS#5 will pad data evenly divisible by block size with an extra
# block.
local -a zeroPaddedKey
zeroPaddedKey=($(arrayZeroPadToAlignment 8 ${plaintextKey[@]}))
local -a encryptedKey
encryptedKey=($(
arrayToBinary ${zeroPaddedKey[@]} |
openssl des-cbc -K $(arrayToHex ${digestKey[@]}) -iv $(arrayToHex ${digestKey[@]}) |
od -t d1 -A n -w${#zeroPaddedKey[@]} -N ${#zeroPaddedKey[@]}
))
arrayToHex $(arrayForceOddParity $(arrayRange $((${#encryptedKey[@]} - 8)) ${#encryptedKey[@]} ${encryptedKey[@]}))
}
arrayZeroPadToAlignment() {
local alignment="$1"
shift
local -a data=("$@")
local padding=$(( (alignment - ${#data[@]} % alignment) % alignment ))
echo -n "${data[@]}"
while [[ $padding -gt 0 ]]; do
echo -n ' 0'
padding=$(( padding - 1 ))
done
}
arrayToBinary() {
local -a data=("$@")
if [[ ${#data[@]} -eq 0 ]]; then return; fi
printf $(printf '\\x%02x' "${data[@]}")
}
charToArray() {
local characters="$1"
echo -n "$characters" | od -t d1 -A n -w${#characters}
}
arrayToHex() {
local -a HEX=(0 1 2 3 4 5 6 7 8 9 a b c d e f)
while [[ $# -gt 0 ]]; do
c=$1
c=$(((c >> 4) & 0xf))
echo -n "${HEX[c]}"
c=$1
c=$((c & 0xf))
echo -n "${HEX[c]}"
shift
done
echo
}
arrayRange() {
local startInclusive="$1"
local endExclusive="$2"
shift 2
local array=("$@")
local i
for ((i = startInclusive; i < endExclusive; i++)); do
echo -n "${array[$i]} "
done
}
arrayForceOddParity() {
while [[ $# -gt 0 ]]; do
local n=$1
shift
local parity=0
local odd=0
if ((n & 0x80)); then let ++parity; fi
if ((n & 0x40)); then let ++parity; fi
if ((n & 0x20)); then let ++parity; fi
if ((n & 0x10)); then let ++parity; fi
if ((n & 0x08)); then let ++parity; fi
if ((n & 0x04)); then let ++parity; fi
if ((n & 0x02)); then let ++parity; fi
if ((n & 0x01)); then
let ++parity
odd=1
fi
if ! ((parity & 1)); then
if ((odd)); then
echo -n $((n - 1))
else
echo -n $((n + 1))
fi
else
echo -n $n
fi
echo ' '
done
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment