Crypto chat with VK API Technologies

Омаров Магомед Шамилович

Студент 4го курса У-351гр

ФКТВТиЭ

Крипто чат с использованием технологий VK API

Crypto chat with VK API Technologies

Аннотация. Статья посвящена описанию программной системы, разработанной на языке Java для мобильной платформы Android, для шифрования передаваемой текстовой информации с использованием ассиметричного или симметричного алгоритма шифрования с использованием технологий VK API

Ключевые слова: Информационная безопасность, крипто чат, криптография, шифрование, RSA, XOR, DES, AES

Description. The article describes a software system developed in Java for the Android mobile platform, which encrypts the messages using asymmetrical or symmetrical encryption with VK API technologies

Keywords: Information security, crypto chat, cryptography, encryption, RSA, XOR, DES, AES

Программная система состоит из сервера VK и клиентского мобильного приложения, разработанного для платформы Android.

API (application programming interface) — это посредник между разработчиком приложений и какой-либо средой, с которой это приложение должно взаимодействовать. API упрощает создание кода, поскольку предоставляет набор готовых классов, функций или структур для работы с имеющимися данными.

1. Методы и объекты

API ВКонтакте — это интерфейс, который позволяет получать информацию из базы данных vk.com с помощью http-запросов к специальному серверу. Вам не нужно знать в подробностях, как устроена база, из каких таблиц и полей каких типов она состоит — достаточно того, что API-запрос об этом «знает». Синтаксис запросов и тип возвращаемых ими данных строго определены на стороне самого сервиса.

Например, для получения данных о пользователе с идентификатором 210700286 необходимо составить запрос такого вида:

 

https://api.vk.com/method/users.get?user_id=210700286&v=5.52

 

Рассмотрим отдельно все его составляющие.

https:// — протокол соединения.

api.vk.com/methods — адрес API-сервиса.

users.get — название метода API ВКонтакте. Методы представляют собой условные команды, которые соответствуют той или иной операции с базой данных — получение информации, запись или удаление. Например, users.get — метод для получения информации о пользователе, video.add — метод для добавления видеозаписи в свой список, likes.delete — метод для удаления отметки «Мне нравится».

 

Все методы разделены на секции. Например, для работы с сообществами Вам нужны методы секции groups, для работы с фотографиями — photos, и так далее. Полный список методов по секциям доступен на этой странице.

?user_id=210700286&v=5.52 — параметры запроса. После названия метода нужно передать его входные данные (если они есть) — как обычные GET-параметры в http-запросе. В нашем примере мы сообщаем серверу, что хотим получить данные о пользователе с id=210700286 и формат этих данных должен соответствовать версии API 5.52 (о версиях мы еще поговорим позже). Входные параметры всегда перечислены на странице с описанием метода.

 

В ответ сервер вернет JSON-объект с запрошенными данными (или сообщение об ошибке, если что-то пошло не так). JSON — это формат записи данных в виде пар «имя свойства»: «значение».

 

Ответ на наш запрос выглядит так:

{"response":[{"id":210700286,"first_name":"Lindsey","last_name":"Stirling"}]}

Структура ответа каждого метода также строго задана, и при работе с API Вы заранее знаете, что в поле id придет число, а в поле first_name — строка. Такие правила оговариваются на страницах с описанием метода и соответствующих объектов, которые он возвращает в ответе. Например, users.get — здесь описаны входные параметры метода и структура его ответа, а здесь — user подробно расписано каждое поле объекта из ответа.

 

Объект из ответа может быть не уникален для конкретного метода. Например, объект пользователя с набором полей, содержащих данные о его образовании, возрасте, интересах, может возвращаться в ответе от методов users.get, users.search, groups.getMembers и еще нескольких.

 

ВКонтакте — социальная сеть, где есть дружеские связи, настройки приватности и даже черные списки. Многое зависит от того, кто просматривает страницу: кто-то увидит на ней всю ту же информацию, что и владелец, а кто-то — лишь общедоступные данные.

 

В API этот принцип сохраняется. Если Вы скрыли список своих групп от не-друзей, то и через API Ваши не-друзья не должны его увидеть. Поэтому почти все методы требуют авторизации пользователя перед началом работы.

В общем случае для идентификации в API используется специальный ключ доступа, который называется access_token. Токен — это строка из цифр и латинских букв, которую Вы передаете на сервер вместе с запросом. Из этой строки сервер получает всю нужную ему информацию. Есть разные способы получения токена, более того, он может быть выдан не только пользователю, но и сообществу, и сразу всему приложению.

В данной программой системы использован самый простой способ Implicit flow.

Программный код для получения токена имеет след вид :

  1. public class auth extends AppCompatActivity {
  2. WebView wb = (WebView) findViewById(R.id.web);
  3. WebSettings webSettings = wb.getSettings();
  4. webSettings.setJavaScriptEnabled(true);
  5. SimpleWebViewClient webViewClient = new SimpleWebViewClient();
  6. wb.setWebViewClient(webViewClient);
  7. wb.loadUrl("https://oauth.vk.com/authorize?client_id=5213947&redirect_uri=oauth.vk.com/blank.html&display=mobile&scope=4098&&response_type=token&v=5.58");
  8. …}

После перехода по данному адресу браузер созданный внутри приложения выведет сообщение , предостерегающее нас от передачи адреса браузера на сторонние сервисы , т.к. есть риск утери данных

Для получения токена из адресной строки используется функция GetToken.

  1. public void GetToken (View view) {
  2. WebView wb = (WebView) findViewById(R.id.web);
  3. token = wb.getUrl().toString().split("=")[1].toString().split("&")[0];
  4. Snackbar.make(view, "Получаю токен...", Snackbar.LENGTH_LONG).setAction("Action", null).show();

5. wb.setVisibility(View.INVISIBLE); }

Токен — это Ваш ключ доступа. При выполнении определенных условий человек, получивший Ваш токен, может нанести существенный ущерб Вашим данным и данным других людей. Поэтому очень важно не передавать свой токен третьим лицам. В данной системе токен хранится в глобальной переменной token .

 

Поле expires_in содержит время жизни токена в секундах. 86400 секунд — это ровно сутки. Через сутки полученный токен перестанет действовать, для продолжения работы нужно будет получить новый. Есть возможность получить токен без срока действия — для этого в scope добавьте значение offline.

Поле user_id содержит id пользователя, для которого получен токен.

 

Для загрузки списка друзей используем подкласс супер класса AssyncTask GetFriends.

  1. class GetFriend extends AsyncTask<String, Void, String> {
  2. @Override
  3. protected void onPreExecute() {
  4. super.onPreExecute();
  5. }
  6. @Override
  7. protected String doInBackground(String... params) {
  8. StringBuilder sb = new StringBuilder();
  9. try {
  10. HttpURLConnection connection = (HttpURLConnection) newURL(params[0]).openConnection();
  11. connection.connect();
  12. InputStream inputStream =connection.getInputStream();
  13. BufferedReader reader = newBufferedReader(new InputStreamReader(inputStream));
  14. String line = null;
  15. while ((line = reader.readLine()) !=null) {
  16. sb.append(line);
  17. }
  18. TimeUnit.SECONDS.sleep(2);
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. } catch (MalformedURLException e) {
  22. e.printStackTrace();
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. return sb.toString();
  27. }
  28. @Override
  29. protected void onPostExecute(String result) {
  30. String friendsCount = null;
  31. String posts = "";
  32. super.onPostExecute(result);
  33. try {
  34. int i;
  35. JSONObject obj = new JSONObject(result);
  36. friendsCount = obj.getJSONObject("response").getString("count");
  37. JSONArray arr = obj.getJSONObject("response").getJSONArray("items");
  38. friends = new String[Integer.parseInt(friendsCount)];
  39. for (i = 0; i < arr.length(); i++) {
  40. friends[i] =
  41. "id" +arr.getJSONObject(i).getString("id")
  42. + ":" + '\n' +arr.getJSONObject(i).getString("first_name")
  43. + " " +arr.getJSONObject(i).getString("last_name")
  44. + " <<" +arr.getJSONObject(i).getString("online") + ">>";
  45. friends[i] =friends[i].replace("<<1>>", " online");
  46. friends[i] =friends[i].replace("<<0>>", " offline");
  47. }
  48. showDialog(55);
  49. } catch (JSONException e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. }

Список друзей записан в глобальный массив friends.

Для получение истории сообщений используется подкласс суперкласса AssyncTask getHistory.

1.

  1. class GetHistory extends AsyncTask<String, Void, String> {
  2. @Override
  3. protected void onPreExecute() {
  4. super.onPreExecute();
  5. }
  6. @Override
  7. protected String doInBackground(String... params) {
  8. StringBuilder sb = new StringBuilder();
  9. try {
  10. HttpURLConnection connection = (HttpURLConnection) newURL(params[0]).openConnection();
  11. connection.connect();
  12. InputStream inputStream =connection.getInputStream();
  13. BufferedReader reader = newBufferedReader(newInputStreamReader(inputStream));
  14. String line = null;
  15. while ((line =reader.readLine()) != null) {
  16. sb.append(line);
  17. }
  18. TimeUnit.SECONDS.sleep(2);
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. } catch (MalformedURLException e) {
  22. e.printStackTrace();
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. return sb.toString();
  27. }
  28. @Override
  29. protected void onPostExecute(String result) {
  30. String messegesCount = null;
  31. String posts = "";
  32. super.onPostExecute(result);
  33. ////&#1087;&#1072;&#1088;&#1089;&#1080;&#1085;&#1075;
  34. try {
  35. JSONObject obj = new JSONObject(result);
  36. messegesCount = obj.getJSONObject("response").getString("count");
  37. JSONArray arr = obj.getJSONObject("response").getJSONArray("items");
  38. for (int i = 0; i <arr.length(); i++) {
  39. String msg =arr.getJSONObject(i).getString("body");
  40. if(msg.contains(":CRMSGWLDMR:")) {
  41. msg =decrypt(msg.replace(":CRMSGWLDMR:", "") , key).replace("+"," ");
  42. }
  43. if(arr.getJSONObject(i).getString("from_id").equals(user_id))
  44. posts +=" Собеседник:" + msg + "\n";
  45. else
  46. posts += "Я" + msg + "\n";
  47. }
  48. } catch (JSONException e) {
  49. e.printStackTrace();
  50. }
  51. if (result.contains("count")) {
  52. final AlertDialog.Builder builder = new AlertDialog.Builder(auth.this);
  53. if (!user_id_name.equals(null))
  54. builder.setTitle("История" + user_id_name);

На 50й строчке кода идет проверка на наличие в полученном сообщение флага «:CRMSGWLDMR:» он используется для того чтобы систем а поняла что сообщение зашифровано и есть необхожимость расшифровать сообщение (52-я строчка кода )

Для получение истории сообщений используется подкласс суперкласса AssyncTask sendMessage.

  1. class SendMessage extends AsyncTask<String, Void, String> {
  2. @Override
  3. protected void onPreExecute() {
  4. super.onPreExecute();
  5. }
  6. @Override
  7. protected String doInBackground(String... params) {
  8. StringBuilder sb = new StringBuilder();
  9. try {
  10. HttpURLConnection connection = (HttpURLConnection) newURL(params[0]).openConnection();
  11. connection.connect();
  12. InputStream inputStream =connection.getInputStream();
  13. BufferedReader reader = newBufferedReader(newInputStreamReader(inputStream));
  14. String line = null;
  15. while ((line =reader.readLine()) != null) {
  16. sb.append(line);
  17. }
  18. TimeUnit.SECONDS.sleep(2);
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. } catch (MalformedURLException e){
  22. e.printStackTrace();
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. return sb.toString();
  27. }
  28. @Override
  29. protected void onPostExecute(String result) {
  30. GetHistory("https://api.vk.com/method/messages.getHistory?offset=0&count=5&user_id="+ user_id + "&access_token=" + token + "&v=5.59");
  31. }
  32. }

Для шифрования и дешифрованния передаваемых или получаемых сообщений в данной программной системе используются модули с алгоритмом шифрования XOR. Стоит отметить что данные модули легко заменяемы в программном коде .

  1. public static String xor_encrypt(String message, String key){
  2. try {
  3. if (message==null || key==null ) return null;
  4. char[] keys=key.toCharArray();
  5. char[] mesg=message.toCharArray();
  6. BASE64Encoder encoder = new BASE64Encoder();
  7. int ml=mesg.length;
  8. int kl=keys.length;
  9. char[] newmsg=new char[ml];
  10. for (int i=0; i<ml; i++){
  11. newmsg[i]=(char)(mesg[i]^keys[i%kl]);
  12. }
  13. mesg=null;
  14. keys=null;
  15. String temp = newString(newmsg);
  16. return new String(newBASE64Encoder().encodeBuffer(temp.getBytes()));
  17. }
  18. catch ( Exception e ) {
  19. return null;
  20. }
  21. }
  22. public static String xor_decrypt(String message, String key){
  23. try {
  24. if (message==null || key==null ) return null;
  25. BASE64Decoder decoder = new BASE64Decoder();
  26. char[] keys=key.toCharArray();
  27. message = new String(decoder.decodeBuffer(message));
  28. char[] mesg=message.toCharArray();
  29. int ml=mesg.length;
  30. int kl=keys.length;
  31. char[] newmsg=new char[ml];
  32. for (int i=0; i<ml; i++){
  33. newmsg[i]=(char)(mesg[i]^keys[i%kl]);
  34. }
  35. mesg=null; keys=null;
  36. return new String(newmsg);
  37. }
  38. catch ( Exception e ) {
  39. return null;
  40. }
  41. }