在Bash中按位XOR一个字符串

时间:2010-06-02 17:46:41

标签: perl bash scripting shell

我正在尝试用Bash脚本完成一项工作。我有一个字符串,我想用我的密钥进行异或。

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

teststring="abcdefghijklmnopqr"

现在我如何对testtring的值进行异或,并使用bash将其存储在变量中?

任何帮助将不胜感激。

基本上我正在尝试复制以下VB脚本的结果:

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

6 个答案:

答案 0 :(得分:4)

these hints的帮助下,我写了这个快速的脚本来完成佩德罗的回答:

#!/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"

结果:

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

答案 1 :(得分:1)

如果你决定选择Perl one-liner,这就是我想出的

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
Perl 6中的

zip功能可以做得更好......

答案 2 :(得分:1)

又一个答案

function xenc {
  local data=$1 key=$2
  local _data _key ndata nkey count i _res
  _data=($(eval printf "'%d '" $(printf "%s" "$data" | sed -e '$!N;${s/./"'"'"'&" /g;s/""/\\&/g}')))
  _key=($(eval printf "'%d '" $(printf "%s" "$key" | sed '$!N;${s/./"'"'"'&" /g;s/""/\\&/g}')))
  ndata=${#_data[@]} nkey=${#_key[@]}
  (( count = ndata < nkey ? nkey : ndata ))
  for ((i = 0; i < count; i++)); do
    (( _res[i] = ${_data[i]:-0} ^ ${_key[i%nkey]:-0} ))
  done
  printf "\\\\\\%o" "${_res[@]}"  | xargs printf
}
res=$(xenc abcdefghijklmnopqrstuvwxyz FLqFb8LU0TY)
xenc "$res" FLqFb8LU0TY

答案 3 :(得分:0)

BASH中的按位异或要求两个操作数都是数字。由于没有内置的方法来获取bash中字符的序数(ASCII)值,因此您需要使用Perl来获取该值。

修改:如下所述,ord仅适用于字符串的第一个字符。

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

当然,一旦你进入Perl,你可以在那里完成所有工作:

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

编辑:事实证明,您可以使用printf获取BASH中字符串的序数值。只需在字符串前加'

printf "%d" "'string"

所以,仅在BASH中:

let a=$(printf "%d" "'string")^123; echo $a

答案 4 :(得分:0)

在busybox中炒作(粘贴无法接收两个流),也是重复的关键

#!/bin/sh
numitems() { i=0;while read ITEM; do i=$(( $i + 1 )) ; done; echo $i; }
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()
{
KEY=$1;STR=$2;
while [ ${#KEY} -lt ${#STR} ]; do KEY="$KEY$KEY"; done; #make key longer then str
[ -e /tmp/paste_col1 ] && rm -rf /tmp/paste_col1
[ -e /tmp/paste_col1t ] && rm -rf /tmp/paste_col1t
[ -e /tmp/paste_col2 ] && rm -rf /tmp/paste_col2
map_ord "$KEY">/tmp/paste_col1t
map_ord "$STR">/tmp/paste_col2
head -n `wc -l /tmp/paste_col2 |sed -r 's|^([0-9]+)\s.*|\1|'` /tmp/paste_col1t>/tmp/paste_col1 #trim lines
[ -e /tmp/paste_col1t ] && rm -rf /tmp/paste_col1t
paste /tmp/paste_col1 /tmp/paste_col2 | starmap xor | starmap chr
[ -e /tmp/paste_col1 ] && rm -rf /tmp/paste_col1
[ -e /tmp/paste_col2 ] && rm -rf /tmp/paste_col2
echo
}
KEY="12345678"
TESTSTRING="abcdefghasdfasdfasfdas"
encrypt "$KEY" "$TESTSTRING"
ENC="`encrypt \"$KEY\" \"$TESTSTRING\"`"
encrypt "$KEY" "$ENC" # we should get $TESTSTRING again

答案 5 :(得分:0)

仅将函数转换为bash的最相似的转换是:
(#表示评论):

# Function XOREncryption(CodeKey, DataIn)
XOREncryption(){
    local CodeKey=$1
    local DataIn=$2
    # Dim lonDataPtr strDataOut temp tempstring intXOrValue1 intXOrValue2
    local lonDataPtr strDataOut temp tempstring intXOrValue1 intXOrValue2

    # For lonDataPtr = 1 To Len(DataIn) Step 1
    for (( lonDataPtr=0; lonDataPtr < ${#DataIn}; lonDataPtr++ )); do
        #The first value to be XOr-ed comes from the data to be encrypted
    # intXOrValue1 = Asc(Mid(DataIn, lonDataPtr, 1))
    intXOrValue1=$( toAsc "${DataIn:$lonDataPtr:1}" )
    echo "val1=$intXOrValue1 and=<${DataIn:$lonDataPtr:1}> and $(toAsc "${DataIn:$lonDataPtr:1}")"
        #The second value comes from the code key
    echo "Ptr=$lonDataPtr Mod=<$(( lonDataPtr % ${#CodeKey} ))>"
    # intXOrValue2 = Asc(Mid(CodeKey, ((lonDataPtr Mod Len(CodeKey)) + 1), 1))
    intXOrValue2=$( toAsc "${CodeKey:$(( lonDataPtr % ${#CodeKey} )):1}" )
    echo "val1=$intXOrValue1 val2=<${CodeKey:$(( lonDataPtr % ${#CodeKey} )):1}> and |$intXOrValue2|"
    # temp = (intXOrValue1 Xor intXOrValue2)
    temp=$(( intXOrValue1 ^ intXOrValue2 ))
    echo "temp=$temp"
        # tempstring = Hex(temp)
    tempstring=$(printf '%02x' "$temp")
    echo "tempstring=$tempstring"
    # strDataOut = strDataOut + tempstring
        strDataOut+=$tempstring
    echo
    # Next
    done
    # XOREncryption = strDataOut
    printf '%s\n' "$strDataOut"
# End Function
}

删除评论并清理代码:

#!/bin/bash

Asc() { printf '%d' "'$1"; }

XOREncryption(){
    local key=$1 DataIn=$2
    local ptr DataOut val1 val2

    for (( ptr=0; ptr < ${#DataIn}; ptr++ )); do
        val1=$( Asc "${DataIn:$ptr:1}" )
        val2=$( Asc "${key:$(( ptr % ${#key} )):1}" )
        DataOut+=$(printf '%02x' "$(( val1 ^ val2 ))")
    done
    printf '%s\n' "$DataOut"
}

CodeKey="$1"
teststring="$2"
XOREncryption "$CodeKey" "$teststring"

运行它:

$ ./script.sh "123456789" "abcdefghijklmnopqr"
5050505050505050505b595f595b5947494b