Commit 257d1e51 authored by Ahmad Nemati's avatar Ahmad Nemati

init

parent 083c7735
......@@ -35,6 +35,11 @@ dependencies {
// excluding org.json which is provided by Android
exclude group: 'org.json', module: 'json'
}
implementation 'com.google.code.gson:gson:2.8.5'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
}
android {
......
......@@ -5,9 +5,19 @@ import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.EditText;
import org.telegram.io.Proxy;
import org.telegram.messenger.R;
import org.telegram.tgnet.ConnectionsManager;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.Subscriber;
import rx.schedulers.Schedulers;
public class MainActivity extends AppCompatActivity {
EditText editText;
......@@ -16,16 +26,16 @@ public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = findViewById(R.id.editText);
connectionsManager = new ConnectionsManager();
ConnectionsManager.setProxySettings("52.47.197.51", 1128, "b40bcc741a4ae965c3aa200fed2637ca");
findViewById(R.id.button).setOnClickListener(view -> {
connectionsManager.checkProxy("52.47.197.51", 1128, "b40bcc741a4ae965c3aa200fed2637ca"
, time -> Log.e("HerePing", String.valueOf(time)));
});
}
}
package org.telegram.io;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import android.util.Base64;
public class CryptLib {
/**
* Encryption mode enumeration
*/
private enum EncryptMode {
ENCRYPT, DECRYPT
}
// cipher to be used for encryption and decryption
private Cipher _cx;
// encryption key and initialization vector
private byte[] _key, _iv;
public CryptLib() throws NoSuchAlgorithmException, NoSuchPaddingException {
// initialize the cipher with transformation AES/CBC/PKCS5Padding
_cx = Cipher.getInstance("AES/CBC/PKCS5Padding");
_key = new byte[32]; //256 bit key space
_iv = new byte[16]; //128 bit IV
}
/**
*
* @param inputText Text to be encrypted or decrypted
* @param encryptionKey Encryption key to used for encryption / decryption
* @param mode specify the mode encryption / decryption
* @param initVector Initialization vector
* @return encrypted or decrypted bytes based on the mode
* @throws UnsupportedEncodingException
* @throws InvalidKeyException
* @throws InvalidAlgorithmParameterException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
private byte[] encryptDecrypt(String inputText, String encryptionKey,
EncryptMode mode, String initVector) throws UnsupportedEncodingException,
InvalidKeyException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException {
int len = encryptionKey.getBytes("UTF-8").length; // length of the key provided
if (encryptionKey.getBytes("UTF-8").length > _key.length)
len = _key.length;
int ivlength = initVector.getBytes("UTF-8").length;
if(initVector.getBytes("UTF-8").length > _iv.length)
ivlength = _iv.length;
System.arraycopy(encryptionKey.getBytes("UTF-8"), 0, _key, 0, len);
System.arraycopy(initVector.getBytes("UTF-8"), 0, _iv, 0, ivlength);
SecretKeySpec keySpec = new SecretKeySpec(_key, "AES"); // Create a new SecretKeySpec for the specified key data and algorithm name.
IvParameterSpec ivSpec = new IvParameterSpec(_iv); // Create a new IvParameterSpec instance with the bytes from the specified buffer iv used as initialization vector.
// encryption
if (mode.equals(EncryptMode.ENCRYPT)) {
// Potentially insecure random numbers on Android 4.3 and older. Read for more info.
// https://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html
_cx.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);// Initialize this cipher instance
return _cx.doFinal(inputText.getBytes("UTF-8")); // Finish multi-part transformation (encryption)
} else {
_cx.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);// Initialize this cipher instance
byte[] decodedValue = Base64.decode(inputText.getBytes(), Base64.DEFAULT);
return _cx.doFinal(decodedValue); // Finish multi-part transformation (decryption)
}
}
/***
* This function computes the SHA256 hash of input string
* @param text input text whose SHA256 hash has to be computed
* @param length length of the text to be returned
* @return returns SHA256 hash of input text
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
private static String SHA256 (String text, int length) throws NoSuchAlgorithmException, UnsupportedEncodingException {
String resultString;
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(text.getBytes("UTF-8"));
byte[] digest = md.digest();
StringBuilder result = new StringBuilder();
for (byte b : digest) {
result.append(String.format("%02x", b)); //convert to hex
}
if(length > result.toString().length()) {
resultString = result.toString();
} else {
resultString = result.toString().substring(0, length);
}
return resultString;
}
public String encryptPlainText(String plainText, String key, String iv) throws Exception {
byte[] bytes = encryptDecrypt(plainText, CryptLib.SHA256(key, 32), EncryptMode.ENCRYPT, iv);
return Base64.encodeToString(bytes, Base64.DEFAULT);
}
public String decryptCipherText(String cipherText, String key, String iv) throws Exception {
byte[] bytes = encryptDecrypt(cipherText, CryptLib.SHA256(key, 32), EncryptMode.DECRYPT, iv);
return new String(bytes);
}
public String encryptPlainTextWithRandomIV(String plainText, String key) throws Exception {
byte[] bytes = encryptDecrypt(generateRandomIV16() + plainText, CryptLib.SHA256(key, 32), EncryptMode.ENCRYPT, generateRandomIV16());
return Base64.encodeToString(bytes, Base64.DEFAULT);
}
public String decryptCipherTextWithRandomIV(String cipherText, String key) throws Exception {
byte[] bytes = encryptDecrypt(cipherText, CryptLib.SHA256(key, 32), EncryptMode.DECRYPT, generateRandomIV16());
String out = new String(bytes);
return out.substring(16, out.length());
}
/**
* Generate IV with 16 bytes
* @return
*/
public String generateRandomIV16() {
SecureRandom ranGen = new SecureRandom();
byte[] aesKey = new byte[16];
ranGen.nextBytes(aesKey);
StringBuilder result = new StringBuilder();
for (byte b : aesKey) {
result.append(String.format("%02x", b)); //convert to hex
}
if (16 > result.toString().length()) {
return result.toString();
} else {
return result.toString().substring(0, 16);
}
}
}
\ No newline at end of file
package org.telegram.io;
import android.util.Log;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by Ahmad Nemati on 1/26/19.
*/
public class Proxy {
@SerializedName("id")
@Expose
private int id;
@SerializedName("ip")
@Expose
private String ip;
@SerializedName("port")
@Expose
private int port;
@SerializedName("secret")
@Expose
private String secret;
@SerializedName("owner")
@Expose
private int owner;
@SerializedName("delete")
@Expose
private int delete;
@SerializedName("status")
@Expose
private String status;
@SerializedName("createdAt")
@Expose
private String createdAt;
@SerializedName("updatedAt")
@Expose
private String updatedAt;
@SerializedName("ping")
@Expose
private long ping = 0;
@SerializedName("messageId")
@Expose
private String messageId;
private int retry = 0;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public int getOwner() {
return owner;
}
public void setOwner(int owner) {
this.owner = owner;
}
public int getDelete() {
return delete;
}
public void setDelete(int delete) {
this.delete = delete;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}
public long getPing() {
return ping;
}
public void setPing(long ping) {
this.ping = ping;
}
public String getMessageId() {
return messageId;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public int getRetry() {
return retry;
}
public void setRetry(int retry) {
this.retry = retry;
}
}
......@@ -23,7 +23,7 @@ public class SingletonSocket {
try {
IO.Options opts = new IO.Options();
opts.forceNew = true;
opts.reconnection = false;
opts.reconnection = true;
opts.secure = true;
mSocket = IO.socket(Constants.CHAT_SERVER_URL,opts);
} catch (URISyntaxException e) {
......
package org.telegram.io;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Ahmad Nemati on 1/28/19.
*/
public class Utils {
public static List<Proxy> removeDuplicator(List<Proxy> proxyList) {
for (int i = 0; i < proxyList.size(); i++) {
Boolean needRemove = false;
List<Proxy> newList = new ArrayList<>(proxyList);
for (int j = 0; j < newList.size(); j++) {
if (i == j)
continue;
if (proxyList.get(i).getIp().equals(newList.get(j).getIp()) &&
proxyList.get(i).getPort() == newList.get(j).getPort() &&
proxyList.get(i).getSecret().equals(newList.get(j).getSecret()))
{
needRemove = true;
break;
}
}
if (needRemove) {
proxyList.remove(i);
}
}
return proxyList;
}
}
......@@ -6,19 +6,51 @@ import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.telegram.io.Constants;
import org.telegram.io.CryptLib;
import org.telegram.io.Proxy;
import org.telegram.io.SingletonSocket;
import org.telegram.io.Utils;
import org.telegram.tgnet.ConnectionsManager;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.crypto.NoSuchPaddingException;
import io.socket.emitter.Emitter;
import rx.Observable;
import rx.Subscriber;
import rx.schedulers.Schedulers;
/**
* Created by Ahmad Nemati on 1/17/19.
*/
public class SocketService extends Service implements Emitter.Listener {
private Gson gson;
private CryptLib cryptLib;
private static final String key = "6*sN_rZxHD4!X$=T";
ConnectionsManager connectionsManager;
Boolean work = false;
@Override
public void onCreate() {
super.onCreate();
gson = new Gson();
connectionsManager = new ConnectionsManager();
try {
cryptLib = new CryptLib();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
SingletonSocket.getInstance().getSocket().on(Constants.GET_JSON_FOR_PING, this);
SingletonSocket.getInstance().getSocket().connect();
......@@ -37,7 +69,102 @@ public class SocketService extends Service implements Emitter.Listener {
@Override
public void call(Object... args) {
if (args.length == 0) return;
if (work) {
Log.e("Ping", "Reject Worker is work!");
return;
}
Log.e("Received from server", String.valueOf(args.length));
String chiper = String.valueOf(args[0]);
try {
String decrypt = cryptLib.decryptCipherTextWithRandomIV(chiper, key);
List<Proxy> proxyList = gson.fromJson(decrypt, new TypeToken<List<Proxy>>() {
}.getType());
proxyList = Utils.removeDuplicator(proxyList);
Log.e("PingSizeOfRes", String.valueOf(proxyList.size()));
work = true;
initCheckProxy(proxyList);
} catch (Exception e) {
e.printStackTrace();
}
}
public Observable<Proxy> getPingServerObservable(Proxy proxy) {
return Observable.create(subscriber -> {
ConnectionsManager.setProxySettings(proxy.getIp(), proxy.getPort(), proxy.getSecret());
connectionsManager.checkProxy(proxy.getIp(), proxy.getPort(), proxy.getSecret()
, time -> {
proxy.setPing(time);
subscriber.onNext(proxy);
subscriber.onCompleted();
});
});
}
public void initCheckProxy(List<Proxy> proxyList) {
Observable.from(proxyList)
.subscribeOn(Schedulers.io())
.concatMap(proxy -> getPingServerObservable(proxy)
.subscribeOn(Schedulers.io())
.timeout(5, TimeUnit.SECONDS)
.onErrorResumeNext(t ->
{
if (proxy.getRetry() == 1) {
proxy.setPing(0);
return Observable.just(proxy);
}
Log.e("Ping","Try Retry");
proxy.setRetry(1);
return getPingServerObservable(proxy)
.subscribeOn(Schedulers.newThread())
.timeout(5, TimeUnit.SECONDS)
.onErrorResumeNext(throwable -> {
proxy.setPing(0);
return Observable.just(proxy);
});
}))
.toList()
.subscribe(new Subscriber<List<Proxy>>() {
@Override
public void onCompleted() {
work = false;
//Log.e("Ping", "Done");
}
@Override
public void onError(Throwable e) {
work = false;
}
@Override
public void onNext(List<Proxy> proxyList) {
work = false;
Log.e("Ping", "Task Check Finished for " + proxyList.size() + " Ips");
try {
String cipherText = cryptLib.encryptPlainTextWithRandomIV(gson.toJson(proxyList), key);
SingletonSocket.getInstance().getSocket().emit("checkping", cipherText);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment