Skip to content

glk/mmcrypt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mmcrypt -- password-based key derivation function.

Interface supports arbitrary input parameters and arbitrary length
output:
 - mmcrypt_absorb(data) -- input data, may be called arbitrary number of
   times with arguments like salt, password, service tag, secret salt,
   etc;
 - mmcrypt_stretch(iter, m, s) -- key stretch procedure;
 - mmcrypt_squeeze() => key -- produce cryptographic key based on
   current state, may be called arbitrary number of times.

Two primitives are used: Duplex construction on top of 512-bit Keccak
(as in SHA-3) and Galois field multiplication.

Pseudo-code:
sm, s1, s2 - Duplex constructions. s.Duplexing is stateful operation.

MSB(A, N) -- get N most significant bits of A
LSB(A, N) -- get N least significant bits of A
LSB_WRAP(A, i) -- LSB(A, floor(log2(i))) + i - (2 ** floor(log2(i)))

mmcrypt_abosrb(data) --
	sm.Duplexing(data)

mmcrypt_squeeze() --
	return sm.Duplexing(NULL)

mmcrypt_stretch(iter, c, s) --
	/* Create 64-bit big-endian array with 8 elements */
	sm.Duplexing((be64){MMCRYPT_FRATE, iter, c, s, 0, 0, 0, 0})
	for i 0 to iter - 1
		mmcrypt_stretch'(c, s)

mmcrypt_stretch'(c, s) --
	fcount = 0
	s1.Duplexing(sm.Duplexing(NULL))
	s2.Duplexing(sm.Duplexing(NULL))
	/* Choose start positions k[i], should not be 0 */
	for i in 0 to s - 1
		k[i] = MSB(sm.Duplexing(NULL), c * 2) | 1;
	/* Create T1 and T2 tables. */
	/* Ti[[x]] := Ti[x / s][x % s] */
	T1[[0]] = s1.Duplexing(NULL)
	T2[[0]] = s2.Duplexing(NULL)
	for i in 1 to 2^c * s - 1
		j = LSB_WRAP(T2[[i - 1]], i)
		T1[[i]] = s1.Duplexing(T2[[j]])
		j = LSB_WRAP(T1[[i - 1]], i)
		T2[[i]] = s2.Duplexing(T1[[j]])
	/* Traverse all (T1[k1][i], T2[k2][i]) pairs. */
	/* (T1[0], T2[0]) pair is skipped. */
	k0 = k[0]
	do
		for i in 0 to s - 1
			/* Multiplication in GF(2^(c * 2)) */
			k[i] = k[i] (*) alpha
			k1 = MSB(k[i], c)
			k2 = LSB(k[i], c)
			if MSB(T1[k1][i], c) != MSB(T2[k2][i], c)
				feedback ^= T1[k1][i] ^ T2[k2][i]
			/* Multiplication in GF(2^512) */
			feedback = feedback (*) alpha
			if MSB(feedback) == 1
				tmp = (T1[k1][i] ^ T2[k2][i]) (*) alpha
				T1[k1][(i + 1) % s] ^= tmp
				T2[k2][(i + 1) % s] ^= tmp
				swap T1[k1][(i + 1) % s], T2[k2][(i + 1) % s]
			if ++fcount % MMCRYPT_FRATE == 0
				feedback = sm.Duplexing(feedback)
	while k[0] != k0
	sm.Duplexing(feedback)
	swap s1, s2


Notes:

Always perform the same non data dependent sequence of operations, but
start at position that depends on user provided data.

Make memory access pattern unpredictable for cache hierarchy in order to
achieve higher memory pressure.

Duplex construction is equivalent to sponge construction (see
Duplexing-sponge lemma in "Duplexing the sponge: single-pass
authenticated encryption and other applications") with padded inputs.
Sponge is SHA-3 in our case.

Keccak authors suggest Sponge(password || {0}n) with large n as a
password-based key derivation function (see "Cryptographic sponge
functions").

The problem may be reformulated as meet-in-the-middle attack:
Find A = {(i, j)} such as MSB(H1(i), c) = MSB(H2(j), c).
where H(i) requires i Keccak-f operations for known inputs. E.g. it
gives us 2^(c-1) operations on average for H(i) calculation.

About

mmcrypt -- password-based key derivation function

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published