PushUtils.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /**
  2. * Nextcloud Android client application
  3. *
  4. * @author Mario Danic
  5. * Copyright (C) 2017 Mario Danic
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.owncloud.android.utils;
  21. import android.accounts.Account;
  22. import android.accounts.AuthenticatorException;
  23. import android.accounts.OperationCanceledException;
  24. import android.content.Context;
  25. import android.text.TextUtils;
  26. import android.util.Base64;
  27. import android.util.Log;
  28. import com.owncloud.android.MainApp;
  29. import com.owncloud.android.R;
  30. import com.owncloud.android.authentication.AccountUtils;
  31. import com.owncloud.android.db.PreferenceManager;
  32. import com.owncloud.android.lib.common.OwnCloudAccount;
  33. import com.owncloud.android.lib.common.OwnCloudClient;
  34. import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
  35. import com.owncloud.android.lib.common.operations.RemoteOperation;
  36. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  37. import com.owncloud.android.lib.common.utils.Log_OC;
  38. import com.owncloud.android.lib.resources.notifications.RegisterAccountDeviceForNotificationsOperation;
  39. import com.owncloud.android.lib.resources.notifications.RegisterAccountDeviceForProxyOperation;
  40. import com.owncloud.android.lib.resources.notifications.models.PushResponse;
  41. import java.io.File;
  42. import java.io.FileInputStream;
  43. import java.io.FileNotFoundException;
  44. import java.io.FileOutputStream;
  45. import java.io.IOException;
  46. import java.security.Key;
  47. import java.security.KeyFactory;
  48. import java.security.KeyPair;
  49. import java.security.KeyPairGenerator;
  50. import java.security.MessageDigest;
  51. import java.security.NoSuchAlgorithmException;
  52. import java.security.PublicKey;
  53. import java.security.spec.InvalidKeySpecException;
  54. import java.security.spec.PKCS8EncodedKeySpec;
  55. import java.security.spec.X509EncodedKeySpec;
  56. public class PushUtils {
  57. private static final String TAG = "PushUtils";
  58. private static final String KEYPAIR_FOLDER = "nc-keypair";
  59. private static final String KEYPAIR_FILE_NAME = "push_key";
  60. private static final String KEYPAIR_PRIV_EXTENSION = ".priv";
  61. private static final String KEYPAIR_PUB_EXTENSION = ".pub";
  62. public static String generateSHA512Hash(String pushToken) {
  63. MessageDigest messageDigest = null;
  64. try {
  65. messageDigest = MessageDigest.getInstance("SHA-512");
  66. messageDigest.update(pushToken.getBytes());
  67. return bytesToHex(messageDigest.digest());
  68. } catch (NoSuchAlgorithmException e) {
  69. Log_OC.d(TAG, "SHA-512 algorithm not supported");
  70. }
  71. return "";
  72. }
  73. private static String bytesToHex(byte[] bytes) {
  74. StringBuilder result = new StringBuilder();
  75. for (byte individualByte : bytes) {
  76. result.append(Integer.toString((individualByte & 0xff) + 0x100, 16)
  77. .substring(1));
  78. }
  79. return result.toString();
  80. }
  81. public static int generateRsa2048KeyPair() {
  82. String keyPath = MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator
  83. + KEYPAIR_FOLDER;
  84. ;
  85. String privateKeyPath = keyPath + File.separator + KEYPAIR_FILE_NAME + KEYPAIR_PRIV_EXTENSION;
  86. String publicKeyPath = keyPath + File.separator + KEYPAIR_FILE_NAME + KEYPAIR_PUB_EXTENSION;
  87. File keyPathFile = new File(keyPath);
  88. if (!new File(privateKeyPath).exists() && !new File(publicKeyPath).exists()) {
  89. try {
  90. if (!keyPathFile.exists()) {
  91. keyPathFile.mkdir();
  92. }
  93. KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
  94. keyGen.initialize(2048);
  95. KeyPair pair = keyGen.generateKeyPair();
  96. int statusPrivate = saveKeyToFile(pair.getPrivate(), privateKeyPath);
  97. int statusPublic = saveKeyToFile(pair.getPublic(), publicKeyPath);
  98. if (statusPrivate == 0 && statusPublic == 0) {
  99. // all went well
  100. return 0;
  101. } else {
  102. return -2;
  103. }
  104. } catch (NoSuchAlgorithmException e) {
  105. Log_OC.d(TAG, "RSA algorithm not supported");
  106. }
  107. } else {
  108. // we already have the key
  109. return -1;
  110. }
  111. // we failed to generate the key
  112. return -2;
  113. }
  114. public static void pushRegistrationToServer() {
  115. String token = PreferenceManager.getPushToken(MainApp.getAppContext());
  116. if (!TextUtils.isEmpty(MainApp.getAppContext().getResources().getString(R.string.push_server_url)) &&
  117. !TextUtils.isEmpty(token)) {
  118. PushUtils.generateRsa2048KeyPair();
  119. String pushTokenHash = PushUtils.generateSHA512Hash(token).toUpperCase();
  120. PublicKey devicePublicKey = (PublicKey) PushUtils.readKeyFromFile(true);
  121. if (devicePublicKey != null) {
  122. byte[] publicKeyBytes = Base64.encode(devicePublicKey.getEncoded(), 0);
  123. String publicKey = new String(publicKeyBytes);
  124. Context context = MainApp.getAppContext();
  125. for (Account account : AccountUtils.getAccounts(context)) {
  126. try {
  127. OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
  128. OwnCloudClient mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
  129. getClientFor(ocAccount, context);
  130. RemoteOperation registerAccountDeviceForNotificationsOperation =
  131. new RegisterAccountDeviceForNotificationsOperation(pushTokenHash,
  132. publicKey, context.getResources().getString(R.string.push_server_url));
  133. RemoteOperationResult remoteOperationResult = registerAccountDeviceForNotificationsOperation.
  134. execute(mClient);
  135. if (remoteOperationResult.isSuccess()) {
  136. PushResponse pushResponse = remoteOperationResult.getPushResponseData();
  137. RemoteOperation registerAccountDeviceForProxyOperation = new
  138. RegisterAccountDeviceForProxyOperation(
  139. context.getResources().getString(R.string.push_server_url),
  140. token, pushResponse.getDeviceIdentifier(), pushResponse.getSignature(),
  141. pushResponse.getPublicKey());
  142. remoteOperationResult = registerAccountDeviceForProxyOperation.execute(mClient);
  143. Log.d("THIS IS MARIO", "MARIO");
  144. PreferenceManager.setPushTokenLastSentTime(MainApp.getAppContext(),
  145. System.currentTimeMillis());
  146. }
  147. } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) {
  148. Log_OC.d(TAG, "Failed to find an account");
  149. } catch (AuthenticatorException e) {
  150. Log_OC.d(TAG, "Failed via AuthenticatorException");
  151. } catch (IOException e) {
  152. Log_OC.d(TAG, "Failed via IOException");
  153. } catch (OperationCanceledException e) {
  154. Log_OC.d(TAG, "Failed via OperationCanceledException");
  155. }
  156. }
  157. }
  158. }
  159. }
  160. public static Key readKeyFromFile(boolean readPublicKey) {
  161. String keyPath = MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator
  162. + KEYPAIR_FOLDER;
  163. ;
  164. String privateKeyPath = keyPath + File.separator + KEYPAIR_FILE_NAME + KEYPAIR_PRIV_EXTENSION;
  165. String publicKeyPath = keyPath + File.separator + KEYPAIR_FILE_NAME + KEYPAIR_PUB_EXTENSION;
  166. String path;
  167. if (readPublicKey) {
  168. path = publicKeyPath;
  169. } else {
  170. path = privateKeyPath;
  171. }
  172. FileInputStream fileInputStream = null;
  173. try {
  174. fileInputStream = new FileInputStream(path);
  175. byte[] bytes = new byte[fileInputStream.available()];
  176. fileInputStream.read(bytes);
  177. fileInputStream.close();
  178. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  179. if (readPublicKey) {
  180. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
  181. return keyFactory.generatePublic(keySpec);
  182. } else {
  183. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
  184. return keyFactory.generatePrivate(keySpec);
  185. }
  186. } catch (FileNotFoundException e) {
  187. Log_OC.d(TAG, "Failed to find path while reading the Key");
  188. } catch (IOException e) {
  189. Log_OC.d(TAG, "IOException while reading the key");
  190. } catch (InvalidKeySpecException e) {
  191. Log_OC.d(TAG, "InvalidKeySpecException while reading the key");
  192. } catch (NoSuchAlgorithmException e) {
  193. Log_OC.d(TAG, "RSA algorithm not supported");
  194. }
  195. return null;
  196. }
  197. private static int saveKeyToFile(Key key, String path) {
  198. byte[] encoded = key.getEncoded();
  199. FileOutputStream keyFileOutputStream = null;
  200. try {
  201. if (!new File(path).exists()) {
  202. new File(path).createNewFile();
  203. }
  204. keyFileOutputStream = new FileOutputStream(path);
  205. keyFileOutputStream.write(encoded);
  206. keyFileOutputStream.close();
  207. return 0;
  208. } catch (FileNotFoundException e) {
  209. Log_OC.d(TAG, "Failed to save key to file");
  210. } catch (IOException e) {
  211. Log_OC.d(TAG, "Failed to save key to file via IOException");
  212. }
  213. return -1;
  214. }
  215. }