Monday, November 14, 2016

Logic with large numbers in Bash

I found that I was losing information when passing information between commands via bash. Bash cannot seem to deal with numbers larger than 64-bits. The solution was for me to change everything into an ASCII series of 0's and 1's and then run logic on the strings. The code below takes a hexadecimal number, 549b93563bfa04fb, splits it in two, and XOR's the halves. I tried the code on a 4096-bit number and it worked well.
 #!/bin/sh  
 #Before anything else, set the PATH_SCRIPT variable  
      pushd `dirname $0` > /dev/null; PATH_SCRIPT=`pwd -P`; popd > /dev/null  
      PROGNAME=${0##*/}; PROGVERSION=0.1.0   

 lowercase(){  
 # convert the uppercase to lowercase  
   echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/"  
 }  
 bashhex2bin()  
 {  
 # Take a value as a hex number and convert it to a binary string  
 #  
  HEXVAL=$1  
  #echo "$@"  
  #echo "$#"  
  if [ "$#" -lt 1 ]; then  
   # this means that the function was run without any arguments  
   : #null command to make BASH happy  
  else  
   #echo "bashhex2bin(): total args passed to me $#"  
   STRSIZE=${#HEXVAL} #the string length of the argument  
   for ((COUNTER1=0; COUNTER1 < STRSIZE ; COUNTER1++))  
   do  
    #echo "Welcome $COUNTER1 times"  
    CHARATINDEX=${HEXVAL:$COUNTER1:1}  
    #convert the hex value to binary  
    bashchar2bin $CHARATINDEX  
   done   
  fi  
 }  
 bashchar2bin()  
 {  
 # Take a nibble as an argument, and return a binary represntation  
 #  
  NIB=$1 #this should be 0 to F  
  NIB=$(lowercase $NIB)  
  case $NIB in  
   "0" )  
     printf "0000" ;;  
   "1" )  
     printf "0001" ;;  
   "2" )  
     printf "0010" ;;  
   "3" )  
     printf "0011" ;;       
   "4" )  
     printf "0100" ;;  
   "5" )  
     printf "0101" ;;  
   "6" )  
     printf "0110" ;;                  
   "7" )  
     printf "0111" ;;   
   "8" )  
     printf "1000" ;;  
   "9" )  
     printf "1001" ;;  
   "a" )  
     printf "1010" ;;  
   "b" )  
     printf "1011" ;;       
   "c" )  
     printf "1100" ;;  
   "d" )  
     printf "1101" ;;  
   "e" )  
     printf "1110" ;;   
   *)   
     printf "1111" ;;   
  esac  
 }  
 xor()   
 {  
      if (( $1 ^ $2 )) ;then  
           printf "1"  
      else  
           printf "0"  
      fi  
 }  
 bashXORbinstring()  
 {  
 # Take a string, such as arguments 1, 2:  
 # 10100001  
 # 10100000  
 # and return the XOR result  
 STRBIN1=$1  
 STRBIN2=$2  
 if [ ${#STRBIN1} -eq ${#STRBIN2} ]; then  
   STRSIZE=${#STRBIN1} #the string length of the argument  
   for ((COUNTER1=0; COUNTER1 < STRSIZE ; COUNTER1++))  
   do  
    xor ${STRBIN1:$COUNTER1:1} ${STRBIN2:$COUNTER1:1}  
   done   
 else  
  echo "ERROR, XOR failed due to different lengths $STRBIN1, $STRBIN2"   
 fi  
 }  

 CMDRESULT=549b93563bfa04fb
 # at this point, CMDRESULT should have a key, such as:  
 # 549b93563bfa04fb  
 #  
 # now need to split the key into two.  
 STRSIZE=${#CMDRESULT}   
 STRHALFSIZE=$(($STRSIZE / 2)) #divide by two  
 #now use BASH to split the string  
 #echo $CMDRESULT  
 XORARG1=${CMDRESULT:0:$STRHALFSIZE}  
 XORARG2=${CMDRESULT:$STRHALFSIZE:STRHALFSIZE}  
 #echo $XORARG1  
 #echo $XORARG2  
 #convert the strings into binary as a string  
 BINARG1=$(bashhex2bin $XORARG1)  
 BINARG2=$(bashhex2bin $XORARG2)  
 #use the XOR function to XOR the ASCII strings  
 RESULTXOR=$(bashXORbinstring $BINARG1 $BINARG2)  
 echo $BINARG1  
 echo $BINARG2  
 echo $RESULTXOR  

No comments:

Post a Comment