content: package com.akdeniz.googleplaycrawler;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.math.BigInteger;
  import java.security.KeyFactory;
  import java.security.KeyManagementException;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.security.PublicKey;
  import java.security.spec.RSAPublicKeySpec;
  import java.util.Arrays;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.StringTokenizer;
  
  import javax.crypto.Cipher;
  import javax.net.ssl.SSLContext;
  import javax.net.ssl.TrustManager;
  
  import org.apache.http.conn.scheme.Scheme;
  import org.apache.http.conn.ssl.SSLSocketFactory;
  
  import com.akdeniz.googleplaycrawler.GooglePlay.AndroidBuildProto;
  import com.akdeniz.googleplaycrawler.GooglePlay.AndroidCheckinProto;
  import com.akdeniz.googleplaycrawler.GooglePlay.AndroidCheckinRequest;
  import com.akdeniz.googleplaycrawler.GooglePlay.DeviceConfigurationProto;
  import com.akdeniz.googleplaycrawler.misc.Base64;
  import com.akdeniz.googleplaycrawler.misc.DummyX509TrustManager;
  
  /**
   * 
   * @author akdeniz
   * 
   */
  public class Utils {
  
      private static final String GOOGLE_PUBLIC_KEY = "AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3"
  	    + "iJIZdodyhKZQrNWp5nKJ3srRXcUW+F1BD3baEVGcmEgqaLZUNBjm057pKRI16kB0YppeGx5qIQ5QjKzsR8ETQbKLNWgRY0Q"
  	    + "RNVz34kMJR3P/LgHax/6rmf5AAAAAwEAAQ==";
  
      /**
       * Parses key-value response into map.
       */
      public static Map<String, String> parseResponse(String response) {
  
  	Map<String, String> keyValueMap = new HashMap<String, String>();
  	StringTokenizer st = new StringTokenizer(response, "\n\r");
  
  	while (st.hasMoreTokens()) {
  	    String[] keyValue = st.nextToken().split("=");
  	    keyValueMap.put(keyValue[0], keyValue[1]);
  	}
  
  	return keyValueMap;
      }
  
      private static PublicKey createKey(byte[] keyByteArray) throws Exception {
  
  	int modulusLength = readInt(keyByteArray, 0);
  	byte[] modulusByteArray = new byte[modulusLength];
  	System.arraycopy(keyByteArray, 4, modulusByteArray, 0, modulusLength);
  	BigInteger modulus = new BigInteger(1, modulusByteArray);
  
  	int exponentLength = readInt(keyByteArray, modulusLength + 4);
  	byte[] exponentByteArray = new byte[exponentLength];
  	System.arraycopy(keyByteArray, modulusLength + 8, exponentByteArray, 0, exponentLength);
  	BigInteger publicExponent = new BigInteger(1, exponentByteArray);
  
  	return KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, publicExponent));
      }
  
      /**
       * Encrypts given string with Google Public Key.
       * 
       */
      public static String encryptString(String str2Encrypt) throws Exception {
  
  	byte[] keyByteArray = Base64.decode(GOOGLE_PUBLIC_KEY, Base64.DEFAULT);
  
  	byte[] header = new byte[5];
  	byte[] digest = MessageDigest.getInstance("SHA-1").digest(keyByteArray);
  	header[0] = 0;
  	System.arraycopy(digest, 0, header, 1, 4);
  
  	PublicKey publicKey = createKey(keyByteArray);
  
  	Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA1ANDMGF1PADDING");
  	byte[] bytes2Encrypt = str2Encrypt.getBytes("UTF-8");
  	int len = ((bytes2Encrypt.length - 1) / 86) + 1;
  	byte[] cryptedBytes = new byte[len * 133];
  
  	for (int j = 0; j < len; j++) {
  	    cipher.init(1, publicKey);
  	    byte[] arrayOfByte4 = cipher.doFinal(bytes2Encrypt, j * 86, (bytes2Encrypt.length - j * 86));
  	    System.arraycopy(header, 0, cryptedBytes, j * 133, header.length);
  	    System.arraycopy(arrayOfByte4, 0, cryptedBytes, j * 133 + header.length, arrayOfByte4.length);
  	}
  	return Base64.encodeToString(cryptedBytes, 10);
      }
  
      private static int readInt(byte[] data, int offset) {
  	return (0xFF & data[offset]) << 24 | (0xFF & data[(offset + 1)]) << 16 | (0xFF & data[(offset + 2)]) << 8
  		| (0xFF & data[(offset + 3)]);
      }
  
      /**
       * Reads all contents of the input stream.
       * 
       */
      public static byte[] readAll(InputStream inputStream) throws IOException {
  
  	ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  	byte[] buffer = new byte[1024];
  
  	int k = 0;
  	for (; (k = inputStream.read(buffer)) != -1;) {
  	    outputStream.write(buffer, 0, k);
  	}
  
  	return outputStream.toByteArray();
      }
  
      public static String bytesToHex(byte[] bytes) {
  	final char[] hexArray = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
  	char[] hexChars = new char[bytes.length * 2];
  	int v;
  	for (int j = 0; j < bytes.length; j++) {
  	    v = bytes[j] & 0xFF;
  	    hexChars[j * 2] = hexArray[v >>> 4];
  	    hexChars[j * 2 + 1] = hexArray[v & 0x0F];
  	}
  	return new String(hexChars);
      }
  
      public static byte[] hexToBytes(String s) {
  	int len = s.length();
  	byte[] data = new byte[len / 2];
  	for (int i = 0; i < len; i += 2) {
  	    data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
  	}
  	return data;
      }
  
      public static Scheme getMockedScheme() throws NoSuchAlgorithmException, KeyManagementException {
  	SSLContext sslcontext = SSLContext.getInstance("TLS");
  
  	sslcontext.init(null, new TrustManager[] { new DummyX509TrustManager() }, null);
  	SSLSocketFactory sf = new SSLSocketFactory(sslcontext);
  	Scheme https = new Scheme("https", 443, sf);
  
  	return https;
      }
  
      /**
       * Generates android checkin request with properties of "Galaxy S3".
       * 
       * <a href=
       * "http://www.glbenchmark.com/phonedetails.jsp?benchmark=glpro25&D=Samsung+GT-I9300+Galaxy+S+III&testgroup=system"
       * > http://www.glbenchmark.com/phonedetails.jsp?benchmark=glpro25&D=Samsung
       * +GT-I9300+Galaxy+S+III&testgroup=system </a>
       */
      public static AndroidCheckinRequest generateAndroidCheckinRequest() {
  
  	return AndroidCheckinRequest
  		.newBuilder()
  		.setId(0)
  		.setCheckin(
  			AndroidCheckinProto
  				.newBuilder()
  				.setBuild(
  					AndroidBuildProto.newBuilder()
  						.setId("samsung/m0xx/m0:4.0.4/IMM76D/I9300XXALF2:user/release-keys")
  						.setProduct("smdk4x12").setCarrier("Google").setRadio("I9300XXALF2")
  						.setBootloader("PRIMELA03").setClient("android-google")
  						.setTimestamp(new Date().getTime() / 1000).setGoogleServices(16).setDevice("m0")
  						.setSdkVersion(16).setModel("GT-I9300").setManufacturer("Samsung")
  						.setBuildProduct("m0xx").setOtaInstalled(false)).setLastCheckinMsec(0)
  				.setCellOperator("310260").setSimOperator("310260").setRoaming("mobile-notroaming")
  				.setUserNumber(0)).setLocale("en_US").setTimeZone("Europe/Istanbul").setVersion(3)
  		.setDeviceConfiguration(getDeviceConfigurationProto()).setFragment(0).build();
      }
  
      public static DeviceConfigurationProto getDeviceConfigurationProto() {
  	return DeviceConfigurationProto
  		.newBuilder()
  		.setTouchScreen(3)
  		.setKeyboard(1)
  		.setNavigation(1)
  		.setScreenLayout(2)
  		.setHasHardKeyboard(false)
  		.setHasFiveWayNavigation(false)
  		.setScreenDensity(320)
  		.setGlEsVersion(131072)
  		.addAllSystemSharedLibrary(
  			Arrays.asList("android.test.runner", "com.android.future.usb.accessory", "com.android.location.provider",
  				"com.android.nfc_extras", "com.google.android.maps", "com.google.android.media.effects",
  				"com.google.widevine.software.drm", "javax.obex"))
  		.addAllSystemAvailableFeature(
  			Arrays.asList("android.hardware.bluetooth", "android.hardware.camera",
  				"android.hardware.camera.autofocus", "android.hardware.camera.flash",
  				"android.hardware.camera.front", "android.hardware.faketouch", "android.hardware.location",
  				"android.hardware.location.gps", "android.hardware.location.network",
  				"android.hardware.microphone", "android.hardware.nfc", "android.hardware.screen.landscape",
  				"android.hardware.screen.portrait", "android.hardware.sensor.accelerometer",
  				"android.hardware.sensor.barometer", "android.hardware.sensor.compass",
  				"android.hardware.sensor.gyroscope", "android.hardware.sensor.light",
  				"android.hardware.sensor.proximity", "android.hardware.telephony",
  				"android.hardware.telephony.gsm", "android.hardware.touchscreen",
  				"android.hardware.touchscreen.multitouch", "android.hardware.touchscreen.multitouch.distinct",
  				"android.hardware.touchscreen.multitouch.jazzhand", "android.hardware.usb.accessory",
  				"android.hardware.usb.host", "android.hardware.wifi", "android.hardware.wifi.direct",
  				"android.software.live_wallpaper", "android.software.sip", "android.software.sip.voip",
  				"com.cyanogenmod.android", "com.cyanogenmod.nfc.enhanced",
  				"com.google.android.feature.GOOGLE_BUILD", "com.nxp.mifare", "com.tmobile.software.themes"))
  		.addAllNativePlatform(Arrays.asList("armeabi-v7a", "armeabi"))
  		.setScreenWidth(720)
  		.setScreenHeight(1184)
  		.addAllSystemSupportedLocale(
  			Arrays.asList("af", "af_ZA", "am", "am_ET", "ar", "ar_EG", "bg", "bg_BG", "ca", "ca_ES", "cs", "cs_CZ",
  				"da", "da_DK", "de", "de_AT", "de_CH", "de_DE", "de_LI", "el", "el_GR", "en", "en_AU", "en_CA",
  				"en_GB", "en_NZ", "en_SG", "en_US", "es", "es_ES", "es_US", "fa", "fa_IR", "fi", "fi_FI", "fr",
  				"fr_BE", "fr_CA", "fr_CH", "fr_FR", "hi", "hi_IN", "hr", "hr_HR", "hu", "hu_HU", "in", "in_ID",
  				"it", "it_CH", "it_IT", "iw", "iw_IL", "ja", "ja_JP", "ko", "ko_KR", "lt", "lt_LT", "lv",
  				"lv_LV", "ms", "ms_MY", "nb", "nb_NO", "nl", "nl_BE", "nl_NL", "pl", "pl_PL", "pt", "pt_BR",
  				"pt_PT", "rm", "rm_CH", "ro", "ro_RO", "ru", "ru_RU", "sk", "sk_SK", "sl", "sl_SI", "sr",
  				"sr_RS", "sv", "sv_SE", "sw", "sw_TZ", "th", "th_TH", "tl", "tl_PH", "tr", "tr_TR", "ug",
  				"ug_CN", "uk", "uk_UA", "vi", "vi_VN", "zh_CN", "zh_TW", "zu", "zu_ZA"))
  		.addAllGlExtension(
  			Arrays.asList("GL_EXT_debug_marker", "GL_EXT_discard_framebuffer", "GL_EXT_multi_draw_arrays",
  				"GL_EXT_shader_texture_lod", "GL_EXT_texture_format_BGRA8888",
  				"GL_IMG_multisampled_render_to_texture", "GL_IMG_program_binary", "GL_IMG_read_format",
  				"GL_IMG_shader_binary", "GL_IMG_texture_compression_pvrtc", "GL_IMG_texture_format_BGRA8888",
  				"GL_IMG_texture_npot", "GL_IMG_vertex_array_object", "GL_OES_EGL_image",
  				"GL_OES_EGL_image_external", "GL_OES_blend_equation_separate", "GL_OES_blend_func_separate",
  				"GL_OES_blend_subtract", "GL_OES_byte_coordinates", "GL_OES_compressed_ETC1_RGB8_texture",
  				"GL_OES_compressed_paletted_texture", "GL_OES_depth24", "GL_OES_depth_texture",
  				"GL_OES_draw_texture", "GL_OES_egl_sync", "GL_OES_element_index_uint",
  				"GL_OES_extended_matrix_palette", "GL_OES_fixed_point", "GL_OES_fragment_precision_high",
  				"GL_OES_framebuffer_object", "GL_OES_get_program_binary", "GL_OES_mapbuffer",
  				"GL_OES_matrix_get", "GL_OES_matrix_palette", "GL_OES_packed_depth_stencil",
  				"GL_OES_point_size_array", "GL_OES_point_sprite", "GL_OES_query_matrix", "GL_OES_read_format",
  				"GL_OES_required_internalformat", "GL_OES_rgb8_rgba8", "GL_OES_single_precision",
  				"GL_OES_standard_derivatives", "GL_OES_stencil8", "GL_OES_stencil_wrap",
  				"GL_OES_texture_cube_map", "GL_OES_texture_env_crossbar", "GL_OES_texture_float",
  				"GL_OES_texture_half_float", "GL_OES_texture_mirrored_repeat", "GL_OES_vertex_array_object",
  				"GL_OES_vertex_half_float")).build();
      }
  }
  