4

I am working on ARM-based modem Linux host machine and I need to read a bin file as an 8-,16- or 32- bits array. I basically need to encrypt the file in question and was thinking of just XOR-ing the bits with a random bit sequence (I don't need a very complex system). The Linux host doesn't have C or PERL modules in it so I cannot use them and hence I need to do it using a shell script. Can anyone give me some pointers on how to proceed with this?

  • @DeerHunter, awk doesn't do XOR native. The shell's $((...)) does though. How is that not encryption? – Stéphane Chazelas Jun 19 '13 at 12:02
  • I'm curious - if you need to encrypt a file, why not just use openssl or gpg/pgp? – Drake Clarris Jun 19 '13 at 14:49
  • “I don't need a very complex system” Do you need the files to be encrypted or not? If yes: you need a proper encryption algorithm, which xor on its own is not (you need a one-time-pad, or a stream cipher). If not: use cat. – Gilles Jun 19 '13 at 23:24
3

Use tr (here rot128):

LC_ALL=C tr '\0-\377' '\200-\377\0-\177' < infile > outfile

For XOR 123, you'd need to compute the corresponding tr line:

LC_ALL=C tr '\0-\377' '\173\172\171\170\177\176\175\174\163\162\161\160\167\166\165\164\153\152\151\150\157\156\155\154\143\142\141\140\147\146\145\144\133\132\131\130\137\136\135\134\123\122\121\120\127\126\125\124\113\112\111\110\117\116\115\114\103\102\101\100\107\106\105\104\73\72\71\70\77\76\75\74\63\62\61\60\67\66\65\64\53\52\51\50\57\56\55\54\43\42\41\40\47\46\45\44\33\32\31\30\37\36\35\34\23\22\21\20\27\26\25\24\13\12\11\10\17\16\15\14\3\2\1\0\7\6\5\4\373\372\371\370\377\376\375\374\363\362\361\360\367\366\365\364\353\352\351\350\357\356\355\354\343\342\341\340\347\346\345\344\333\332\331\330\337\336\335\334\323\322\321\320\327\326\325\324\313\312\311\310\317\316\315\314\303\302\301\300\307\306\305\304\273\272\271\270\277\276\275\274\263\262\261\260\267\266\265\264\253\252\251\250\257\256\255\254\243\242\241\240\247\246\245\244\233\232\231\230\237\236\235\234\223\222\221\220\227\226\225\224\213\212\211\210\217\216\215\214\203\202\201\200\207\206\205\204'

More generally, to answer the question, to convert a file into an array of numbers to be used by the shell with standard commands:

set -- $(od -An -vtu1 < infile)

You can then apply the transformations you want and convert back to a file with awk's printf("%c").

That's going to be very inefficient though.

Like:

for i in $(od -An -vtu1 < infile); do
  echo "$(($i ^ 123))"
done | awk '{printf "%c", $0}' > outfile

You can use od -An -vtu2, to get 16bit numbers, but note that it is in the local endianness, so when converting back to characters, you have to take that into account.

  • That doesn't do any useful encryption. You have to vary the transformation with every character. – Gilles Jun 19 '13 at 23:24
  • @Gilles, please define "useful" in this context. – Stéphane Chazelas Jun 20 '13 at 6:30
  • Useful = that can't trivially be broken. Encryption that's trivially broken is worse than no encryption: it's added complexity and gives the illusion of security without providing any security. – Gilles Jun 20 '13 at 7:15
2

You can't use null terminators in most shell's variables (or rather, you can, but they will be terminated as, in general, they are stored as such), so that's a fairly major caveat of any binary read.

If you have xxd:

xxd -b | awk '{ for(i=2 ; i<=NF-1 ; i++) { print $i } }'

For example:

echo -n mayonnaise | xxd -b | awk '{ for(i=2 ; i<=NF-1 ; i++) { print $i } }'
01101101
01100001
01111001
01101111
01101110
01101110
01100001
01101001
01110011
01100101
  • Note that your first sentence doesn't apply to zsh which can store NUL in its variable. zsh is unlikely to be installed on the OP's machine though. – Stéphane Chazelas Jun 20 '13 at 7:11
2

I used this very crude function to xor two 128 byte files:

one_time_pad() {
    asrc="$1"
    bsrc="$2"
    dst="$3"

    atmp="`mktemp`"
    btmp="`mktemp`"

    hexdump -v -e '1/1 "%02x" " "' "$asrc" > "$atmp"
    hexdump -v -e '1/1 "%02x" " "' "$bsrc" > "$btmp"

    rm "$dst"
    touch "$dst"

    for i in `seq 1 128`
    do
        a=`awk '{print $'$i';}' < "$atmp"`
        b=`awk '{print $'$i';}' < "$btmp"`

        echo -n -e '\x'`printf "%x" $((0x$a^0x$b))` >> "$dst"
    done
}

one_time_pad in1 in2 out

Performance wise this is utterly horrible (it's calling awk twice for every byte!). In my case, performance simply wasn't an issue. I'm sure you can find a much better way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.