I have a key (of random binary data) that gets generated by get_key.

And with this key, I can do several things with my encrypted files. For example, I can decrypt them.

get_key | tee >(decrypt file1) >(decrypt file2)

I would like to know how I could generalize that to n files where the files are given as FILES=file1 file2 file3 file4 file5.

At the moment, I can see two solutions:

1) Compute a string and eval it

2) replace decrypt by a recursive function f that calls decrypt does tee >(decrypt A[0]) | f ("${A[@]:1}") (it decrypts the first element and calls itself recursively) if the array is not empty and nothing if it is.

I wanted to know if you had a nicer way to doing that (note that I do not want the key to be written to a file or a variable, so loops aren't an option).

Edit: I'll use it in https://github.com/xavierm02/combine-keys

  • Given what you've said in comments about wanting to feed a key to cryptsetup, I think you're barking up the wrong tree. You should carefully think about your security requirements (what are the risks? what are the attack vectors?) and infrastructure (when are you doing this — presumably in the boot process? what information and tools do you have available?) and ask one or more higher-level question about that. – Gilles 'SO- stop being evil' May 9 '14 at 17:57
  • I want to protect all data at rest with a password and a keyfile and be able to back up the keyfile using secret sharing. This implies that I can't encrypt the keyfile with the password because otherwise, I would have to replace all the backups everytime I changed the password. The only other way to require both is to derive a key from both (atm using xor). And I have any tools I want available since I can just add hooks to make update-initramfs add things to the ramfs. Aside from the derivation method, there is no real choice, unless I want to mess with dm-crypt directly, and I don't. – xavierm02 May 9 '14 at 22:29
  • @Gilles : I asked a new question there: crypto.stackexchange.com/questions/16109/… – xavierm02 May 10 '14 at 17:24

Make FIFOs in a loop and have your decrypts wait for them to be written to:

for i in "${A[@]}";do
    mkfifo /tmp/"$i"_fifo
    decrypt "$i" </tmp/"$i"_fifo &
getkey | tee >/dev/null /tmp/*_fifo
rm -f /tmp/*_fifo
  • You're writing the keys to several files. I want to use the key to decrypt several files.. – xavierm02 May 8 '14 at 22:14
  • @xavierm02 Sorry, I wasn't paying attention. Does this help? – Joseph R. May 8 '14 at 22:39
  • @xavierm02 Please don't forget to mark the answer 'Accepted' if it helped solve your problem. – Joseph R. May 9 '14 at 0:02
  • 1
    I will :) I'm just making sure it works first. And since the program isn't as simple as I made it look, it's taking time :) – xavierm02 May 9 '14 at 0:03

Given your use case, there's no point in starting to run the decryption until the key is fully generated, so you don't need to launch the decrypt processes until get_key has finished. Therefore a pipe has no advantage, you might as well store the output of get_key somewhere and use it afterwards.

Storing the output in a variable is the easiest way. However, since this is binary data that can contain null bytes, this only works in zsh, not in other shells. If you're worried about security, don't be: an attacker who can observe the content of the variable can also run get_key and watch its output.

for file in $FILES; do
  print -rn -- $key | decrypt $file

In other shells, you can use a temporary file. Be sure to make it readable only by you. If the temporary file is on an on-disk filesystem, then there is a small risk that the key could be leaked if the server's hard disk was stolen at the wrong time. If the file is on an in-memory filesystem, there is no such risk.

key_file=$(umask 077; mktemp)
get_key >"$key_file"
for file; do
  decrypt "$file" <"$key_file"
rm "$key_file"

If you don't want to use a temporary file and don't have zsh, you can use another language such as Perl or Python.

perl -e '
    $key = `get_key`;
    foreach (@ARGV) {
        open KEY, "|-", "decrypt", $_ or die $!;
        print KEY $key or die $!;
        close KEY or die $!;

If you have no better language than a POSIX shell or ksh or bash, and can't use a temporary file, then you'll need to fall back to piping into tee (or do some hairy encoding and decoding). To cope with the variable number of outputs, you can create one fifo per output, or build and eval a string containing the necessary <(…) (beware of the tricky quoting).

  • get_key prompts for a password so he won't get anything. And I'm not trying to protect data from someone having a virus on my computer or access to it while it's on. I'm trying to protect it from someone who would try to recover the data from the computer while off. And that someone wouldn't care what permissions your file has or where it was written. I did not know about that feature of ksh so thank you for that. But I still like the idea of never having the whole key written linearly in memory so I'll do it Joseph's way. +1 though :) – xavierm02 May 9 '14 at 0:36
  • 1
    @xavierm02 Warning: your security model is flawed. If the key is in the memory of get_key, or of decrypt, or in a pipe, it's still in memory! Putting it in the memory of zsh or perl doesn't make things worse. To counter someone who would steal the disk, as I indicate, make sure that the temporary file is on an in-memory filesystem. (An encrypted filesystem would also do fine.) – Gilles 'SO- stop being evil' May 9 '14 at 0:40
  • It's not. get_key asks for a password, calls a C program (xor) with via stdin (but the password is in memory). The C program returns the xor of the key and the keyfile it reads (and I don't think he even has all the keyfile in memory). Which is piped to cryptsetup. In short decrypt device means promt_password | xor keyfile | cryptsetup luksOpen -d - device. I don't think it will ever be all in memory, or at least not in the part of the process I control. – xavierm02 May 9 '14 at 1:32
  • 1
    @xavierm02 No, the key is quite obviously in the memory of the C program, since it's producing the key as output. Where else did you think the key was, if it wasn't in memory? Oh, and also, ouch! Xor is not a good way of masking a key with a password. Since you're using cryptsetup, use its key file feature. You're falling into the trap of rolling your own cryptography and doing a much worse job than the standard tools. – Gilles 'SO- stop being evil' May 9 '14 at 1:45
  • 1
    @xavierm02 This is too long to explain in a comment, but in a nutshell: xor requires a password that's as long as the key, and doesn't spread entropy well because the password isn't uniformly random. You should use a key derivation function, with key stretching on the password. – Gilles 'SO- stop being evil' May 9 '14 at 15:52

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.