java - Secure non-repeating Random alphanumeric URL slug -
i'm able achieve non-repeating random alphanumeric url slug part base58, this,
private static final char[] base58_chars = "123456789abcdefghjklmnpqrstuvwxyzabcdefghijkmnopqrstuvwxyz".tochararray(); private static final int length = base58_chars.length; public static string genslug(long priimarykeyid) { char[] buffer = new char[20]; int index = 0; { int = (int) (priimarykeyid % length); buffer[index++] = base58_chars[i]; priimarykeyid = priimarykeyid / length; } while (priimarykeyid > 0); return new string(buffer, 0, index); }
but how achieve secure-randomness it?
if
hashing.sha256().hashstring(genslug(priimarykeyid), standardcharsets.utf_8).tostring();
the slug becomes 64 characters , that's long (expecting same length genslug, between 1 , 12 chars long)..
you truncate output of hash function , still appear random, possibility of hash collision rise. since constraint maximum output of 12 characters, means have truncate hash output 70 bits (12/8 * log(256)/log(58)
). due birthday paradox, collision after 270/2 such hashes.
since need guaranteed uniqueness, can use pseudo-random permutation (prp) transform priimarykeyid
random token. block cipher such prp. since maximum size of block size 70, can safely use triple des use case. has block size of 64 bit size of long
.
example (not thoroughly tested):
private static final char[] base58_chars = "123456789abcdefghjklmnpqrstuvwxyzabcdefghijkmnopqrstuvwxyz".tochararray(); private static final int length = base58_chars.length; private static final biginteger length_bi = biginteger.valueof(length); // todo: change key random! private static final byte[] key = new byte {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8}; public static string genslug(long priimarykeyid) { bytebuffer bb = bytebuffer.allocate(8); bb.putlong(priimarykeyid); cipher cipher = cipher.getinstance("desede/ecb/nopadding"); cipher.init(cipher.encrypt_mode, new secretkeyspec(key, "desede")); byte[] encrypted = cipher.dofinal(bb.array()); biginteger bi = new biginteger(1, encrypted); char[] buffer = new char[20]; int index = 0; { biginteger = bi.mod(length_bi); buffer[index++] = base58_chars[i.intvalue()]; bi = bi.divide(length_bi); } while (bi.compareto(biginteger.zero) == 1); return new string(buffer, 0, index); }
the main thing need keep key safe.
Comments
Post a Comment