Bash 中的按位异或字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2960136/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
bitwise XOR a string in Bash
提问by ricky2002
I am trying to accomplish a work in Bash scripting. I have a string which i want to XOR with my key.
我正在尝试在 Bash 脚本中完成一项工作。我有一个字符串,我想用我的密钥异或。
#!/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?
现在我如何使用 bash 对 teststring 的值进行异或并将其存储在变量中?
Any help will be appreciated.
任何帮助将不胜感激。
Basically i am trying to duplicate the result of follwing VB Script:
基本上我试图复制以下 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
回答by Fernando Miguélez
With the help of these hintsi wrote this quickly script to complete Pedro's answer:
在这些提示的帮助下,我编写了这个快速脚本来完成 Pedro 的回答:
#!/bin/bash
function ascii2dec
{
RES=""
for i in `echo | 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=
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
回答by Cyrille Lefevre
yet another answer
另一个答案
function xenc {
local data= key=
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
回答by Cyrille Lefevre
If you decide to go for Perl one-liner, here is what I came up with
如果你决定使用 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
zip function in Perl 6 would do a better job...
Perl 6 中的 zip 函数会做得更好......
回答by Cyrille Lefevre
The most similar transformation of only the function to bash would be:
(# means comment):
仅将函数转换为 bash 的最相似的转换是:
(# 表示注释):
# Function XOREncryption(CodeKey, DataIn)
XOREncryption(){
local CodeKey=
local DataIn=
# 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
}
Removing the comments, and cleaning the code:
删除注释并清理代码:
#!/bin/bash
Asc() { printf '%d' "'"; }
XOREncryption(){
local key= DataIn=
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=""
teststring=""
XOREncryption "$CodeKey" "$teststring"
Running it:
运行它:
$ ./script.sh "123456789" "abcdefghijklmnopqr"
5050505050505050505b595f595b5947494b
回答by Shimon Doodkin
woks in busybox(the paste could not receive two streams), also made the key to repeat
在busybox中炒锅(粘贴不能接收两个流),也做了重复的关键
#!/bin/sh
numitems() { i=0;while read ITEM; do i=$(( $i + 1 )) ; done; echo $i; }
starmap() { while read ITEM; do $ITEM; done; }
ord() { printf '%d\n' "'"; }
chr() { printf \$(printf '%03o' ); }
split_chars() { echo -n "" | sed 's/./&\n/g'; }
xor() { echo $(( ^ )); }
map_ord() { split_chars "" | starmap ord; }
encrypt()
{
KEY=;STR=;
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.*||'` /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
回答by Pedro Silva
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.
BASH 中的按位异或要求两个操作数都是数字。由于在 bash 中没有获取字符的序数 (ASCII) 值的内置方法,因此您需要使用 Perl 来获取该值。
Edit: as noted below, ordworks on the first character of a string only.
编辑:如下所述,仅ord适用于字符串的第一个字符。
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:
当然,一旦你在 Perl 中,你也可以在那里做所有的事情:
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. 只需在字符串前加上'.
printf "%d" "'string"
So, in BASH only:
因此,仅在 BASH 中:
let a=$(printf "%d" "'string")^123; echo $a

