CryptoHelper.java

  1package eu.siacs.conversations.utils;
  2
  3import java.security.SecureRandom;
  4import java.text.Normalizer;
  5import java.util.Arrays;
  6import java.util.Collection;
  7import java.util.Iterator;
  8import java.util.LinkedHashSet;
  9import java.util.List;
 10
 11import eu.siacs.conversations.Config;
 12
 13public final class CryptoHelper {
 14	public static final String FILETRANSFER = "?FILETRANSFERv1:";
 15	private final static char[] hexArray = "0123456789abcdef".toCharArray();
 16	private final static char[] vowels = "aeiou".toCharArray();
 17	private final static char[] consonants = "bcdfghjklmnpqrstvwxyz".toCharArray();
 18	final public static byte[] ONE = new byte[] { 0, 0, 0, 1 };
 19
 20	public static String bytesToHex(byte[] bytes) {
 21		char[] hexChars = new char[bytes.length * 2];
 22		for (int j = 0; j < bytes.length; j++) {
 23			int v = bytes[j] & 0xFF;
 24			hexChars[j * 2] = hexArray[v >>> 4];
 25			hexChars[j * 2 + 1] = hexArray[v & 0x0F];
 26		}
 27		return new String(hexChars);
 28	}
 29
 30	public static byte[] hexToBytes(String hexString) {
 31		int len = hexString.length();
 32		byte[] array = new byte[len / 2];
 33		for (int i = 0; i < len; i += 2) {
 34			array[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
 35					.digit(hexString.charAt(i + 1), 16));
 36		}
 37		return array;
 38	}
 39
 40	public static String hexToString(final String hexString) {
 41		return new String(hexToBytes(hexString));
 42	}
 43
 44	public static byte[] concatenateByteArrays(byte[] a, byte[] b) {
 45		byte[] result = new byte[a.length + b.length];
 46		System.arraycopy(a, 0, result, 0, a.length);
 47		System.arraycopy(b, 0, result, a.length, b.length);
 48		return result;
 49	}
 50
 51	public static String randomMucName(SecureRandom random) {
 52		return randomWord(3, random) + "." + randomWord(7, random);
 53	}
 54
 55	private static String randomWord(int lenght, SecureRandom random) {
 56		StringBuilder builder = new StringBuilder(lenght);
 57		for (int i = 0; i < lenght; ++i) {
 58			if (i % 2 == 0) {
 59				builder.append(consonants[random.nextInt(consonants.length)]);
 60			} else {
 61				builder.append(vowels[random.nextInt(vowels.length)]);
 62			}
 63		}
 64		return builder.toString();
 65	}
 66
 67	/**
 68	 * Escapes usernames or passwords for SASL.
 69	 */
 70	public static String saslEscape(final String s) {
 71		final StringBuilder sb = new StringBuilder((int) (s.length() * 1.1));
 72		for (int i = 0; i < s.length(); i++) {
 73			char c = s.charAt(i);
 74			switch (c) {
 75				case ',':
 76					sb.append("=2C");
 77					break;
 78				case '=':
 79					sb.append("=3D");
 80					break;
 81				default:
 82					sb.append(c);
 83					break;
 84			}
 85		}
 86		return sb.toString();
 87	}
 88
 89	public static String saslPrep(final String s) {
 90		return Normalizer.normalize(s, Normalizer.Form.NFKC);
 91	}
 92
 93	public static String prettifyFingerprint(String fingerprint) {
 94		if (fingerprint==null) {
 95			return "";
 96		} else if (fingerprint.length() < 40) {
 97			return fingerprint;
 98		}
 99		StringBuilder builder = new StringBuilder(fingerprint.replaceAll("\\s",""));
100		for(int i=8;i<builder.length();i+=9) {
101			builder.insert(i, ' ');
102		}
103		return builder.toString();
104	}
105
106	public static String[] getOrderedCipherSuites(final String[] platformSupportedCipherSuites) {
107		final Collection<String> cipherSuites = new LinkedHashSet<>(Arrays.asList(Config.ENABLED_CIPHERS));
108		final List<String> platformCiphers = Arrays.asList(platformSupportedCipherSuites);
109		cipherSuites.retainAll(platformCiphers);
110		cipherSuites.addAll(platformCiphers);
111		filterWeakCipherSuites(cipherSuites);
112		return cipherSuites.toArray(new String[cipherSuites.size()]);
113	}
114
115	private static void filterWeakCipherSuites(final Collection<String> cipherSuites) {
116		final Iterator<String> it = cipherSuites.iterator();
117		while (it.hasNext()) {
118			String cipherName = it.next();
119			// remove all ciphers with no or very weak encryption or no authentication
120			for (String weakCipherPattern : Config.WEAK_CIPHER_PATTERNS) {
121				if (cipherName.contains(weakCipherPattern)) {
122					it.remove();
123					break;
124				}
125			}
126		}
127	}
128}