/******************************************************************************* * Copyright (C) 2015 Connor Lanigan (email: dev@connorlanigan.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package de.norvos.utils; import java.math.BigInteger; import java.net.NetworkInterface; import java.net.SocketException; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Enumeration; /** * Provides various utility methods related to random data. * * @author Connor Lanigan */ public class RandomUtils { static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static SecureRandom random = new SecureRandom(); /** * Generates an install ID with a maximum of 14bit. The number is based on * the SHA-1 hash of the first MAC adress in the system. If no such adress * is found, a random number is chosen.<br> * <br> * Taken from * {@link org.whispersystems.textsecure.api.TextSecureAccountManager#verifyAccount * TextSecureAccountManager.verifyAccount()}, which uses this value:<br> * "A random 14-bit number that identifies this TextSecure install. This * value should remain consistent across registrations for the same install, * but probabilistically differ across registrations for separate installs." * * @return a random number with a maximum of 14 bit; * @throws SocketException * if an I/O-error occurs while getting the system's MAC address * @throws NoSuchAlgorithmException * if the SHA-1 hash algorithm cannot be found */ public static int generateInstallId() { try { final MessageDigest digest = MessageDigest.getInstance("SHA-1"); final byte[] hashedMac = digest.digest(getFirstMACAdress()); return limitInt(new BigInteger(hashedMac).intValue(), 14); } catch (final Exception e) { final int size = (int) Math.pow(2, 14 + 1); return random.nextInt(size); } } /** * Returns the first MAC adress that is found in the system. * * @return MAC adress * @throws SocketException * if an I/O error occurs. */ private static byte[] getFirstMACAdress() throws SocketException { final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); while (networkInterfaces.hasMoreElements()) { final NetworkInterface network = networkInterfaces.nextElement(); final byte[] bmac = network.getHardwareAddress(); if (bmac != null) { return bmac; } } throw new SocketException("No network interfaces with a MAC adress found."); } /** * Returns the first <code>bitlength</code> bits of the given int. * * @param value * the int to shorten * @param bitlength * the amount of bits to return * @return the <code>bitlength</code> most significant bits of the value */ private static int limitInt(final int value, final int bitlength) { return Integer.parseInt(Integer.toBinaryString(value).substring(0, bitlength), 2); } /** * Generates a random alphanumerical String of the given length. The used * characters are:<br> * <br> * 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ * * @param len * length of the String to generate * @return the generated random String */ public static String randomAlphanumerical(final int len) { final StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) { sb.append(AB.charAt(random.nextInt(AB.length()))); } return sb.toString(); } /** * Generates a random String containing ASCII characters. Every ASCII * character can appear in the String, even non-printable ones and all * others. * * @param size * number of ASCII characters to generate * @return the generated random String */ public static String randomASCII(final int size) { final byte[] array = new byte[size]; random.nextBytes(array); return new String(array, StandardCharsets.US_ASCII); } }