Re: [dev] Fmask [c posix]

From: Marc Collin <>
Date: Wed, 30 Dec 2015 22:54:40 -0200

Hiltjo, I'm sorry, that was really unthoughtful from me.
Not sure if this email conversation is still able to be saved, but
here goes the the author's documentation I mentioned.
In the future I'll remember to make better emails.

fmask -- apply masks to files.

Table of Contents
1 Where did the name come from?
2 I want to compile this!
3 HOWTO use fmask
4 principles of the mask programs (HOWTO add your own)
5 How powerful is this?

1 Where did the name come from?

Gmask. []

2 I want to compile this!

!UNIX ONLY! Just chmod and run dummy !UNIX ONLY!

3 HOWTO use fmask

fmask is simple. You specify the operations you want to perform to the
file, in the arguments, and the file itself in the last argument. I've
implemented three operations: reverse, swap and xor. The last one is
just xor'ing the file with a byte or a passphrase. If it's a three or
less digit number, it xors with the bytes value, else it treats it as
a string. To pass arguments to those operations you use the :
character to separate their name from their arguments. Example use:

./fmask xor:15 example-file

will xor example-file with the byte 0x0F. The output of fmask will be
the arguments you need to pass to fmask in order to get the original
file back from the new file (fmask will modify example-file, it won't
create a new file with the result). In this example, fmask will

xor:15 example-file

since xor is an inverse operation of itself. I've written two more
programs, reverse and swap, which are generalizations of simpler
operations. For reverse, with no arguments it simply reverses a
file. If the content of example-file is 123456, with

./fmask reverse example-file

example-file will contain 654321. How can this be generalized? By
adding an argument, say x, which shows how many bytes will be treated
as a single block. In case of no arguments, x is 1 (note reverse is
also an inverse operation of itself). Here's how to visualize this

block 1 block 2 block 2 block 1
+--------+--------+ +--------+--------+
+---+---+---+---+ reverse:2 +---+---+---+---+
| A | B | C | D | =========> | C | D | A | B |
+---+---+---+---+ +---+---+---+---+

The last operation, swap, is merely exchanging odd-offset blocks with
even blocks for a block of size 1:


for blocks of larger size, it joins them. Suppose the block size is 3:


Here's a way to visualize this:

block 1 block 2
| A | B | C | D | E | F |

block 1
| A | B | C |
+---+---+---+ \
block 2 join these DA - EB - FC
+---+---+---+ /
| D | E | F |

D is picked first (first from block 2). Then A is picked second
(first from block 1). E is picked third, and B is picked fourth, et
cetera (this is a generalization of the odd/even exchange).

This operation is not the inverse of itself. I have written another
program, called rswap (which you don't need to use by yourself; it's
useful only for fmask), which is the inverse of swap. Here's an

printf 123456 > example-file
./fmask swap:3 example-file

output is rswap:3 example-file. That tells you with the argument
'rswap:3 example-file', fmask will create the original file back from
the new file just created.

There's one thing to mention left: padding. Because reverse and swap
operate on blocks of arbitrary size, sometimes the block size does not
perfectly divide the file size into blocks; when this occurs, fmask
will add padding bytes of random values to the end of the file before
it calls the operations. As such, you'll also need to crop these
random bytes out. That is why fmask also provides the 'resize'
operation, which you should not use by yourself because you will lose
your data. Here's an illustration of what I'm talking about

printf 123456 > example-file
./fmask reverse:4 swap:5 example-file

Since example-file is only 6 bytes long, 2 bytes must be added in
order for 4 to perfectly divide the size of the file. These two random
bytes are added. Then reverse is performed. Then comes the time of
swap, which has a block size of 5. The file is 8 bytes long, and 2
bytes must be added in order for 5 to perfectly divide the file
size. These bytes are added, then swap is performed. Clearly, the
reverse operations will have to remove those bytes in every step. The
return string of fmask demonstrates this:

rswap:5 resize:8 reverse:4 resize:6 foo

notice the file is resized twice.

4 principles of the mask programs (HOWTO add your own)

1) must have an inverse program
2) must print the number of bytes added to the file in case of padding
-- the inverse program must get those bytes to be the last in the
file (this will be fixed in the next version of fmask and the
program won't have to do this dirty job -- fmask will do it).
3) the last argument argv[argc-1] is the file operating on, passed by
fmask. It's handy because of 'file = argv[--argc];'

Here's an example, the simple_xor.c program:

int main(int argc, char **argv)
FILE *fp;
fpos_t fpos;
int c;
// we want 2 arguments, byte to xor and the filename
if(argc != 3) return 0;
if((fp = fopen(argv[argc - 1], "r+b")) == NULL) return 0;
fgetpos(fp, &pos);
while((c = getc(fp)) != EOF) {
fsetpos(fp, &pos); // go back 1 byte to write the new byte
putc(c ^ argv[1][0], fp);
fgetpos(fp, &pos);
puts("0"); // we did not modify the file size; print 0 to indicate
// 0 bytes were added to the file.
return 0;

Compile and put the binary in the fmask directory. Run

./fmask simple_xor:A example-file

to XOR example-file bytes with the byte A.
If your operation has an inverse different than itself, you must add
the alias to the cmds[] struct in fmask.c. swap is one such operation;
rswap is its inverse (and swap is the inverse of rswap -- struct works
both ways).

5 How powerful is this?

Really powerful! Or at least the author thinks so. The operations
reverse and swap are the only operations you'll probably ever need,
but you can add your own, and they don't have to operate on same-sized
blocks (for example, their size might be an arithmetic progression or
really anything that you have in mind). Here's an example of how well
it hides the original content of the file. example-file contains the
alphabet and a newline.

$ cat example-file
$ ./fmask reverse:3 reverse:5 swap:7 reverse:11 swap reverse example-file
reverse rswap reverse:11 resize:42 rswap:7 resize:30 reverse:5
resize:27 reverse:3 example-file
$ hd -C example-file | uniq
00000000 d3 4c e4 4b 41 4a 43 41 42 46 4d 45 52 50 51 55 |.L.KAJCABFMERPQU|
00000010 48 54 44 53 49 47 57 21 56 cf 58 7e 4f 0a 4e 5a |HTDSIGW!V.X~O.NZ|
00000020 d3 59 5a e4 71 4f cf 7e f4 21 d3 f4 |.YZ.qO.~.!..|

Recognize anything? If you run the decryption string returned by fmask
you get the original file back again, with the alphabet

Here's another example of adding rc4 functionality using OpenSSLs tools.

In this example, I'll show you how to add OpenSSL's blowfish
encryption to fmask, without writing any C code. First how to use the
openssl(1) utility for blowfish encryption and decryption:

-in (the source file)
-out (the encrypted file)
-k (password)
-d (decrypt)

first argument should be the algorithm we want to use, which is bf
(sort for blowfish). There'll be two shell scripts, for encryption and
decryption. Here is

if [ $# -eq 2 ]; then
openssl rc4 -in $2 -out "$2.temp" -k $1
mv "$2.temp" $2
echo 0

Notice I print 0 since the algorithm doesn't add any padding to the
filesize; after decryption, it'll be back to its original size, and
not some padded one. is similar except there's a -d added
in the argument list to denote decryption. If you don't want to type
the .sh part when you invoke fmask, use symbolic links like so:

ln -s rc4
ln -s rc4_dec

and don't forget to add "rc4" and "rc4_dec" in the cmds struct in

On Wed, Dec 30, 2015 at 6:50 PM, <> wrote:
> meta-meta
> * Hiltjo Posthuma 2015-12-30 12:21
>> What's next? Linking interesting tweets?
Received on Thu Dec 31 2015 - 01:54:40 CET

This archive was generated by hypermail 2.3.0 : Thu Dec 31 2015 - 02:00:12 CET