Shh... Can You Split a Secret?

2

1

In Applied Cryptography by Bruce Schneier (which I have been reading quite a lot recently), a protocol for splitting secrets is discussed. Here is a brief description:

  1. Trent generates a random byte string, R, the same length as the message, M.
  2. Trent XORS M with R to make S.
  3. He gives R to Alice and S to Bob.

Your task is to, given an input, split the input into two output files or print the split secret to STDOUT. One output/part of output should contain the random string; the other should contain the original input XOR'd with the random string. Input and output may be to/from files or to/from STDIN/STDOUT. Outputting to STDERR is also allowed.
There are a few restrictions, however:

  1. Your program must take 1 input (1 input filename & 2 outputs if doing file I/O), and output the random string and the original string XOR'd with that random string into the other.
  2. Your program must be cryptographically secure. All random number generators must be cryptographically secure. For example, /dev/random is fine, but the Mersenne Twister (usually randint(number,number) is not. Any random number generator must be explicitly cryptographically secure.
    • If you want to know anything more about what "cryptographically secure" means, check here.
  3. Standard rules and loopholes apply.

This is , so the code with the fewest bytes will win.
May the best coder prosper...

ckjbgames

Posted 2017-03-23T21:41:20.640

Reputation: 1 287

6-1 for the cryptographically secure part. It doesn't add much to the challenge, other than making answers work around that restriction. It's not harder, just another step. – Rɪᴋᴇʀ – 2017-03-23T21:51:38.643

@Riker I felt like that adds to the challenge, personally, but I hear you. – ckjbgames – 2017-03-23T21:52:44.207

This is similar, but this isn't necessarily alphanumeric. – ckjbgames – 2017-03-23T21:54:04.550

"random string" String of bits, bytes, or printable ASCII chars? – ETHproductions – 2017-03-23T22:01:41.467

@ETHproductions If you aren't doing file I/O, these aren't needed. – ckjbgames – 2017-03-23T22:07:37.500

@ETHproductions Bytes – ckjbgames – 2017-03-23T22:07:42.510

Also, a thank you to whoever starred this question. – ckjbgames – 2017-03-23T22:10:39.070

@ETHproductions You're welcome :) – ckjbgames – 2017-03-23T22:12:39.097

Is XORing done bitwise for each byte? Can we assume any character-to-bytes encoding? – Luis Mendo – 2017-03-23T22:22:09.110

Can we take input and output as arrays of bytes, rather than strings? – ETHproductions – 2017-03-23T22:28:56.120

@LuisMendo It is done for each byte, and you can assume any encoding that actually exists. – ckjbgames – 2017-03-23T22:29:51.277

@ETHproductions Yes. I actually encourage that, in fact. – ckjbgames – 2017-03-23T22:30:11.650

Is I/O in hexadecimal acceptable? – Dennis – 2017-03-24T16:56:47.277

Answers

3

Bash + coreutils + openssl, 91 bytes

0000000: 63 3d 22 6f 70 65 6e 73 73 6c 20 65 6e 63 20 2d  c="openssl enc -
0000010: 61 65 73 2d 31 32 38 2d 63 74 72 20 2d 4b 20 24  aes-128-ctr -K $
0000020: 28 78 78 64 20 2d 70 73 20 2d 6c 20 31 36 20 2f  (xxd -ps -l 16 /
0000030: 64 65 76 2f 72 61 6e 64 6f 6d 29 20 2d 69 76 20  dev/random) -iv
0000040: 30 22 0a 24 63 3c 24 31 0a 74 72 20 01 2d ff 20  0".$c<$1.tr .-.
0000050: 5c 30 3c 24 31 7c 24 63 3e 26 32                 \0<$1|$c>&2

Takes a filename as argument and splits the secret to STDOUT and STDERR. Input and output are in raw binary format.

Sample run

$ cat input.txt
Bruce
$ bash split input.txt 2> >(xxd -ps >& 2) | xxd -ps
d5725c26aa3b
97002945cf31
$ printf %02x $[0xd5725c26aa3b ^ 0x97002945cf31] | xxd -r -ps
Bruce

Dennis

Posted 2017-03-23T21:41:20.640

Reputation: 196 637

2

JavaScript (ES6), 77 76 bytes

let f =
M=>[R=crypto.getRandomValues(new Uint8Array(M.length)),M.map((c,i)=>c^R[i])]

let g = m => console.log(f([...m].map(c=>c.charCodeAt())).map(x=>`[${x.join(", ")}]`).join(",\n"))
g("Secret message")
g("\0\0\0\0\0\0\0\0")

I think this is what's being asked for. It takes in an array of bytes and outputs [random bytes, XORed message]. I'm assuming that crypto.getRandomValues is cryptographically secure (else I don't know why it exists), and that Math.random isn't. Otherwise I could save 28 bytes.

ETHproductions

Posted 2017-03-23T21:41:20.640

Reputation: 47 880

1This is the kind of answer I wanted! – ckjbgames – 2017-03-23T22:36:26.350

2

Haskell, 178 Bytes

import System.Entropy
import qualified Data.ByteString as B
import Data.Bits
main|f<-B.init=do b<-B.getLine;r<-getEntropy.B.length$f b;B.putStrLn.pack.B.zipWith xor r$f b;print r

Unfortunately, I can't quite think of a way to do this without three big imports.

More readable version:

main=do b<-B.getLine
        r<-getEntropy . B.length $ B.init b
        B.putStrLn . pack . B.zipWith xor r $ f b
        print r

Basically, it reads a line from stdin, makes a random number with that length and then prints the xor'd version and the random number

Generic Display Name

Posted 2017-03-23T21:41:20.640

Reputation: 365

1

Python 3, 85 bytes

import os
s=input()
k=os.urandom(len(s))
print(list(k),[j^ord(i)for i,j in zip(k,s)])

The only part that might need explaining is the list comprehension ([j^ord...])

It combines the input with the random key (zip([1,2,3],[4,5,6])==[(1,4),(2,5),(3,6)]) and xors them together.

internet_user

Posted 2017-03-23T21:41:20.640

Reputation: 314

1

Ruby, 88 76 bytes

Edit: I guess the outputs don't have to be strings strings?

m=gets.bytes
p r=`head -c#{m.size}</dev/random`.bytes,m.zip(r).map{|a,b|a^b}

daniero

Posted 2017-03-23T21:41:20.640

Reputation: 17 193

0

Java, 292 bytes

Not sure if 100% correct

enum e{;public static void main(String[]a){java.security.SecureRandom r=new java.security.SecureRandom();byte[]b=a[0].getBytes(),c=new byte[b.length],d=new byte[c.length];int i=-1;r.nextBytes(c);while(++i<b.length)d[i]=(byte)(b[i]^c[i]);System.out.println(new String(c)+"\n"+new String(d));}}

Takes the input as first argument, outputs key and XOR'ed string to STDOUT separated by newlines.

Ungolfed with comments:

enum e {
    ;

    public static void main(String[] a) {
        java.security.SecureRandom r = new java.security.SecureRandom();            // Secure random
        byte[] b = a[0].getBytes(), c = new byte[b.length], d = new byte[c.length]; // 3 arrays
        int i = -1;                                                                 // Index
        r.nextBytes(c);                                                             // Key
        while (++i < b.length) d[i] = (byte) (b[i] ^ c[i]);                         // XOR the input with key
        System.out.println(new String(c) + "\n" + new String(d));                   // Output key and XORed string
    }
}

cookie

Posted 2017-03-23T21:41:20.640

Reputation: 271

This is a perfectly acceptable answer. – ckjbgames – 2017-03-26T23:49:11.410

You could drop the java.security. as any modern IDE can auto-import that unambiguously. – Mark Jeronimus – 2017-09-28T14:49:21.667