Anti-forensic, safe storage of private keys
In any modern application, especially on
Client/Server nTier architecture as our little mORMot offers, we
often have to persist some private keys in a safe way.
Problem with such keys is that they consist in small amount of bytes (typically 16 or 32 bytes), easy to be left somewhere in disk or memory.
Given the abilities of recent forensic data recovery methods, data can't be destroyed on magnetic or flash storage media reliably.
We have just added to our SynCrypto OpenSource library
the Anti-forensic Information Splitter algorithm, as proposed in
TKS1, and implemented in the LUKS
LUKS is the de-facto standard of platform-independent standard on-disk format for use in various tools.
Storing any encrypted master key on disk, must take extra precaution, since data is not guaranteed to be ever erased.
- Hard disk have a long long memory. Even if you think data is gone, even if you have overwritten the whole disk with zeros, even if you invoked the security erase SATA command of your hard disk, data can be easily recovered, if not special care is taken to destroy it properly. Bad block remapping of modern firmwares supports data safety but weakens the opposite, data destruction.
- Modern SSD controllers are also affected by this issue, and are now so complex that even the TRIM command may leave some traces of the previously stored data.
- Some bytes may be stored on disk whereas they were supposed to stay in RAM, e.g. when the OS starts paging its memory, or when you put your computer in hibernate mode.
This Anti-Forensic Splitter algorithm supports secure data
destruction crucial for secure on-disk key management.
The key idea is to bloat information and therefor improving the chance of destroying a single bit of it.
The information is bloated in such a way, that a single missing bit causes the original information become unrecoverable.
The TKS1 theory is presented as such:
An easy approach is to create the inter-dependency for a data set S, S = s1, s2, . . . sn, is by generating s1 . . . sn−1 random data items and computing sn so that s1 X s2 X s3 X . . .X sn = D (X denotes the XOR operation).
The reconstruction is done by carring out the left-side of the equation, XOR-ing all data items together.
If one item s# is missing, D can’t be reconstructed, since an arbitrary s# effects the entire D.
This scheme can be enhanced to include diffusion of information, so that the k-th bit of an arbitrary si does not only affect the k-th bit of D but the entire D.
To achieve this diffusion, we insert a diffusion element in the chain of XORs.
A crytographic hash function can be used as such element, but since it might not output sufficiently large data, it will be processed a few times with an increasing number, similar to an initial vector, prepended to the complete dataset to produce enough data. As a hash function is usually required to be non-invertible, we can not choose it’s output. Therefore, the last diffusion will be omitted. This will degrade security slightly, so when computing destruction probabilities the last element shall never be taken into account.
Our SynCrypto implementation follows this algorithm, and uses SHA-256 as diffusion element (whereas LUKS used SHA-1).
The TAESPRNG class now offers those two new methods:
function AFSplit(const Buffer; BufferBytes, StripesCount: integer): RawByteString;
class function AFUnsplit(const Split: RawByteString; out Buffer; BufferBytes: integer): boolean;