public enum TrackerName {
	APP_TRACKER, GLOBAL_TRACKER, ECOMMERCE_TRACKER,
} public class DebugActivity extends AppCompatActivity {

	private ListView keysafe_list;
	private ArrayList<String> keysafe = new ArrayList<String>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_debug);
		Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
		setSupportActionBar(toolbar);
		getSupportActionBar().setDisplayHomeAsUpEnabled(true);
		getSupportActionBar().setHomeButtonEnabled(true);
		this.setTitle("Debug Activity");

		keysafe_list = (ListView) this.findViewById(R.id.keysafe_list);

		update();
		keysafe_list.setOnItemLongClickListener(new OnItemLongClickListener() {

			public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int pos, long id) {
				KeySafe.getInstance(this).remove(keysafe.get(pos).split("=")[0]);
				KeySafe.getInstance(this).save();
				Toast.makeText(DebugActivity.this, "Removed from Keysafe", Toast.LENGTH_SHORT).show();
				update();
				return true;
			}
		});

	}

	public void update() {
		HashMap<String, KeyEntity> map = KeySafe.getInstance(this).getMap();
		keysafe = new ArrayList<String>();
		if (map != null)
			for (Map.Entry<String, KeyEntity> entry : map.entrySet()) {
				keysafe.add(entry.getKey());
			}

		ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, keysafe);
		keysafe_list.setAdapter(arrayAdapter);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			NavUtils.navigateUpFromSameTask(this);
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

} public class NewSMSContactActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {

	private ListView contactList;
	public static ContactNameMap contactNameMap;
	private ProfilePictureCache fb_img;
	public ArrayList<ContactModel> contacts;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_new_contact);

		Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
		setSupportActionBar(toolbar);
		getSupportActionBar().setDisplayHomeAsUpEnabled(true);
		getSupportActionBar().setHomeButtonEnabled(true);

		contactNameMap = new ContactNameMap(this);

		contactList = (ListView) this.findViewById(R.id.listview);

		TextView padding = new TextView(this);
		padding.setHeight(10);
		contactList.addHeaderView(padding);
		contactList.setHeaderDividersEnabled(false);
		contactList.addFooterView(padding, null, false);
		contactList.setFooterDividersEnabled(false);

		updateContacts();
		contactList.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
				if (contacts == null) {
					updateContacts();
				}
				openMessageActivity(NewSMSContactActivity.this, arg2 - 1);
			}

		});

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.new_contact, menu);
		SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
		MenuItem searchMenuItem = menu.findItem(R.id.search);
		SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);

		searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
		searchView.setSubmitButtonEnabled(true);
		searchView.setOnQueryTextListener(this);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			finish();
			return true;
		case R.id.action_message_encrypted: {
			return true;
		}
		}

		return super.onOptionsItemSelected(item);
	}

	public void openMessageActivity(Activity activity, int arg2) {
		if (arg2 < 0)
			return;
		Intent smsIntent = new Intent(activity, MessageOverview.class);
		ContactAdapter adapter = ((ContactAdapter) ((HeaderViewListAdapter) contactList.getAdapter())
				.getWrappedAdapter());
		smsIntent.putExtra("CONTACT_NUMBER", ((ContactModel) adapter.getItem(arg2)).getLastMessage());
		smsIntent.putExtra("CONTACT_NAME", ((ContactModel) (adapter.getItem(arg2))).getTitle());
		smsIntent.putExtra("CONTACT_ID", ((ContactModel) (adapter.getItem(arg2))).getThreadID());

		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		Bitmap temp = ((ContactModel) (adapter.getItem(arg2))).getPicture();
		if (temp != null) {
			temp.compress(Bitmap.CompressFormat.PNG, 100, stream);
			byte[] bytes = stream.toByteArray();

			smsIntent.putExtra("profilePicture", bytes);
		}
		try {
			KeyEntity key = KeySafe.getInstance(this).get(
					PhoneNumberUtils.formatNumber(contacts.get(arg2).getLastMessage()));
			if (key != null)
				smsIntent.putExtra("CONTACT_KEY", key);
		} catch (NullPointerException e) {
		}
		activity.startActivityForResult(smsIntent, 2);
	}

	public void updateContacts() {
		if (contacts == null)
			contacts = readSMSContacts(this);

		if (contactList != null && contactList.getAdapter() != null) {
			if (contacts.size() > 0 && contactList != null) {
				((ContactAdapter) ((HeaderViewListAdapter) contactList.getAdapter()).getWrappedAdapter()).refill(
						contacts, 0);
			}
		} else {
			if (contactList != null) {
				ContactAdapter arrayAdapter = new ContactAdapter(this, contacts, 0);
				contactList.setAdapter(arrayAdapter);
			}
		}
	}

	public ArrayList<ContactModel> readSMSContacts(Activity activity) {
		LinkedHashSet<ContactModel> smsList = new LinkedHashSet<ContactModel>();
		Cursor phones = activity.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
				null, null, null);
		while (phones.moveToNext()) {
			String name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
			String phoneNumber = phones.getString(phones.getColumnIndex(PhoneNumberUtils
					.formatNumber(ContactsContract.CommonDataKinds.Phone.NUMBER)));
			String photo = phones.getString(phones
					.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI));
			String primary = name;
			if (name == null)
				primary = phoneNumber;
			smsList.add(new ContactModel(fetchThumbnail(activity, photo != null ? Uri.parse(photo) : null), primary,
					phoneNumber, "", false));
		}
		phones.close();
		ArrayList<ContactModel> unsorted = new ArrayList<ContactModel>(smsList);
		Collections.sort(unsorted, new Comparator<ContactModel>() {
			@Override
			public int compare(ContactModel lhs, ContactModel rhs) {
				return lhs.getTitle().compareTo(rhs.getTitle());
			}
		});
		return unsorted;
	}

	public final Bitmap fetchThumbnail(Context context, Uri uri) {
		if (uri == null)
			return null;
		FileDescriptor fileDescriptor;
		try {
			fileDescriptor = context.getContentResolver().openAssetFileDescriptor(uri, "r").getFileDescriptor();
		} catch (FileNotFoundException e) {
			return null;
		}

		if (fileDescriptor != null) {
			return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, null);
		}
		return null;
	}

	@Override
	public boolean onQueryTextChange(String arg0) {
		((ContactAdapter) ((HeaderViewListAdapter) contactList.getAdapter()).getWrappedAdapter()).getFilter().filter(
				arg0);
		return true;
	}

	@Override
	public boolean onQueryTextSubmit(String arg0) {
		return true;
	}

} public class QuickPrefsActivity extends AppCompatActivity {

	public static int fragment;

	@Override
	protected void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_prefs);

		Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
		setSupportActionBar(toolbar);
		getSupportActionBar().setDisplayHomeAsUpEnabled(true);
		getSupportActionBar().setHomeButtonEnabled(true);
		fragment = 0;
		getFragmentManager().beginTransaction().replace(R.id.prefscontent, new MyPreferenceFragment()).commit();

	}

	@Override
	public void onBackPressed() {
		if (QuickPrefsActivity.fragment == 0) {
			super.onBackPressed();
		} else {
			getFragmentManager().beginTransaction().replace(R.id.prefscontent, new MyPreferenceFragment()).commit();
		}
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			if (QuickPrefsActivity.fragment == 0) {
				NavUtils.navigateUpFromSameTask(this);
				return true;
			} else {
				getFragmentManager().beginTransaction().replace(R.id.prefscontent, new MyPreferenceFragment()).commit();
				return true;
			}
		}
		return false;
	}







} public class SMSItem implements Comparable {
	public static final String ID = "_id";
	public static final String THREAD = "thread_id";
	public static final String ADDRESS = "address";
	public static final String PERSON = "person";
	public static final String DATE = "date";
	public static final String READ = "read";
	public static final String BODY = "body";
	public static final String SUBJECT = "subject";

	public static final String[] PHOTO_ID_PROJECTION = new String[] { ContactsContract.Contacts.PHOTO_ID };

	public static final String[] PHOTO_BITMAP_PROJECTION = new String[] { ContactsContract.CommonDataKinds.Photo.PHOTO };

	public String mAddress;
	public String mBody;
	public String mSubject;
	public long mID;
	public long mThreadID;
	public long mDate;
	public long mRead;
	public long mPerson;
	public Uri profilePicture;
	public int photoID;

	private static int mIdIdx;
	private static int mThreadIdx;
	private static int mAddrIdx;
	private static int mPersonIdx;
	private static int mDateIdx;
	private static int mReadIdx;
	private static int mBodyIdx;
	private static int mSubjectIdx;

	public SMSItem(Cursor cur) {
		mID = cur.getLong(mIdIdx);
		mThreadID = cur.getLong(mThreadIdx);
		mAddress = cur.getString(mAddrIdx);
		mPerson = cur.getLong(mPersonIdx);
		mDate = cur.getLong(mDateIdx);
		mRead = cur.getLong(mReadIdx);
		mBody = cur.getString(mBodyIdx);
		mSubject = cur.getString(mSubjectIdx);
	}

	public SMSItem() {

	}

	public String printArray(String[] sa) {
		String erg = "";
		for (String s : sa)
			erg += s + "; ";
		return erg;
	}

	public SMSItem(Cursor cur, boolean b) {
		mID = cur.getLong(mIdIdx);
		mAddress = cur.getString(cur.getColumnIndex(PhoneNumberUtils
				.formatNumber(ContactsContract.CommonDataKinds.Phone.NUMBER)));
		mPerson = cur.getLong(mPersonIdx);
	}

	public static void initIdx(Cursor cur) {
		mIdIdx = cur.getColumnIndex(ID);
		mThreadIdx = cur.getColumnIndex(THREAD);
		mAddrIdx = cur.getColumnIndex(ADDRESS);
		mPersonIdx = cur.getColumnIndex(PERSON);
		mDateIdx = cur.getColumnIndex(DATE);
		mReadIdx = cur.getColumnIndex(READ);
		mBodyIdx = cur.getColumnIndex(BODY);
		mSubjectIdx = cur.getColumnIndex(SUBJECT);
	}

	public String toString() {
		String ret = ID + ":" + String.valueOf(mID) + " " + THREAD + ":" + String.valueOf(mThreadID) + " " + ADDRESS
				+ ":" + mAddress + " " + PERSON + ":" + String.valueOf(mPerson) + " " + DATE + ":"
				+ String.valueOf(mDate) + " " + READ + ":" + String.valueOf(mRead) + " " + SUBJECT + ":" + mSubject
				+ " " + BODY + ":" + mBody;
		return ret;
	}

	@Override
	public int hashCode() {
		return Long.valueOf(mThreadID).hashCode();
	}

	@Override
	public boolean equals(Object o) {
		return Long.valueOf(mThreadID).equals(((SMSItem) o).mThreadID);
	}

	@Override
	public int compareTo(Object arg0) {
		return mAddress.compareTo(((SMSItem) (arg0)).mAddress);
	}

	public String getDate() {
		long cur = System.currentTimeMillis();
		String erg = "";
		if ((long) (cur / 86400000) == (long) (mDate / 86400000))
			erg = new SimpleDateFormat("HH:mm").format(mDate);
		else if (mDate >= cur - 518400000)
			erg = new SimpleDateFormat("EE").format(mDate);
		else
			erg = new SimpleDateFormat("dd. MMM").format(mDate);
		return erg;
	}

	public Uri getPhotoUri() {
		return profilePicture;
	}

	private Integer fetchThumbnailId(Context context) {

		final Uri uri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, Uri
				.encode(this.mAddress));
		final Cursor cursor = context.getContentResolver().query(uri, PHOTO_ID_PROJECTION, null, null,
				ContactsContract.Contacts.DISPLAY_NAME + " ASC");

		try {
			Integer thumbnailId = null;
			if (cursor.moveToFirst()) {
				thumbnailId = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID));
			}
			return thumbnailId;
		} finally {
			cursor.close();
		}

	}

	public final Bitmap fetchThumbnail(Context context) {
		Integer id = fetchThumbnailId(context);
		if (id == null)
			return null;
		final Uri uri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id);
		final Cursor cursor = context.getContentResolver().query(uri, PHOTO_BITMAP_PROJECTION, null, null, null);

		try {
			Bitmap thumbnail = null;
			if (cursor.moveToFirst()) {
				final byte[] thumbnailBytes = cursor.getBlob(0);
				if (thumbnailBytes != null) {
					thumbnail = BitmapFactory.decodeByteArray(thumbnailBytes, 0, thumbnailBytes.length);
				}
			}
			return thumbnail;
		} finally {
			cursor.close();
		}
	}

} public class KeySafe extends KeySafeAbstract {

	private static KeySafe instance;

	private KeySafe(Object activity, KeyEntity universal_key) {
		super(activity, universal_key);
	}

	public static KeySafe getInstance(Object activity) {
		if (instance == null) {
			try {
				instance = new KeySafe(activity, new KeyEntity(ScryptTool.hashUltraLow(pw((Activity) activity)
						.getBytes(), loadSalt(((Activity) activity))), 0L, (byte) (0xff)));
				instance.load();
			} catch (Exception e) {
				e.printStackTrace();
				saveSalt((Activity) activity, ScryptTool.generateSalt(32));
				try {
					instance = new KeySafe(activity, new KeyEntity(ScryptTool.hashUltraLow(pw((Activity) activity)
							.getBytes(), loadSalt(((Activity) activity))), 0L, (byte) (0xff)));
					instance.load();
				} catch (Exception e1) {
					e1.printStackTrace();
					instance = new KeySafe((Activity) activity, null);
					try {
						instance.load();
					} catch (Exception e2) {
						e2.printStackTrace();
					}
				}
			}

		}
		return instance;
	}

	private static String pw(Activity ac) {
		return Secure.getString(ac.getContentResolver(), Secure.ANDROID_ID);
	}

	@Override
	public File fileLocation() {
		return new File(((Activity) activity).getFilesDir(), "keysafe.dat");
	}

	public static boolean existsFile(Activity activity) {
		return new File(activity.getFilesDir(), "keysafe.dat").exists();
	}

	public void put(ExchangeInformation ei, boolean force) throws KeyAlreadyMappedException {
		if (map.containsKey(ei.getPhoneNumber()) && !force)
			throw new KeyAlreadyMappedException(ei.getPhoneNumber() + " already used in map.");
		map.put(ei.getPhoneNumber().replaceAll("\\s+", "").replace("\n", "").replace("\r", ""), ei.getKey());
	}

	public static byte[] loadSalt(Activity activity) throws StreamCorruptedException, FileNotFoundException,
			IOException {
		ObjectInputStream inputStream = null;
		byte[] erg = null;
		try {
			inputStream = new ObjectInputStream(new FileInputStream(new File(activity.getFilesDir(), "salt.dat")));
			erg = (byte[]) inputStream.readObject();
		} catch (ClassNotFoundException e) {
		} finally {
			try {
				if (inputStream != null)
					inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return erg;
	}

	public static void saveSalt(Activity activity, byte[] salt) {
		saveSalt(activity, salt, "salt.dat");
	}

	public static void saveSalt(Activity activity, byte[] salt, String file) {
		ObjectOutputStream outputStream = null;
		try {
			outputStream = new ObjectOutputStream(new FileOutputStream(new File(activity.getFilesDir(), file)));
			outputStream.writeObject(salt);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (outputStream != null)
					outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

} public final class PRNGFixes {

	private static final int VERSION_CODE_JELLY_BEAN = 16;
	private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
	private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL = getBuildFingerprintAndDeviceSerial();

	/** Hidden constructor to prevent instantiation. */
	private PRNGFixes() {
	}

	/**
	 * Applies all fixes.
	 * 
	 * @throws SecurityException
	 *             if a fix is needed but could not be applied.
	 */
	public static void apply() {
		applyOpenSSLFix();
		installLinuxPRNGSecureRandom();
	}

	/**
	 * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
	 * fix is not needed.
	 * 
	 * @throws SecurityException
	 *             if the fix is needed but could not be applied.
	 */
	private static void applyOpenSSLFix() throws SecurityException {
		if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN) || (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
			// No need to apply the fix
			return;
		}

		try {
			// Mix in the device- and invocation-specific seed.
			Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto").getMethod("RAND_seed", byte[].class)
					.invoke(null, generateSeed());

			// Mix output of Linux PRNG into OpenSSL's PRNG
			int bytesRead = (Integer) Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto").getMethod(
					"RAND_load_file", String.class, long.class).invoke(null, "/dev/urandom", 1024);
			if (bytesRead != 1024) {
				throw new IOException("Unexpected number of bytes read from Linux PRNG: " + bytesRead);
			}
		} catch (Exception e) {
			throw new SecurityException("Failed to seed OpenSSL PRNG", e);
		}
	}

	/**
	 * Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
	 * default. Does nothing if the implementation is already the default or if
	 * there is not need to install the implementation.
	 * 
	 * @throws SecurityException
	 *             if the fix is needed but could not be applied.
	 */
	private static void installLinuxPRNGSecureRandom() throws SecurityException {
		if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
			// No need to apply the fix
			return;
		}

		// Install a Linux PRNG-based SecureRandom implementation as the
		// default, if not yet installed.
		Provider[] secureRandomProviders = Security.getProviders("SecureRandom.SHA1PRNG");
		if ((secureRandomProviders == null) || (secureRandomProviders.length < 1)
				|| (!LinuxPRNGSecureRandomProvider.class.equals(secureRandomProviders[0].getClass()))) {
			Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
		}

		// Assert that new SecureRandom() and
		// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
		// by the Linux PRNG-based SecureRandom implementation.
		SecureRandom rng1 = new SecureRandom();
		if (!LinuxPRNGSecureRandomProvider.class.equals(rng1.getProvider().getClass())) {
			throw new SecurityException("new SecureRandom() backed by wrong Provider: " + rng1.getProvider().getClass());
		}

		SecureRandom rng2;
		try {
			rng2 = SecureRandom.getInstance("SHA1PRNG");
		} catch (NoSuchAlgorithmException e) {
			throw new SecurityException("SHA1PRNG not available", e);
		}
		if (!LinuxPRNGSecureRandomProvider.class.equals(rng2.getProvider().getClass())) {
			throw new SecurityException("SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong" + " Provider: "
					+ rng2.getProvider().getClass());
		}
	}

	/**
	 * {@code Provider} of {@code SecureRandom} engines which pass through all
	 * requests to the Linux PRNG.
	 */
	private static class LinuxPRNGSecureRandomProvider extends Provider {

		public LinuxPRNGSecureRandomProvider() {
			super("LinuxPRNG", 1.0, "A Linux-specific random number provider that uses" + " /dev/urandom");
			// Although /dev/urandom is not a SHA-1 PRNG, some apps
			// explicitly request a SHA1PRNG SecureRandom and we thus need to
			// prevent them from getting the default implementation whose output
			// may have low entropy.
			put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
			put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
		}
	}

	/**
	 * {@link SecureRandomSpi} which passes all requests to the Linux PRNG (
	 * {@code /dev/urandom}).
	 */
	public static class LinuxPRNGSecureRandom extends SecureRandomSpi {

		/*
		 * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
		 * are passed through to the Linux PRNG (/dev/urandom). Instances of
		 * this class seed themselves by mixing in the current time, PID, UID,
		 * build fingerprint, and hardware serial number (where available) into
		 * Linux PRNG.
		 * 
		 * Concurrency: Read requests to the underlying Linux PRNG are
		 * serialized (on sLock) to ensure that multiple threads do not get
		 * duplicated PRNG output.
		 */

		private static final File URANDOM_FILE = new File("/dev/urandom");

		private static final Object sLock = new Object();

		/**
		 * Input stream for reading from Linux PRNG or {@code null} if not yet
		 * opened.
		 * 
		 * @GuardedBy("sLock")
		 */
		private static DataInputStream sUrandomIn;

		/**
		 * Output stream for writing to Linux PRNG or {@code null} if not yet
		 * opened.
		 * 
		 * @GuardedBy("sLock")
		 */
		private static OutputStream sUrandomOut;

		/**
		 * Whether this engine instance has been seeded. This is needed because
		 * each instance needs to seed itself if the client does not explicitly
		 * seed it.
		 */
		private boolean mSeeded;

		@Override
		protected void engineSetSeed(byte[] bytes) {
			try {
				OutputStream out;
				synchronized (sLock) {
					out = getUrandomOutputStream();
				}
				out.write(bytes);
				out.flush();
			} catch (IOException e) {
				// On a small fraction of devices /dev/urandom is not writable.
				// Log and ignore.
				Log.w(PRNGFixes.class.getSimpleName(), "Failed to mix seed into " + URANDOM_FILE);
			} finally {
				mSeeded = true;
			}
		}

		@Override
		protected void engineNextBytes(byte[] bytes) {
			if (!mSeeded) {
				// Mix in the device- and invocation-specific seed.
				engineSetSeed(generateSeed());
			}

			try {
				DataInputStream in;
				synchronized (sLock) {
					in = getUrandomInputStream();
				}
				synchronized (in) {
					in.readFully(bytes);
				}
			} catch (IOException e) {
				throw new SecurityException("Failed to read from " + URANDOM_FILE, e);
			}
		}

		@Override
		protected byte[] engineGenerateSeed(int size) {
			byte[] seed = new byte[size];
			engineNextBytes(seed);
			return seed;
		}

		private DataInputStream getUrandomInputStream() {
			synchronized (sLock) {
				if (sUrandomIn == null) {
					// NOTE: Consider inserting a BufferedInputStream between
					// DataInputStream and FileInputStream if you need higher
					// PRNG output performance and can live with future PRNG
					// output being pulled into this process prematurely.
					try {
						sUrandomIn = new DataInputStream(new FileInputStream(URANDOM_FILE));
					} catch (IOException e) {
						throw new SecurityException("Failed to open " + URANDOM_FILE + " for reading", e);
					}
				}
				return sUrandomIn;
			}
		}

		private OutputStream getUrandomOutputStream() throws IOException {
			synchronized (sLock) {
				if (sUrandomOut == null) {
					sUrandomOut = new FileOutputStream(URANDOM_FILE);
				}
				return sUrandomOut;
			}
		}
	}

	/**
	 * Generates a device- and invocation-specific seed to be mixed into the
	 * Linux PRNG.
	 */
	private static byte[] generateSeed() {
		try {
			ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
			DataOutputStream seedBufferOut = new DataOutputStream(seedBuffer);
			seedBufferOut.writeLong(System.currentTimeMillis());
			seedBufferOut.writeLong(System.nanoTime());
			seedBufferOut.writeInt(Process.myPid());
			seedBufferOut.writeInt(Process.myUid());
			seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
			seedBufferOut.close();
			return seedBuffer.toByteArray();
		} catch (IOException e) {
			throw new SecurityException("Failed to generate seed", e);
		}
	}

	/**
	 * Gets the hardware serial number of this device.
	 * 
	 * @return serial number or {@code null} if not available.
	 */
	private static String getDeviceSerialNumber() {
		// We're using the Reflection API because Build.SERIAL is only available
		// since API Level 9 (Gingerbread, Android 2.3).
		try {
			return (String) Build.class.getField("SERIAL").get(null);
		} catch (Exception ignored) {
			return null;
		}
	}

	private static byte[] getBuildFingerprintAndDeviceSerial() {
		StringBuilder result = new StringBuilder();
		String fingerprint = Build.FINGERPRINT;
		if (fingerprint != null) {
			result.append(fingerprint);
		}
		String serial = getDeviceSerialNumber();
		if (serial != null) {
			result.append(serial);
		}
		try {
			return result.toString().getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("UTF-8 encoding not supported");
		}
	}
} public class ContactModel implements Parcelable {

	private Bitmap picture;
	private String title;
	private String last_message;
	private String date;
	private int encrypted;
	private boolean unread;
	private boolean online;
	private boolean mobile;
	private String fromMail;
	private String toMail;
	private long smsID = 0;
	private boolean mail;
	private String fromName;
	private boolean drawOnline = true;

	public ContactModel(Bitmap picture, String title, String last_message, String date, boolean unread) {
		super();
		this.picture = picture;
		this.title = title;
		this.last_message = last_message;
		this.date = date;
		this.unread = unread;
		encrypted = View.INVISIBLE;
	}

	public ContactModel(Bitmap picture, String title, String last_message, String date, boolean unread, boolean online,
			boolean mobile) {
		super();
		this.picture = picture;
		this.title = title;
		this.last_message = last_message;
		this.date = date;
		this.unread = unread;
		this.mobile = mobile;
		this.online = online;
		encrypted = View.INVISIBLE;
	}

	// MAIL
	public ContactModel(Bitmap picture, String title, String last_message, String date, boolean unread, String from,
			String to, String fromName) {
		super();
		this.picture = picture;
		this.title = title;
		this.last_message = last_message;
		this.date = date;
		this.unread = unread;
		this.fromMail = from;
		this.toMail = to;
		this.fromName = fromName != null ? fromName : "";
		this.mail = true;
		encrypted = View.INVISIBLE;
	}

	public ContactModel drawOnline(boolean b) {
		drawOnline = b;
		return this;
	}

	public boolean drawOnline() {
		return drawOnline;
	}

	public String getFromName() {
		return fromName;
	}

	public String getFromMail() {
		return fromMail;
	}

	public void setFromMail(String fromMail) {
		this.fromMail = fromMail;
	}

	public String getToMail() {
		return toMail;
	}

	public void setToMail(String toMail) {
		this.toMail = toMail;
	}

	public boolean isMail() {
		return mail;
	}

	public boolean isOnline() {
		return online;
	}

	public void setOnline(boolean online) {
		this.online = online;
	}

	public boolean isMobile() {
		return mobile;
	}

	public void setMobile(boolean mobile) {
		this.mobile = mobile;
	}

	public boolean isUnread() {
		return unread;
	}

	public void setUnread(boolean unread) {
		this.unread = unread;
	}

	public int getEncrypted() {
		return encrypted;
	}

	public void setEncrypted(int encrypted) {
		this.encrypted = encrypted;
	}

	public Bitmap getPicture() {
		return picture;
	}

	public String getTitle() {
		return title;
	}

	public String getLastMessage() {
		return last_message;
	}

	public String getDate() {
		return date;
	}

	public void setDate(String date) {
		this.date = date;
	}

	public void setLastMessage(String msg) {
		this.last_message = msg;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public void setPicture(Bitmap picture) {
		this.picture = picture;
	}

	public String toString() {
		return title;
	}

	public int describeContents() {
		return 0;
	}

	@Override
	public int hashCode() {
		return getTitle().hashCode() ^ getLastMessage().hashCode() ^ getDate().hashCode();
	}

	@Override
	public boolean equals(Object o) {
		return ((ContactModel) o).getTitle().equals(getTitle())
				&& ((ContactModel) o).getLastMessage().equals(getLastMessage())
				&& ((ContactModel) o).getDate().equals(getDate());
	}

	public void writeToParcel(Parcel dest, int parcelableFlags) {
		dest.writeString(title);
		dest.writeString(last_message);
		dest.writeString(date);
		dest.writeParcelable(picture, parcelableFlags);
	}

	public static final Creator<ContactModel> CREATOR = new Creator<ContactModel>() {
		public ContactModel createFromParcel(Parcel source) {
			return new ContactModel(source);
		}

		public ContactModel[] newArray(int size) {
			return new ContactModel[size];
		}
	};

	private ContactModel(Parcel source) {
		title = source.readString();
		last_message = source.readString();
		date = source.readString();
		picture = source.readParcelable(getClass().getClassLoader());
	}

	public void setThreadID(long id) {
		this.smsID = id;
	}

	public long getThreadID() {
		return smsID;
	}

} public class NavBarAdapter extends ArrayAdapter<NavItemModel> {

	private final Context context;
	private final ArrayList<NavItemModel> modelsArrayList;

	public NavBarAdapter(Context context, ArrayList<NavItemModel> modelsArrayList) {

		super(context, R.layout.nav_drawer_item, modelsArrayList);

		this.context = context;
		this.modelsArrayList = modelsArrayList;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

		View rowView = null;
		if (modelsArrayList.get(position).isHeader()) {
			rowView = inflater.inflate(R.layout.nav_drawer_header, parent, false);
			ImageView picture = (ImageView) rowView.findViewById(R.id.item_picture_profiles);
			TextView titleView = (TextView) rowView.findViewById(R.id.item_title);
			if (modelsArrayList.get(position).getProfilePicture() != null) {
				picture.setBackgroundColor(0x00000000);
				picture.setImageBitmap(modelsArrayList.get(position).getProfilePicture());
			}
			titleView.setText(modelsArrayList.get(position).getTitle());
			rowView.setEnabled(false);
			rowView.setOnClickListener(null);
		} else {

			if (!modelsArrayList.get(position).isGroupHeader()) {
				rowView = inflater.inflate(R.layout.nav_drawer_item, parent, false);

				ImageView imgView = (ImageView) rowView.findViewById(R.id.item_picture_profiles);
				TextView titleView = (TextView) rowView.findViewById(R.id.item_title);
				TextView counterView = (TextView) rowView.findViewById(R.id.item_counter);
				View divider = (View) rowView.findViewById(R.id.nav_divider);

				if (!modelsArrayList.get(position).hasDivider())
					divider.setVisibility(View.INVISIBLE);
				imgView.setImageResource(modelsArrayList.get(position).getIcon());
				titleView.setText(modelsArrayList.get(position).getTitle());
				if (!modelsArrayList.get(position).getCounter().equals("0")) {
					counterView.setText(modelsArrayList.get(position).getCounter());
					counterView.setEnabled(true);
					counterView.setBackgroundResource(R.drawable.rectangle);
				} else {
					counterView.setEnabled(false);
					if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
						counterView.setBackground(null);
					else
						counterView.setBackgroundDrawable(null);

				}
			} else {
				rowView = inflater.inflate(R.layout.nav_drawer_group, parent, false);
				TextView titleView = (TextView) rowView.findViewById(R.id.header);
				titleView.setText(modelsArrayList.get(position).getTitle());
				titleView.setOnClickListener(new OnClickListener() {
					int i = 0;

					@Override
					public void onClick(View v) {
						i++;
						if (i == 10) {
							PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("in_debug_mode",
									true).apply();
							Toast.makeText(context, "Debug mode enabled", Toast.LENGTH_LONG).show();
						}
					}

				});

			}
		}

		return rowView;
	}
} public class NavItemModel {

	private int icon;
	private String title;
	private String counter;
	private boolean divider;
	private boolean isGroupHeader = false;

	private Bitmap profile_picture;
	private boolean isHeader = false;;

	public NavItemModel(String title) {
		this(-1, title, null, true);
		isGroupHeader = true;
	}

	public NavItemModel(int icon, String title, String counter, boolean divider) {
		super();
		this.icon = icon;
		this.title = title;
		this.counter = counter;
		this.divider = divider;
	}

	public NavItemModel(Bitmap profile_picture, String title) {
		this.profile_picture = profile_picture;
		this.title = title;
		this.isHeader = true;
	}

	public void setDivider(boolean b) {
		this.divider = b;
	}

	public boolean hasDivider() {
		return divider;
	}

	public boolean isHeader() {
		return isHeader;
	}

	public Bitmap getProfilePicture() {
		return profile_picture;
	}

	public void setProfilePicture(Bitmap profile_picture) {
		this.profile_picture = profile_picture;
	}

	public boolean isGroupHeader() {
		return isGroupHeader;
	}

	public int getIcon() {
		return icon;
	}

	public String getTitle() {
		return title;
	}

	public String getCounter() {
		return counter;
	}

	public void setIcon(int icon) {
		this.icon = icon;
	}

} public class ProfilePictureCache {
	HashMap<String, byte[]> cache;
	private static ProfilePictureCache instance;

	public static ProfilePictureCache getInstance(Context context) {
		if (instance == null) {
			instance = new ProfilePictureCache();
			try {
				instance.load(context);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return instance;
	}

	private ProfilePictureCache() {
		cache = new HashMap<String, byte[]>();
	}

	public Bitmap get(String s) {
		if (s == null || cache.get(s) == null)
			return null;
		return BitmapFactory.decodeByteArray(cache.get(s), 0, cache.get(s).length);
	}

	public boolean put(String s, Bitmap b) {
		if (b == null)
			return false;
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		b.compress(Bitmap.CompressFormat.PNG, 100, stream);
		byte[] byteArray = stream.toByteArray();

		cache.put(s, byteArray);
		return true;
	}

	public boolean putNoForce(String s, Bitmap b) {
		if (b == null || cache.containsKey(s))
			return false;
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		b.compress(Bitmap.CompressFormat.PNG, 100, stream);
		byte[] byteArray = stream.toByteArray();

		cache.put(s, byteArray);
		return true;
	}

	public boolean contains(String s) {
		if (s == null)
			return false;
		return cache.containsKey(s);
	}

	public void save(Context activity) {
		ObjectOutputStream outputStream = null;
		try {
			outputStream = new ObjectOutputStream(new FileOutputStream(new File(activity.getFilesDir(),
					"profile_picture_cache.dat")));
			outputStream.writeObject(cache);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (outputStream != null)
					outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@SuppressWarnings("unchecked")
	public void load(Context activity) throws StreamCorruptedException, FileNotFoundException, IOException {
		if (!new File(activity.getFilesDir(), "profile_picture_cache.dat").exists())
			return;
		if (cache.size() > 0)
			return;
		ObjectInputStream inputStream = null;
		try {
			inputStream = new ObjectInputStream(new FileInputStream(new File(activity.getFilesDir(),
					"profile_picture_cache.dat")));
			cache = (HashMap<String, byte[]>) inputStream.readObject();
		} catch (ClassNotFoundException e) {
		} finally {
			try {
				if (inputStream != null)
					inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
} public class RoundedImageView extends ImageView {

	public RoundedImageView(Context context) {
		super(context);
	}

	public RoundedImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	@Override
	protected void onDraw(Canvas canvas) {

		Drawable drawable = getDrawable();

		if (drawable == null) {
			return;
		}

		if (getWidth() == 0 || getHeight() == 0) {
			return;
		}
		Bitmap b = ((BitmapDrawable) drawable).getBitmap();
		Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

		int w = getWidth(), h = getHeight();

		Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
		canvas.drawBitmap(roundBitmap, 0, 0, null);
	}

	public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
		if (bmp == null)
			return null;
		Bitmap sbmp;
		if (bmp.getWidth() != radius || bmp.getHeight() != radius)
			sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
		else
			sbmp = bmp;
		Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(output);

		final int color = 0xffa19774;
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());

		paint.setAntiAlias(true);
		paint.setFilterBitmap(true);
		paint.setDither(true);
		canvas.drawARGB(0, 0, 0, 0);
		paint.setColor(Color.parseColor("#BAB399"));
		canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f, sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);
		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(sbmp, rect, rect, paint);

		return output;
	}

} public class HandshakeProcessor {

	private Activity ac;

	public HandshakeProcessor(Activity ac) {
		this.ac = ac;
	}

	public void processReceivedRandomConfirmationCode(Intent data) {
		if (MainActivity.tempSafe.containsKey(data.getStringExtra("ADD_NEW_KEY_CONFIRMATIONCODE"))) {
			KeyEntity key = MainActivity.tempSafe.get(data.getStringExtra("ADD_NEW_KEY_CONFIRMATIONCODE"));
			try {
				KeySafe.getInstance(ac).put(data.getStringExtra("ADD_NEW_KEY_TELEPHONNUMBER"), key, false);
				KeySafe.getInstance(ac).save();
				MainActivity.tempSafe.remove(data.getStringExtra("ADD_NEW_KEY_CONFIRMATIONCODE"));
			} catch (KeyAlreadyMappedException e) {
			}
		}
	}

	public void processReceivedExchangeInformation(Intent data, Activity activity, String myid) {
		ExchangeInformation ei = null;
		try {
			ei = new ExchangeInformation(data.getByteArrayExtra("QR_RETURNED_Bytes"));
			if (!ei.getMyID().equals(myid)) {

			}
			if (ei.getVersion() == 0x01) {
				try {
					KeySafe.getInstance(ac).put(ei, false);
				} catch (KeyAlreadyMappedException e) {
					showAlreadyMappedDialog(ei, new String(ei.getRandomConfirmation()), 0, activity);
					return;
				}
				finishUpSMS(ei);

			} else if (ei.getVersion() == 0x02) {
				try {
					KeySafe.getInstance(ac).put(ei, false);
				} catch (KeyAlreadyMappedException e) {
					showAlreadyMappedDialog(ei, new String(ei.getRandomConfirmation()), 1, activity);
					return;
				}
				finishUpFb(ei);
			} else if (ei.getVersion() == 0x03) {
				try {
					KeySafe.getInstance(ac).put(ei, false);
				} catch (KeyAlreadyMappedException e) {
					showAlreadyMappedDialog(ei, new String(ei.getRandomConfirmation()), 2, activity);
					return;
				}
				finishUpMail(ei, activity);
			}

		} catch (WrongByteFormatException e1) {
			Toast.makeText(ac, "Failed - Wrong Byte Format!", Toast.LENGTH_SHORT).show();
			e1.printStackTrace();
		} catch (ArrayIndexOutOfBoundsException e) {
			Toast.makeText(ac, "Failed - Array Index Byte Format!", Toast.LENGTH_SHORT).show();
			e.printStackTrace();
		}

	}

	private void finishUpSMS(ExchangeInformation ei) {
		KeySafe.getInstance(ac).save();
		new SMSTool(ac).sendConfirmationCode(ei.getPhoneNumber(), ei.getRandomConfirmation());
	}

	private void finishUpMail(ExchangeInformation ei, Activity activity) {
		KeySafe.getInstance(activity).save();
		new NewMailActivity().sendMail(ei.getID(), activity.getResources().getString(
				R.string.mail_activity_handshake_mail_subject), "%"
				+ Base64.encodeToString(ei.getRandomConfirmation(), Base64.NO_WRAP));
	}

	private void finishUpFb(ExchangeInformation ei) {
		KeySafe.getInstance(ac).save();

		try {
			final FacebookContact temp = findFacebookContact(ei.getID());
			final byte[] confirm = ei.getRandomConfirmation();
			if (temp != null) {
				new Thread() {
					public void run() {
						try {
							MainActivity.fb_api.sendMessage("%" + Base64.encodeToString(confirm, Base64.NO_WRAP), temp);
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}.start();
			}

			else
				throw new IOException("Cant resolve Contact");
		} catch (IOException e) {
			Toast.makeText(ac, "Error: Cant send confirmation | caused by: " + e.toString(), Toast.LENGTH_SHORT).show();
		}
	}

	public void showAlreadyMappedDialog(final ExchangeInformation ei, final String rcc, final int i,
			final Activity activity) {
		AlreadyMappedDialog a = new AlreadyMappedDialog() {
			@Override
			public void onYes() {
				try {
					KeySafe.getInstance(activity).put(ei, true);
				} catch (KeyAlreadyMappedException e) {
				}

				KeySafe.getInstance(activity).save();

				MainActivity.tempSafe.remove(rcc);

				if (i == 0) // SMS
					finishUpSMS(ei);
				if (i == 1) // Fb
					finishUpFb(ei);
				if (i == 2)
					finishUpMail(ei, activity);
			}
		};

		a.show(ac.getFragmentManager(), "tag");
	}

	private FacebookContact findFacebookContact(String id) {
		for (FacebookContact fc : MainActivity.getFbcontacts())
			if (fc.getTid().equals(id))
				return fc;
		return null;
	}

} public class NotificationService {

	private Context context;
	private Intent service;

	public NotificationService(Context context) {
		this.context = context;
	}

	public void startNotificationService() {
		SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
		if (sharedPrefs.getBoolean("notification_fbs", true) && new File(context.getFilesDir(), "cookie.dat").exists()) {
			context.startService(new Intent(context, FacebookService.class));
		}
		if (sharedPrefs.getBoolean("notification_mail", true)
				&& !context.getSharedPreferences("mail", Context.MODE_PRIVATE).getString("mailaddress", "").equals("")) {
			context.startService(new Intent(context, EMailService.class));
		}
	}

	public void startTempService() {
		SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
		if (!sharedPrefs.getBoolean("notification_fbs", true)) {
			service = new Intent(context, FacebookService.class);
			context.startService(service);
		}
	}

	public void stopNotificationService() {
		FacebookService.staticBoolean = false;
		if (service != null)
			context.stopService(service);
	}

} public class UpdateProcessor {

	private Activity activity;
	private SharedPreferences prefs;

	public UpdateProcessor(Activity activity, SharedPreferences prefs) {
		this.activity = activity;
		this.prefs = prefs;
	}

	public void updateMe(String runningVersion, String currentVersion) {
		runningVersion = runningVersion.replaceAll("[.]", "");
		try {
			int versioncode = Integer.parseInt(runningVersion);
			if (versioncode < 1503241) {
				new File(activity.getFilesDir(), "keysafe.dat").delete();
				new File(activity.getFilesDir(), "salt.dat").delete();
			}

			prefs.edit().putString("version", currentVersion).apply();
		} catch (Exception e) {
		}

	}

} public class Base64 {
	
	private static Pattern base64_pattern = Pattern.compile("^[a-zA-Z0-9=/+$]*$");
	
    /**
     * Default values for encoder/decoder flags.
     */
    public static final int DEFAULT = 0;

    /**
     * Encoder flag bit to omit the padding '=' characters at the end
     * of the output (if any).
     */
    public static final int NO_PADDING = 1;

    /**
     * Encoder flag bit to omit all line terminators (i.e., the output
     * will be on one long line).
     */
    public static final int NO_WRAP = 2;

    /**
     * Encoder flag bit to indicate lines should be terminated with a
     * CRLF pair instead of just an LF.  Has no effect if {@code
     * NO_WRAP} is specified as well.
     */
    public static final int CRLF = 4;

    /**
     * Encoder/decoder flag bit to indicate using the "URL and
     * filename safe" variant of Base64 (see RFC 3548 section 4) where
     * {@code -} and {@code _} are used in place of {@code +} and
     * {@code /}.
     */
    public static final int URL_SAFE = 8;

    /**
     * Flag to pass to {@link Base64OutputStream} to indicate that it
     * should not close the output stream it is wrapping when it
     * itself is closed.
     */
    public static final int NO_CLOSE = 16;

    //  --------------------------------------------------------
    //  shared code
    //  --------------------------------------------------------

    /* package */ static abstract class Coder {
        public byte[] output;
        public int op;

        /**
         * Encode/decode another block of input data.  this.output is
         * provided by the caller, and must be big enough to hold all
         * the coded data.  On exit, this.opwill be set to the length
         * of the coded data.
         *
         * @param finish true if this is the final call to process for
         *        this object.  Will finalize the coder state and
         *        include any final bytes in the output.
         *
         * @return true if the input so far is good; false if some
         *         error has been detected in the input stream..
         */
        public abstract boolean process(byte[] input, int offset, int len, boolean finish);

        /**
         * @return the maximum number of bytes a call to process()
         * could produce for the given number of input bytes.  This may
         * be an overestimate.
         */
        public abstract int maxOutputSize(int len);
    }

    //  --------------------------------------------------------
    //  decoding
    //  --------------------------------------------------------

    /**
     * Decode the Base64-encoded data in input and return the data in
     * a new byte array.
     *
     * <p>The padding '=' characters at the end are considered optional, but
     * if any are present, there must be the correct number of them.
     *
     * @param str    the input String to decode, which is converted to
     *               bytes using the default charset
     * @param flags  controls certain features of the decoded output.
     *               Pass {@code DEFAULT} to decode standard Base64.
     *
     * @throws IllegalArgumentException if the input contains
     * incorrect padding
     */
    public static byte[] decode(String str, int flags) {
        return decode(str.getBytes(), flags);
    }

    /**
     * Decode the Base64-encoded data in input and return the data in
     * a new byte array.
     *
     * <p>The padding '=' characters at the end are considered optional, but
     * if any are present, there must be the correct number of them.
     *
     * @param input the input array to decode
     * @param flags  controls certain features of the decoded output.
     *               Pass {@code DEFAULT} to decode standard Base64.
     *
     * @throws IllegalArgumentException if the input contains
     * incorrect padding
     */
    public static byte[] decode(byte[] input, int flags) {
        return decode(input, 0, input.length, flags);
    }

    /**
     * Decode the Base64-encoded data in input and return the data in
     * a new byte array.
     *
     * <p>The padding '=' characters at the end are considered optional, but
     * if any are present, there must be the correct number of them.
     *
     * @param input  the data to decode
     * @param offset the position within the input array at which to start
     * @param len    the number of bytes of input to decode
     * @param flags  controls certain features of the decoded output.
     *               Pass {@code DEFAULT} to decode standard Base64.
     *
     * @throws IllegalArgumentException if the input contains
     * incorrect padding
     */
    public static byte[] decode(byte[] input, int offset, int len, int flags) {
        // Allocate space for the most data the input could represent.
        // (It could contain less if it contains whitespace, etc.)
        Decoder decoder = new Decoder(flags, new byte[len*3/4]);

        if (!decoder.process(input, offset, len, true)) {
            throw new IllegalArgumentException("bad base-64");
        }

        // Maybe we got lucky and allocated exactly enough output space.
        if (decoder.op == decoder.output.length) {
            return decoder.output;
        }

        // Need to shorten the array, so allocate a new one of the
        // right size and copy.
        byte[] temp = new byte[decoder.op];
        System.arraycopy(decoder.output, 0, temp, 0, decoder.op);
        return temp;
    }

    /* package */ static class Decoder extends Coder {
        /**
         * Lookup table for turning bytes into their position in the
         * Base64 alphabet.
         */
        private static final int DECODE[] = {
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        };

        /**
         * Decode lookup table for the "web safe" variant (RFC 3548
         * sec. 4) where - and _ replace + and /.
         */
        private static final int DECODE_WEBSAFE[] = {
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        };

        /** Non-data values in the DECODE arrays. */
        private static final int SKIP = -1;
        private static final int EQUALS = -2;

        /**
         * States 0-3 are reading through the next input tuple.
         * State 4 is having read one '=' and expecting exactly
         * one more.
         * State 5 is expecting no more data or padding characters
         * in the input.
         * State 6 is the error state; an error has been detected
         * in the input and no future input can "fix" it.
         */
        private int state;   // state number (0 to 6)
        private int value;

        final private int[] alphabet;

        public Decoder(int flags, byte[] output) {
            this.output = output;

            alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
            state = 0;
            value = 0;
        }

        /**
         * @return an overestimate for the number of bytes {@code
         * len} bytes could decode to.
         */
        public int maxOutputSize(int len) {
            return len * 3/4 + 10;
        }

        /**
         * Decode another block of input data.
         *
         * @return true if the state machine is still healthy.  false if
         *         bad base-64 data has been detected in the input stream.
         */
        public boolean process(byte[] input, int offset, int len, boolean finish) {
            if (this.state == 6) return false;

            int p = offset;
            len += offset;

            // Using local variables makes the decoder about 12%
            // faster than if we manipulate the member variables in
            // the loop.  (Even alphabet makes a measurable
            // difference, which is somewhat surprising to me since
            // the member variable is final.)
            int state = this.state;
            int value = this.value;
            int op = 0;
            final byte[] output = this.output;
            final int[] alphabet = this.alphabet;

            while (p < len) {
                // Try the fast path:  we're starting a new tuple and the
                // next four bytes of the input stream are all data
                // bytes.  This corresponds to going through states
                // 0-1-2-3-0.  We expect to use this method for most of
                // the data.
                //
                // If any of the next four bytes of input are non-data
                // (whitespace, etc.), value will end up negative.  (All
                // the non-data values in decode are small negative
                // numbers, so shifting any of them up and or'ing them
                // together will result in a value with its top bit set.)
                //
                // You can remove this whole block and the output should
                // be the same, just slower.
                if (state == 0) {
                    while (p+4 <= len &&
                           (value = ((alphabet[input[p] & 0xff] << 18) |
                                     (alphabet[input[p+1] & 0xff] << 12) |
                                     (alphabet[input[p+2] & 0xff] << 6) |
                                     (alphabet[input[p+3] & 0xff]))) >= 0) {
                        output[op+2] = (byte) value;
                        output[op+1] = (byte) (value >> 8);
                        output[op] = (byte) (value >> 16);
                        op += 3;
                        p += 4;
                    }
                    if (p >= len) break;
                }

                // The fast path isn't available -- either we've read a
                // partial tuple, or the next four input bytes aren't all
                // data, or whatever.  Fall back to the slower state
                // machine implementation.

                int d = alphabet[input[p++] & 0xff];

                switch (state) {
                case 0:
                    if (d >= 0) {
                        value = d;
                        ++state;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;

                case 1:
                    if (d >= 0) {
                        value = (value << 6) | d;
                        ++state;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;

                case 2:
                    if (d >= 0) {
                        value = (value << 6) | d;
                        ++state;
                    } else if (d == EQUALS) {
                        // Emit the last (partial) output tuple;
                        // expect exactly one more padding character.
                        output[op++] = (byte) (value >> 4);
                        state = 4;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;

                case 3:
                    if (d >= 0) {
                        // Emit the output triple and return to state 0.
                        value = (value << 6) | d;
                        output[op+2] = (byte) value;
                        output[op+1] = (byte) (value >> 8);
                        output[op] = (byte) (value >> 16);
                        op += 3;
                        state = 0;
                    } else if (d == EQUALS) {
                        // Emit the last (partial) output tuple;
                        // expect no further data or padding characters.
                        output[op+1] = (byte) (value >> 2);
                        output[op] = (byte) (value >> 10);
                        op += 2;
                        state = 5;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;

                case 4:
                    if (d == EQUALS) {
                        ++state;
                    } else if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;

                case 5:
                    if (d != SKIP) {
                        this.state = 6;
                        return false;
                    }
                    break;
                }
            }

            if (!finish) {
                // We're out of input, but a future call could provide
                // more.
                this.state = state;
                this.value = value;
                this.op = op;
                return true;
            }

            // Done reading input.  Now figure out where we are left in
            // the state machine and finish up.

            switch (state) {
            case 0:
                // Output length is a multiple of three.  Fine.
                break;
            case 1:
                // Read one extra input byte, which isn't enough to
                // make another output byte.  Illegal.
                this.state = 6;
                return false;
            case 2:
                // Read two extra input bytes, enough to emit 1 more
                // output byte.  Fine.
                output[op++] = (byte) (value >> 4);
                break;
            case 3:
                // Read three extra input bytes, enough to emit 2 more
                // output bytes.  Fine.
                output[op++] = (byte) (value >> 10);
                output[op++] = (byte) (value >> 2);
                break;
            case 4:
                // Read one padding '=' when we expected 2.  Illegal.
                this.state = 6;
                return false;
            case 5:
                // Read all the padding '='s we expected and no more.
                // Fine.
                break;
            }

            this.state = state;
            this.op = op;
            return true;
        }
    }

    //  --------------------------------------------------------
    //  encoding
    //  --------------------------------------------------------

    /**
     * Base64-encode the given data and return a newly allocated
     * String with the result.
     *
     * @param input  the data to encode
     * @param flags  controls certain features of the encoded output.
     *               Passing {@code DEFAULT} results in output that
     *               adheres to RFC 2045.
     */
    public static String encodeToString(byte[] input, int flags) {
        try {
            return new String(encode(input, flags), "US-ASCII");
        } catch (UnsupportedEncodingException e) {
            // US-ASCII is guaranteed to be available.
            throw new AssertionError(e);
        }
    }

    /**
     * Base64-encode the given data and return a newly allocated
     * String with the result.
     *
     * @param input  the data to encode
     * @param offset the position within the input array at which to
     *               start
     * @param len    the number of bytes of input to encode
     * @param flags  controls certain features of the encoded output.
     *               Passing {@code DEFAULT} results in output that
     *               adheres to RFC 2045.
     */
    public static String encodeToString(byte[] input, int offset, int len, int flags) {
        try {
            return new String(encode(input, offset, len, flags), "US-ASCII");
        } catch (UnsupportedEncodingException e) {
            // US-ASCII is guaranteed to be available.
            throw new AssertionError(e);
        }
    }

    /**
     * Base64-encode the given data and return a newly allocated
     * byte[] with the result.
     *
     * @param input  the data to encode
     * @param flags  controls certain features of the encoded output.
     *               Passing {@code DEFAULT} results in output that
     *               adheres to RFC 2045.
     */
    public static byte[] encode(byte[] input, int flags) {
        return encode(input, 0, input.length, flags);
    }

    /**
     * Base64-encode the given data and return a newly allocated
     * byte[] with the result.
     *
     * @param input  the data to encode
     * @param offset the position within the input array at which to
     *               start
     * @param len    the number of bytes of input to encode
     * @param flags  controls certain features of the encoded output.
     *               Passing {@code DEFAULT} results in output that
     *               adheres to RFC 2045.
     */
    public static byte[] encode(byte[] input, int offset, int len, int flags) {
        Encoder encoder = new Encoder(flags, null);

        // Compute the exact length of the array we will produce.
        int output_len = len / 3 * 4;

        // Account for the tail of the data and the padding bytes, if any.
        if (encoder.do_padding) {
            if (len % 3 > 0) {
                output_len += 4;
            }
        } else {
            switch (len % 3) {
                case 0: break;
                case 1: output_len += 2; break;
                case 2: output_len += 3; break;
            }
        }

        // Account for the newlines, if any.
        if (encoder.do_newline && len > 0) {
            output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) *
                (encoder.do_cr ? 2 : 1);
        }

        encoder.output = new byte[output_len];
        encoder.process(input, offset, len, true);

        assert encoder.op == output_len;

        return encoder.output;
    }

    /* package */ static class Encoder extends Coder {
        /**
         * Emit a new line every this many output tuples.  Corresponds to
         * a 76-character line length (the maximum allowable according to
         * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>).
         */
        public static final int LINE_GROUPS = 19;

        /**
         * Lookup table for turning Base64 alphabet positions (6 bits)
         * into output bytes.
         */
        private static final byte ENCODE[] = {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
        };

        /**
         * Lookup table for turning Base64 alphabet positions (6 bits)
         * into output bytes.
         */
        private static final byte ENCODE_WEBSAFE[] = {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
        };

        final private byte[] tail;
        /* package */ int tailLen;
        private int count;

        final public boolean do_padding;
        final public boolean do_newline;
        final public boolean do_cr;
        final private byte[] alphabet;

        public Encoder(int flags, byte[] output) {
            this.output = output;

            do_padding = (flags & NO_PADDING) == 0;
            do_newline = (flags & NO_WRAP) == 0;
            do_cr = (flags & CRLF) != 0;
            alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;

            tail = new byte[2];
            tailLen = 0;

            count = do_newline ? LINE_GROUPS : -1;
        }

        /**
         * @return an overestimate for the number of bytes {@code
         * len} bytes could encode to.
         */
        public int maxOutputSize(int len) {
            return len * 8/5 + 10;
        }

        public boolean process(byte[] input, int offset, int len, boolean finish) {
            // Using local variables makes the encoder about 9% faster.
            final byte[] alphabet = this.alphabet;
            final byte[] output = this.output;
            int op = 0;
            int count = this.count;

            int p = offset;
            len += offset;
            int v = -1;

            // First we need to concatenate the tail of the previous call
            // with any input bytes available now and see if we can empty
            // the tail.

            switch (tailLen) {
                case 0:
                    // There was no tail.
                    break;

                case 1:
                    if (p+2 <= len) {
                        // A 1-byte tail with at least 2 bytes of
                        // input available now.
                        v = ((tail[0] & 0xff) << 16) |
                            ((input[p++] & 0xff) << 8) |
                            (input[p++] & 0xff);
                        tailLen = 0;
                    };
                    break;

                case 2:
                    if (p+1 <= len) {
                        // A 2-byte tail with at least 1 byte of input.
                        v = ((tail[0] & 0xff) << 16) |
                            ((tail[1] & 0xff) << 8) |
                            (input[p++] & 0xff);
                        tailLen = 0;
                    }
                    break;
            }

            if (v != -1) {
                output[op++] = alphabet[(v >> 18) & 0x3f];
                output[op++] = alphabet[(v >> 12) & 0x3f];
                output[op++] = alphabet[(v >> 6) & 0x3f];
                output[op++] = alphabet[v & 0x3f];
                if (--count == 0) {
                    if (do_cr) output[op++] = '\r';
                    output[op++] = '\n';
                    count = LINE_GROUPS;
                }
            }

            // At this point either there is no tail, or there are fewer
            // than 3 bytes of input available.

            // The main loop, turning 3 input bytes into 4 output bytes on
            // each iteration.
            while (p+3 <= len) {
                v = ((input[p] & 0xff) << 16) |
                    ((input[p+1] & 0xff) << 8) |
                    (input[p+2] & 0xff);
                output[op] = alphabet[(v >> 18) & 0x3f];
                output[op+1] = alphabet[(v >> 12) & 0x3f];
                output[op+2] = alphabet[(v >> 6) & 0x3f];
                output[op+3] = alphabet[v & 0x3f];
                p += 3;
                op += 4;
                if (--count == 0) {
                    if (do_cr) output[op++] = '\r';
                    output[op++] = '\n';
                    count = LINE_GROUPS;
                }
            }

            if (finish) {
                // Finish up the tail of the input.  Note that we need to
                // consume any bytes in tail before any bytes
                // remaining in input; there should be at most two bytes
                // total.

                if (p-tailLen == len-1) {
                    int t = 0;
                    v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4;
                    tailLen -= t;
                    output[op++] = alphabet[(v >> 6) & 0x3f];
                    output[op++] = alphabet[v & 0x3f];
                    if (do_padding) {
                        output[op++] = '=';
                        output[op++] = '=';
                    }
                    if (do_newline) {
                        if (do_cr) output[op++] = '\r';
                        output[op++] = '\n';
                    }
                } else if (p-tailLen == len-2) {
                    int t = 0;
                    v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) |
                        (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2);
                    tailLen -= t;
                    output[op++] = alphabet[(v >> 12) & 0x3f];
                    output[op++] = alphabet[(v >> 6) & 0x3f];
                    output[op++] = alphabet[v & 0x3f];
                    if (do_padding) {
                        output[op++] = '=';
                    }
                    if (do_newline) {
                        if (do_cr) output[op++] = '\r';
                        output[op++] = '\n';
                    }
                } else if (do_newline && op > 0 && count != LINE_GROUPS) {
                    if (do_cr) output[op++] = '\r';
                    output[op++] = '\n';
                }

                assert tailLen == 0;
                assert p == len;
            } else {
                // Save the leftovers in tail to be consumed on the next
                // call to encodeInternal.

                if (p == len-1) {
                    tail[tailLen++] = input[p];
                } else if (p == len-2) {
                    tail[tailLen++] = input[p];
                    tail[tailLen++] = input[p+1];
                }
            }

            this.op = op;
            this.count = count;

            return true;
        }
    }
    
    /**
     * Is used to check if a Message is an encrypted(!) base64 message (min length 16)
     * @param str
     * @return
     */
	public static boolean isBase64(String str) {
		return Base64.base64_pattern.matcher(str).matches() && str.length() >= 16;
	}
	
	/**
     * Is used to check if a text only contains base64 charset
     * @param str
     * @return
     */
	public static boolean isPureBase64(String str) {
		return Base64.base64_pattern.matcher(str).matches();
	}

    private Base64() { }   // don't instantiate
    
    public static void main(String[] args) {
		String test = "1s++DchtLbMLGedrWBOv2+03MgUVqjHGTedum6A9hFEaMzqxeHHHfQEDZvLlvb9XQsI2HC8yqdRGoFzOjrVvr6w38+L584EQ73+ZFns1mvhYflEg9o1n067XuQjvIMIDaFbzQ3WTTW5YDZTHUF4pMkvBRIZ4w29Spa39rBiX5kJO2qCONRp+safC06xCT7iu7aXTjQJ+dvgiVgVr1s96b6MvrxYxj2wpxfOucVI71e5FVt8gYswet/Co8JJUc9jFS2dJY6jU0QzgwmDbvkrZdDtO68DR6nI/DlUAOI6wAOGuaPdd8s2wnReDEej/DFUMhFruVcGIytz8DD5pgIJUR+Gx6X8FRl/0d7gMPWIEltRBbkUPwraAoY+2Onlt+5LW";
		System.out.println(isBase64(test));
    }
} public class Message {
	
	private String message;
	private String random;
	
	public Message(String message){
		this.message =  message;
	}
	
	private String generateRandom(){
		SecureRandom random = new SecureRandom();
	    byte bytes[] = new byte[3];
	    random.nextBytes(bytes);
		try {
			return new String(bytes, "US-ASCII");
		} catch (UnsupportedEncodingException e) {}
		return "";
	}
	
	private byte [] combine(String message, String random){
		return (random+message).getBytes();
	}
	
	private String uncombine(String decmessage){
		byte[] temp = decmessage.substring(3, decmessage.length()).getBytes();
		if(temp[temp.length-1] == 0){
			for(int i= temp.length-1; i >= 0; i--){
				if(temp[i] != 0){
					byte[] temp2 = new byte[i+1];
					System.arraycopy(temp, 0, temp2, 0, i+1);
					temp = temp2;
					break;
				}
			}
		}
		return new String(temp);
	}
	
	public String encryptedMessage(KeyEntity key) throws MessageEncrypterException{
		this.random = generateRandom();
		try {
			if(key.getVersion() == KeyEntity.BLAKE_AES_NONE_1) // AES
				return new String(Base64.encode(AESCrypt.encrypt(key.getFirstKey(), combine(message, random)), Base64.NO_WRAP), "US-ASCII");
			if(key.getVersion() == KeyEntity.BLAKE_AES_SERPENT_1) // AES & Serpent
				return new String(Base64.encode(AES_SERPENT.encrypt(key.getFirstKey(), key.getSecondKey(), combine(message, random)), Base64.NO_WRAP), "US-ASCII");
			if(key.getVersion() == KeyEntity.BLAKE_AES_THREEFISH_1) // AES & Threefish
				return new String(Base64.encode(AES_THREEFISH.encrypt(key.getFirstKey(), key.getSecondKey(), combine(message, random)), Base64.NO_WRAP), "US-ASCII");
		} catch (Exception e) {
			e.printStackTrace();
			throw new MessageEncrypterException();
		}
		return null;
	}
	
	public String decryptedMessage(KeyEntity key) throws MessageDecrypterException{
		try {
			if(key.getVersion() == KeyEntity.BLAKE_AES_NONE_1) // AES
				return uncombine(new String(AESCrypt.decrypt(key.getFirstKey(), Base64.decode(message.getBytes(), Base64.NO_WRAP)), "UTF-8"));
			if(key.getVersion() == KeyEntity.BLAKE_AES_SERPENT_1) // AES & Serpent
				return uncombine(new String(AES_SERPENT.decrypt(key.getFirstKey(), key.getSecondKey(), Base64.decode(message.getBytes(), Base64.NO_WRAP)), "UTF-8"));
			if(key.getVersion() == KeyEntity.BLAKE_AES_THREEFISH_1) // AES & Threefish
				return uncombine(new String(AES_THREEFISH.decrypt(key.getFirstKey(), key.getSecondKey(), Base64.decode(message.getBytes(), Base64.NO_WRAP)), "UTF-8"));
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new MessageDecrypterException();
		}
		return null;
	}
	
	public String toString(){
		return this.message;
	}
} public class MessageDecrypterException extends Exception{
	
	private static final long serialVersionUID = 1L;

	public MessageDecrypterException(){
		super();
	}
} public class Email implements Serializable {
	
	private String sender;
	private String recipient;
	private String subject;
	private Date date;
	private String text;
	private boolean read = false;
	ArrayList<File> files;
	private String senderName = "";
	
	public Email(String sender, String recipient, String subject,
			Date date, String text, ArrayList<File> files){
		int ind = sender.indexOf("<");
		if(ind >= 0){
			int ind2 = sender.indexOf(">");
			if(ind2 > ind){
				this.sender = sender.substring(ind+1, ind2);
				this.senderName = sender.substring(0, ind);
				this.senderName = this.senderName.replaceAll("\"", ""); // remove "" (like used by amazon)
			}
		} else {
			this.sender = sender;
		}		
		this.recipient = recipient;
		this.subject = subject;
		this.date = date;
		this.text = text;
		this.files = files;
	}
	
	public void setRead(){
		this.read = true;
	}
	
	public boolean isRead(){
		return read;
	}
	
	public String getSenderName(){
		return senderName;
	}
	
	public String getSender(){
		return sender;
	}
	
	public String getRecipient(){
		return recipient;
	}
	
	public Date getDate(){
		return date;
	}
	
	public String getSubject(){
		return subject;
	}
	
	public String getText(){
		return text;
	}
	
	public boolean hasFiles(){
		if(files.size() <= 0){
			return false;
		}
		return true;
	}
	
	public ArrayList<File> getFilesFromEmail(){
		return files;
	}
	
	public String toString(){
		return "["+sender+ "| "+senderName+"] ("+subject+ ") "+text; 
	}
	
} public class MailControlAndroid {

	private static ArrayList<MailProfile> mps = new ArrayList<MailProfile>();
	
	public static void receiveEmailIMAPAndroid(MailProfile mailprofile, String folder) throws Exception{
		receiveEmailIMAPAndroid(mailprofile, folder, 0, 25);
	}
	
	public static void receiveEmailPOPAndroid(MailProfile mailprofile, String folder) throws Exception{
		receiveEmailPOPAndroid(mailprofile, folder, 0, 25);
	}
	
    public static void sendMailAndroid(final MailProfile mailProfile, String recipient, String subject, String text) throws Exception {  
    	Properties props = new Properties();   
        props.setProperty("mail.transport.protocol", "smtp");   
        props.setProperty("mail.host", mailProfile.getSmtpHost());   
        props.put("mail.smtp.auth", "true");   
        props.put("mail.smtp.port", mailProfile.getSmtpPort());   
        
        try{
        Session session = Session.getInstance(props, new javax.mail.Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(mailProfile.getUsername(), mailProfile.getPassword());
			}
		  });
        MimeMessage message = new MimeMessage(session);   
        DataHandler handler = new DataHandler(new ByteArrayDataSource(text.getBytes(), "text/plain"));  
        message.setSender(new InternetAddress(mailProfile.getEmail()));   
        message.setSubject(subject);   
        message.setFrom(new InternetAddress(mailProfile.getEmail()));
        message.setDataHandler(handler);   
        if (recipient.indexOf(',') > 0)   
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient));   
        else  
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipient));   
        Transport.send(message);   
        }catch(Exception e){
        	e.printStackTrace();
        }
    }   
	
	public static void receiveEmailPOPAndroid(MailProfile mailprofile, String folder, int offset, int limit) throws Exception{
		Properties props = new Properties();
        props.setProperty("mail.store.protocol", "pop3");
        props.put("mail.pop3.port", mailprofile.getPop3Port());   
	        props.setProperty("mail.pop3.socketFactory.class",
					"javax.net.ssl.SSLSocketFactory");
	        props.setProperty("mail.pop3.socketFactory.fallback",
					"false");
	        props.setProperty("mail.pop3.port", "" + mailprofile.getPop3Port());
	        props.setProperty("mail.pop3.socketFactory.port", ""
					+ mailprofile.getPop3Port());
	        
            Session session = Session.getInstance(props, null);
            Store store = session.getStore();
            store.connect(mailprofile.getPop3Host(), mailprofile.getEmail(), mailprofile.getPassword());
            Folder inbox = store.getFolder(folder);
            inbox.open(Folder.READ_ONLY); 
            if(limit > inbox.getMessageCount()) limit = inbox.getMessageCount()-1;
            javax.mail.Message[] msg = inbox.getMessages(inbox.getMessageCount()-offset-limit, inbox.getMessageCount()-offset);
            String content = null;
            javax.mail.Message m;
            try{
	            for(int i=msg.length-1; i >= 0; i--){
	            	m = msg[i];
	            	 Object msgContent = m.getContent();                   
	            	     if (msgContent instanceof Multipart) {
	            	         Multipart multipart = (Multipart) msgContent;
	            	         for (int j = 0; j < multipart.getCount(); j++) {
	            	         BodyPart bodyPart = multipart.getBodyPart(j);
	            	         String disposition = bodyPart.getDisposition();
	            	         if (disposition != null && (disposition.equalsIgnoreCase("ATTACHMENT"))) { 
	            	              DataHandler handler = bodyPart.getDataHandler();                 
	            	          }
	            	          else { 
	            	        	  if(bodyPart instanceof IMAPBodyPart){
		            	                 content = ((IMAPBodyPart)bodyPart).getContent().toString();  // the changed code 
		            	                 if(((IMAPBodyPart)bodyPart).getContent() instanceof MimeMultipart){
		            	                	 Multipart multi2 = (Multipart) ((IMAPBodyPart)bodyPart).getContent();
		            	                	 for (int k = 0; k < multi2.getCount(); k++) 
		            	                		 content =multi2.getBodyPart(k).getContent().toString();
		            	        		}
		            	        	}    
	            	            }
	            	        }
	            	     }
	            	     else                
	            	         content= m.getContent().toString();
	            	
	            		if(m.getContentType().startsWith("com.sun.mail.util.BASE64DecoderStream"))
	            			content = ((BASE64DecoderStream) m.getContent()).toString();
		            	mailprofile.addReceivedMessage(
		            			new Email(
		            					MimeUtility.decodeText(m.getFrom()[0].toString()), 
		            					MimeUtility.decodeText(m.getAllRecipients()[0].toString()), 
		            					MimeUtility.decodeText(m.getSubject()), m.getReceivedDate(), 
		            					content, 
		            					new ArrayList<File>()
		            			)
		            	);
	            }
            } catch(Exception e){}
            finally{
            	if(inbox != null)
            		inbox.close(true);
            	if(store != null)
            		store.close();
            }
    
	}
	
	public static void receiveEmailIMAPAndroid(MailProfile mailprofile, String folder, int offset, int limit) throws Exception{
		Properties props = new Properties();
        props.setProperty("mail.store.protocol", "imaps");
        props.put("mail.imap.port", mailprofile.getImapPort());   
        	props.setProperty("mail.imap.socketFactory.class",
   					"javax.net.ssl.SSLSocketFactory");
   	        props.setProperty("mail.imap.socketFactory.fallback",
   					"false");
   	        props.setProperty("mail.imap.port", "" + mailprofile.getImapPort());
   	        props.setProperty("mail.imap.socketFactory.port", ""
   					+ mailprofile.getImapPort());

            Session session = Session.getInstance(props, null);
            Store store = session.getStore();
            store.connect(mailprofile.getImapHost(), mailprofile.getEmail(), mailprofile.getPassword());
            Folder inbox = store.getFolder(folder);
            inbox.open(Folder.READ_ONLY); 
            if(limit > inbox.getMessageCount()) limit = inbox.getMessageCount()-1;
            javax.mail.Message[] msg = inbox.getMessages(inbox.getMessageCount()-offset-limit, inbox.getMessageCount()-offset);
            String content;
            javax.mail.Message m;
            try{
	            for(int i=msg.length-1; i >= 0; i--){
	            	m = msg[i];
	            		content = m.getContent().toString();           		
	            		 Object msgContent = m.getContent();
                   
	            	     if (msgContent instanceof Multipart) {
	            	         Multipart multipart = (Multipart) msgContent;
	            	         for (int j = 0; j < multipart.getCount(); j++) {
	            	         BodyPart bodyPart = multipart.getBodyPart(j);
	            	         String disposition = bodyPart.getDisposition();
	            	         if (disposition != null && (disposition.equalsIgnoreCase("ATTACHMENT"))) { 
	            	             DataHandler handler = bodyPart.getDataHandler();                    
	            	          }
	            	          else { 
	            	        	if(bodyPart instanceof IMAPBodyPart){
	            	                 content = ((IMAPBodyPart)bodyPart).getContent().toString();  // the changed code 
	            	                 if(((IMAPBodyPart)bodyPart).getContent() instanceof MimeMultipart){
	            	                	 Multipart multi2 = (Multipart) ((IMAPBodyPart)bodyPart).getContent();
	            	                	 for (int k = 0; k < multi2.getCount(); k++) 
	            	                		 content =multi2.getBodyPart(k).getContent().toString();
	            	        		}
	            	        	}
	            	        	
	            	            }
	            	        }
	            	     }
	            	    
	            	     else                
	            	         content= m.getContent().toString();
	            		if(content.startsWith("com.sun.mail.util.BASE64DecoderStream")){
	            			
	            		}
		            	mailprofile.addReceivedMessage(
		            			new Email(
		            					MimeUtility.decodeText(m.getFrom()[0].toString()), 
		            					MimeUtility.decodeText(m.getAllRecipients()[0].toString()), 
		            					MimeUtility.decodeText(m.getSubject()), m.getReceivedDate(), 
		            					content, 
		            					new ArrayList<File>()
		            			)
		            	);
	           
	            } 
            } catch(Exception e){e.printStackTrace();} 
            finally{
            	if(inbox != null)
            		inbox.close(true);
            	if(store != null)
            		store.close();
            	
            	
            }
    
	}
	

} public class MailProfile implements Serializable {

	private static final long serialVersionUID = 6739903367018949913L;
	private String smtpHost;
	private String pop3Host;
	private String imapHost;
	private String username;
	private String password;
	private String email;
	private int smtpPort;
	private int Pop3Port;
	private int ImapPort;
	
	private boolean active = false;
	private ArrayList<Email> receivedMessages;
	private ArrayList<Email> sentMessages;
	private TreeMap<String, String> keyMap = new TreeMap<String, String>();
	
	static byte [] temp = {125, 13, 42,  43, 55, 108, 66, 77, 88, 99, 42, 15, 9,  35,  59,  26 };
	private static IvParameterSpec ips = new IvParameterSpec(temp);
	
	public MailProfile(String smtpHost, int smtpPort, String pop3Host, int pop3Port, String imapHost, int imapPort,
			String username, String password, String email) {
		this.smtpHost = smtpHost;
		this.pop3Host = pop3Host;
		this.imapHost = imapHost;
		this.username = username;
		this.password = password;
		this.email = email;
		this.receivedMessages = new ArrayList<Email>();
		this.sentMessages = new ArrayList<Email>();
		this.smtpPort = smtpPort;
		this.ImapPort = imapPort;
		this.Pop3Port = pop3Port;
	}

	public int getPop3Port() {
		return Pop3Port;
	}

	public void setPop3Port(int pop3Port) {
		Pop3Port = pop3Port;
	}

	public int getImapPort() {
		return ImapPort;
	}

	public void setImapPort(int imapPort) {
		ImapPort = imapPort;
	}

	public int getSmtpPort() {
		return smtpPort;
	}

	public void setSmtpPort(int smtpPort) {
		this.smtpPort = smtpPort;
	}
	
	public MailAuthenticator getPasswordAuthentication() {
		return new MailAuthenticator(username, password);
	}

	public void clearSentMessages(){
		sentMessages.removeAll(sentMessages);
	}
	
	public void clearReceivedMessages(){
		receivedMessages.removeAll(receivedMessages);
	}
	
	public void addReceivedMessage(Email email) {
		receivedMessages.add(email);
	}

	public ArrayList<Email> getReceivedMessages() {
		return this.receivedMessages;
	}

	public ArrayList<Email> getSentMessages() {
		return this.sentMessages;
	}

	public void addSentMessage(Email email) {
		sentMessages.add(email);
	}

	public String getUsername() {
		return username;
	}

	public String getPassword() {
		return password;
	}

	public String getPop3Host() {
		return pop3Host;
	}

	public String getSmtpHost() {
		return smtpHost;
	}

	public String getImapHost() {
		return imapHost;
	}

	public boolean getState() {
		return active;
	}

	public void setState(boolean state) {
		this.active = state;
	}

	public String getEmail() {
		return email;
	}

	/**
	 * Schreibt alle konfigurierten Profile des Benutzers in eine vordefinierte
	 * Zieldatei am Dateisystem.
	 * 
	 * @param profiles
	 *            - Eine ArrayList des Types "MailProfile", die alle
	 *            konfigurierten Profile des Benutzers enth�lt.
	 */
	public static void writeToFile(ArrayList<MailProfile> profiles,
			String secretPassword) {
		try {
			Cipher cipher = null;
			cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			System.out.println(ips);
			cipher.init(Cipher.ENCRYPT_MODE, fromStringToAESkey(secretPassword), ips);
			SealedObject sealedObject = null;
			sealedObject = new SealedObject(profiles, cipher);
			CipherOutputStream cipherOutputStream = null;
			cipherOutputStream = new CipherOutputStream(
					new BufferedOutputStream(new FileOutputStream(
							"E:\\My Documents\\Diplomarbeit\\profiles.raven")),
					cipher);
			ObjectOutputStream outputStream = null;
			outputStream = new ObjectOutputStream(cipherOutputStream);
			outputStream.writeObject(sealedObject);
			outputStream.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}

	}

	
	public static SecretKey fromStringToAESkey(String s) {
		return new SecretKeySpec(new BLAKE512().digest(s.getBytes()), "AES");
	}

	@SuppressWarnings("unchecked")
	public static ArrayList<MailProfile> loadFromFile(File data, String secretPassword) {
		ArrayList<MailProfile> userList = null;
		System.out.println(ips);
		try{
			Cipher cipher = null;
		cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

		// Code to write your object to file
		cipher.init(Cipher.DECRYPT_MODE, fromStringToAESkey(secretPassword), ips);
		CipherInputStream cipherInputStream = null;
		cipherInputStream = new CipherInputStream(new BufferedInputStream(
				new FileInputStream(data)), cipher);

		ObjectInputStream inputStream = null;
		inputStream = new ObjectInputStream(cipherInputStream);
		SealedObject sealedObject = null;
		sealedObject = (SealedObject) inputStream.readObject();
		userList = (ArrayList<MailProfile>) sealedObject.getObject(cipher);
		inputStream.close();
		
		
		} catch(Exception ex){
			ex.printStackTrace();
		}
		
		return userList;
		
	}

	@Override
	public boolean equals(Object obj) {
		if ((MailProfile) obj == null) {
			return false;
		}

		if (this.email.equals(((MailProfile) obj).email)) {
			return true;
		}
		return false;
	}

	public void addKey(String contact, String key) {
		if (keyMap.containsKey(contact)) {
			return;
		}
		keyMap.put(contact, key);
	}
	
	public Set<String> getKeyMapEntries(){
		return keyMap.keySet();
	}
} public class KeyEntity implements Serializable{

	private static final long serialVersionUID = 1L;
	
	private byte [] key;
	private byte [] key2;
	private byte version;
	private long timestamp;
	
	// Format: HASH_ENCRYPTION_ENCRYPTION_VERSION
	public static final byte BLAKE_AES_NONE_1 		= 	0x01;
	public static final byte BLAKE_AES_MARS_1		= 	0x02;
	public static final byte BLAKE_AES_MARS_2 		= 	0x03;
	public static final byte BLAKE_AES_SERPENT_1 	= 	0x04;
	public static final byte BLAKE_AES_THREEFISH_1 	= 	0x05;
	public static final byte ECDH_PRIVATE_KEY 		= 	0x1F; // only use for temporary storage of dh private key 
	
	public static final byte DEFAULT = BLAKE_AES_THREEFISH_1;
	
	public KeyEntity(byte [] key, byte [] key2, long timestamp, byte version){
		this.key = key;
		this.key2 = key2;
		this.version = version;
		this.timestamp = timestamp;
	}

	
	public KeyEntity(byte [] key, long timestamp, byte version){
		this.key = new byte[32];
		this.key2 = new byte[32];
		System.arraycopy(key, 0, this.key, 0, 32);
		System.arraycopy(key, 32, this.key2, 0, 32);
		this.version = version;
		this.timestamp = timestamp;
	}
	
	public long getTimeStamp(){
		return timestamp;
	}
	
	public byte [] getFirstKey(){
		return key;
	}

	public byte [] getSecondKey(){
		return key2;
	}
	
	public byte getVersion(){
		return version;
	}
	
	public void setTimeStamp(long timestamp){
		this.timestamp = timestamp;
	}
	
	public void setFirstKey(byte [] b){
		key = b;
	}

	public void setSecondKey(byte [] b){
		key2 = b;
	}
	
	public void setVersion(byte version){
		this.version = version;
	}
	
	public byte[] getBothKeys(){
		ByteHelper bh = new ByteHelper(key, key2);
		return bh.get();
	}
	
	public String toString(){
		String s = "";
		for(int i = 0; i < key.length; i++)
			s+=key[i]+";";
		if(key2 != null){ 
			s+=" ||| ";
			for(int i = 0; i < key2.length; i++)
				s+=key2[i]+";";
		}
		return s;
	}
	
}
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.nfc.NdefRecord;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.provider.ContactsContract.PhoneLookup;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import api.ChatAPI;
import api.FacebookContact;
import at.flack.GoogleAnalyticsTrack.TrackerName;
import at.flack.activity.DebugActivity;
import at.flack.activity.NewSMSContactActivity;
import at.flack.activity.QuickPrefsActivity;
import at.flack.contacts.SMSItem;
import at.flack.exchange.KeySafe;
import at.flack.exchange.PRNGFixes;
import at.flack.ui.ContactModel;
import at.flack.ui.NavBarAdapter;
import at.flack.ui.NavItemModel;
import at.flack.ui.ProfilePictureCache;
import at.flack.ui.RoundedImageView;
import at.flack.utils.HandshakeProcessor;
import at.flack.utils.NotificationService;
import at.flack.utils.UpdateProcessor;
import encryption.Base64;
import encryption.Message;
import exceptions.MessageDecrypterException;
import mail.Email;
import mail.MailControlAndroid;
import mail.MailProfile;
import safe.KeyEntity;
		case 1: { // SMS Main
			fragment = SMSMainActivity.getInstance();
			current_fragment = 1;
			break;
		}
		case 2: { // Facebook Main
			fragment = FacebookMainActivity.getInstance();
			current_fragment = 2;
			break;
		}
		case 3: { // Mail Main
			fragment = MailMainActivity.getInstance();
			current_fragment = 3;
			break;
		}
		case 4: { // Mail Out
			if (!getSharedPreferences("mail", Context.MODE_PRIVATE).getString("mailaddress", "").equals("")) {
				fragment = MailOutActivity.getInstance();
				current_fragment = 4;
			} else {
				fragment = MailMainActivity.getInstance();
				current_fragment = 3;
			}
			break;
		}
		case 6: { // Settings
			Intent settings = new Intent(MainActivity.this, QuickPrefsActivity.class);
			startActivityForResult(settings, 3);
			fragment = null;
			break;
		}
		case 7: {// Debug
			Intent debug = new Intent(MainActivity.this, DebugActivity.class);
			startActivity(debug);
			break;
		}
		case 8: {// About
			new AlertDialog.Builder(this).setTitle("Version " + VERSION).setMessage(
					"Developed by:\n" + "- Manuel S. Caspari\n" + "- Nicolas Lukaschek \n" + "- Philipp Adam\n\n"
							+ "Graphics by Michael Kroißmayr\n\n" + "Used Librarys:\n" + "- Emojicon by Hieu Rocker\n"
							+ "- Floating Action Button by Oleksandr Melnykov\n"
							+ "- Material Design Library by navasmdc\n" + "- Jsoup by Jonathan Hedley\n"
							+ "- Android Mail by Jon Simon\n" + "- ASync HTTP by James Smith\n"
							+ "- Appcompat & Play Services by Google\n" + "- Bouncycastle / Spongycastle\n\n"
							+ "Contact: contact@ravenapp.org\n" + "GNU GPL | 2014 - 2015").setIcon(
					R.drawable.ic_action_image_wb_incandescent).show();

			break;
		}
		default: {
			return;
		}
		}
		try {
			FragmentManager fragmentManager = getFragmentManager();

			if (fragment != null) {
				fragment.onAttach(this);
				fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
			}
		} catch (Exception e) {
		}

		if (position < 5 && position > 0) {
			mDrawerList.setItemChecked(position, true);
			setWhiteIcon(position);
			setTitle(((NavItemModel) (mDrawerList.getItemAtPosition(position))).getTitle());
		} else {
			mDrawerList.setItemChecked(position, false);
			setAllIconsBlack();
		}

		mDrawerLayout.closeDrawer(mDrawerList);

	}

	public void setAllIconsBlack() {
		((NavItemModel) mDrawerList.getItemAtPosition(1)).setIcon(R.drawable.ic_nav_message);
		((NavItemModel) mDrawerList.getItemAtPosition(2)).setIcon(R.drawable.ic_nav_message);
		((NavItemModel) mDrawerList.getItemAtPosition(3)).setIcon(R.drawable.ic_nav_message);
		((NavItemModel) mDrawerList.getItemAtPosition(4)).setIcon(R.drawable.ic_nav_message);
	}

	public void setWhiteIcon(int position) {
		if (position >= 5 || position <= 0)
			return;
		setAllIconsBlack();
		((NavItemModel) mDrawerList.getItemAtPosition(position)).setIcon(R.drawable.ic_nav_message_light);
	}

	@Override
	public void setTitle(CharSequence title) {
		mTitle = title;
		getSupportActionBar().setTitle(mTitle);
	}

	@Override
	protected void onPostCreate(Bundle savedInstanceState) {
		super.onPostCreate(savedInstanceState);
		mDrawerToggle.syncState();
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		mDrawerToggle.onConfigurationChanged(newConfig);
	}

	public void whoEncrypts() {
		if (listItems == null)
			return;
		boolean handshake;
		for (int i = 0; i < getListItems().size(); i++) {
			handshake = false;
			if (getListItems().get(i).getLastMessage() == null)
				continue;
			// Pre Shared Exchange
			if ((getListItems().get(i).getLastMessage().toString().length() == 10 || getListItems().get(i)
					.getLastMessage().toString().length() == 9)
					&& getListItems().get(i).getLastMessage().toString().charAt(0) == '%') {
				if (Base64.isPureBase64(getListItems().get(i).getLastMessage().toString().substring(1, 9))) {