views:

608

answers:

4

Hi. I am trying to accomplish a work in Bash scripting. I have a string which i want to XOR with my key.

#!/bin/sh
PATH=/bin:/usr/bin:/sbin:/usr/sbin export PATH

teststring="abcdefghijklmnopqr"

Now how do i XOR the value of teststring and store it in a variable using bash?

Any help will be appreciated.

Basically i am trying to duplicate the result of follwing VB Script:

Function XOREncryption(CodeKey, DataIn)

Dim lonDataPtr
Dim strDataOut
Dim temp
Dim tempstring
Dim intXOrValue1
Dim intXOrValue2


For lonDataPtr = 1 To Len(DataIn) Step 1
    'The first value to be XOr-ed comes from the data to be encrypted
    intXOrValue1 = Asc(Mid(DataIn, lonDataPtr, 1))
    'The second value comes from the code key
    intXOrValue2 = Asc(Mid(CodeKey, ((lonDataPtr Mod Len(CodeKey)) + 1), 1))

    temp = (intXOrValue1 Xor intXOrValue2)
    tempstring = Hex(temp)
    If Len(tempstring) = 1 Then tempstring = "0" & tempstring

    strDataOut = strDataOut + tempstring
Next
XOREncryption = strDataOut
End Function
A: 

Bitwise exclusive-OR in BASH requires both operands to be numeric. Since there's no built-in way of getting the ordinal (ASCII) value of a character in bash, you'll need to use, say, Perl, to get that value.

Edit: as noted below, ord works on the first character of a string only.

let a=`perl -e 'print ord $_ for split //, $ARGV[0]' string`^123; echo $a

Of course, once you're in Perl, you might as well do it all there:

let a=`perl -e '$ordinal .= ord $_ for split //, $ARGV[0]; print $ordinal ^ $ARGV[1]' string 123`

Edit: it turns out you can grab the ordinal value of a string in BASH using printf. Simply prefix the string with '.

printf "%d" "'string"

So, in BASH only:

let a=$(printf "%d" "'string")^123; echo $a
Pedro Silva
i have something like this in bash but its showing 0 as output...username=`whoami`test=`perl -e 'print ord $strUrl ^ key'`echo ${test}am i making any mistake?
ricky2002
You need to wrap the `perl` command in either backticks or $(). Also, `$strUrl` is undefined, and `key` is a bareword.
Pedro Silva
Is this the proper way of doing it? i am getting a two digit number as output but i was expecting a long number.key=secretstrUrl=cdcdcdcstrUrl=$(($(printf "%d" "'strUrl")^$(printf "%d" "'key")));echo $strUrl
ricky2002
`ord` operates on a single character, so `ord $ARGV[0]` returns the ordinal value of the *first character* of `$ARGV[0]`
mobrule
You're getting the result in decimal format. Convert it to binary with `unpack("N", pack("B32", substr("0" x 32 . $decimal, -32)))`
Pedro Silva
@Pedro, should the unpack be wrapped in ticks?
ricky2002
strUrl=unpack("N", pack("B32", substr("0" x 32 . $strUrl, -32)))This line gives me "Syntax error: "(" unexpected" message
ricky2002
ricky, the unpack is within perl. In any case, just go with the all-BASH version
Pedro Silva
@pedro, this gives me a blank output...Did you also notice the VBscript version of the function which i am trying to match my output to? strUrl=$(($(printf "%d" "'strUrl")^$(printf "%d" "'key"))); strUrl=`perl -le 'unpack("N", pack("B32", substr("0" x 32 . $strUrl, -32)))'`Any ideas?
ricky2002
`$strUrl` in the perl portion is undefined. Passed it as an argument, like so: `strUrl=perl -le 'unpack("N", pack("B32", substr("0" x 32 . $ARGV[0], -32)))' $strUrl`
Pedro Silva
A: 

If you decide to go for Perl one-liner, here is what I came up with

perl -e '@a=split("", $ARGV[0]); @b=split("", $ARGV[1]); print unpack "H2", chr(ord(shift @a)^ord(shift @b)) while @a; print "\n"' aab aaa

zip function in Perl 6 would do a better job...

Arkadiy
+1  A: 

With the help of these hints i wrote this quickly script to complete Pedro's answer:

#!/bin/bash

function ascii2dec
{
  RES=""
  for i in `echo $1 | sed "s/./& /g"`
  do 
    RES="$RES `printf \"%d\" \"'$i\"`"
  done 
  echo $RES
}

function dec2ascii
{
  RES=""
  for i in $*
  do 
    RES="$RES`printf \\\\$(printf '%03o' $i)`"
  done 
  echo $RES
}

function xor
{
  KEY=$1
  shift
  RES=""
  for i in $*
  do
    RES="$RES $(($i ^$KEY))"
  done

  echo $RES
}


KEY=127
TESTSTRING="abcdefghijklmnopqr"

echo "Original String: $TESTSTRING"
STR_DATA=`ascii2dec "$TESTSTRING"`
echo "Original String Data: $STR_DATA"
XORED_DATA=`xor $KEY $STR_DATA`
echo "XOR-ed Data: $XORED_DATA"
RESTORED_DATA=`xor $KEY $XORED_DATA`
echo "Restored Data: $RESTORED_DATA"
RESTORED_STR=`dec2ascii $RESTORED_DATA`
echo "Restored String: $RESTORED_STR"

Result:

iMac:Desktop fer$ bash test.sh
Original String: abcdefghijklmnopqr
Original String Data: 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 
XOR-ed Data: 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13
Restored Data: 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 
Restored String: abcdefghijklmnopqr
Fernando Miguélez
A: 

Another perspective: that's essentially Fernando's answer with a FP-style (slow as hell, that's for sure):

starmap() { while read ITEM; do $1 $ITEM; done; }
ord() { printf '%d\n' "'$1"; }
chr() { printf \\$(printf '%03o' $1); }
split_chars() { echo -n "$1" | sed 's/./&\n/g'; }
xor() { echo $(($1 ^ $2)); }

map_ord() { split_chars "$1" | starmap ord; }

encrypt() {
  paste <(map_ord "$1") <(map_ord "$2") | starmap xor | starmap chr
  echo
}

KEY="12345678"
TESTSTRING="abcdefgh"

ENC=$(encrypt "$KEY" "$TESTSTRING")
encrypt "$KEY" "$ENC" # we should get $TESTSTRING again

I guess this code will look like gibberish if you don't have some functional-programming background. Of course, you should use a better-suited language for this task (Python/Perl/Ruby/...)

tokland