I want to know if AFsplit
(random_data_input, stripes, digestmod=sha)
output is indistinguishable from random data.
The attacker only has access to AFsplit
output data.
EDIT: This question is too vague as the answer depends on the randomness hypothesis taken about random_input_data
. Take care of it reading the proposed answers.
The purpose is to use this function in a deniable encryption implementation.
About AFsplit: AFsplit provides a security against forensic attacks on disk bad blocks. AFsplit splits data among several disk blocks so that if a block is put in reserved "bad block" area, it doesn't contain a complete sensitive information (particularly, a revoked key slot). LUKS uses AFsplit to store the key slots.
Note: I'm not speaking of LUKS itself that is, of course, a plain header. I just want to focus on this particular function.
Below is AFsplit Python implementation:
import sha, string, math, struct
from Crypto.Util.randpool import RandomPool
from Crypto.Cipher import XOR
def _xor(a, b):
"""Internal function to performs XOR on two strings a and b"""
xor = XOR.new(a)
return xor.encrypt(b)
def _diffuse(block, size, digest):
"""Internal function to diffuse information inside a buffer"""
# Compute the number of full blocks, and the size of the leftover block
full_blocks = int(math.floor(float(len(block)) / float(digest.digest_size)))
padding = len(block) % digest.digest_size
# hash the full blocks
ret = ""
for i in range(0, full_blocks):
hash = digest.new()
hash.update(struct.pack(">I", i))
hash.update(block[i*digest.digest_size:(i+1)*digest.digest_size])
ret += hash.digest()
# Hash the remaining data
if padding > 0:
hash = digest.new()
hash.update(struct.pack(">I", full_blocks))
hash.update(block[full_blocks * digest.digest_size:])
ret += hash.digest()[:padding]
return ret
def AFSplit(data, stripes, digestmod=sha):
"""AF-Split data using digestmod. Returned data size will be len(data) * stripes"""
blockSize = len(data)
rand = RandomPool()
bufblock = "\x00" * blockSize
ret = ""
for i in range(0, stripes-1):
# Get some random data
rand.randomize()
rand.stir()
r = rand.get_bytes(blockSize)
if rand.entropy < 0:
print "Warning: RandomPool entropy dropped below 0"
ret += r
bufblock = _xor(r, bufblock)
bufblock = _diffuse(bufblock, blockSize, digestmod)
rand.add_event(bufblock)
ret += _xor(bufblock, data)
return ret