Advertisement
Guest User

Untitled

a guest
Jul 14th, 2016
234
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.69 KB | None | 0 0
  1. if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  2. ...
  3. } else {
  4. ...
  5. }
  6.  
  7. 05-31 14:35:50.924 11941-11941/com.example.app E/dalvikvm: Could not find class 'android.security.keystore.KeyGenParameterSpec$Builder', referenced from method com.example.app.ui.fragment.util.LoginFragment.createKeyPair
  8. 05-31 14:35:50.924 11941-11941/com.example.app W/dalvikvm: VFY: unable to resolve new-instance 263 (Landroid/security/keystore/KeyGenParameterSpec$Builder;) in Lcom/example/app/ui/fragment/util/LoginFragment;
  9. 05-31 14:35:50.924 11941-11941/com.example.app D/dalvikvm: VFY: replacing opcode 0x22 at 0x000c
  10. 05-31 14:35:50.924 11941-11941/com.example.app W/dalvikvm: VFY: unable to resolve exception class 265 (Landroid/security/keystore/KeyPermanentlyInvalidatedException;)
  11. 05-31 14:35:50.924 11941-11941/com.example.app W/dalvikvm: VFY: unable to find exception handler at addr 0x3f
  12. 05-31 14:35:50.924 11941-11941/com.example.app W/dalvikvm: VFY: rejected Lcom/example/app/ui/fragment/util/LoginFragment;.initializeCipher (I)Z
  13. 05-31 14:35:50.924 11941-11941/cp W/dalvikvm: VFY: rejecting opcode 0x0d at 0x003f
  14. 05-31 14:35:50.924 11941-11941/com.example.app W/dalvikvm: VFY: rejected Lcom/example/app/ui/fragment/util/LoginFragment;.initializeCipher (I)Z
  15. 05-31 14:35:50.924 11941-11941/com.example.app W/dalvikvm: Verifier rejected class Lcom/example/app/ui/fragment/util/LoginFragment;
  16. 05-31 14:35:50.924 11941-11941/com.example.app D/AndroidRuntime: Shutting down VM
  17. 05-31 14:35:50.924 11941-11941/com.example.app W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x9cca9b20)
  18. 05-31 14:35:50.934 11941-11941/com.example.app E/AndroidRuntime: FATAL EXCEPTION: main
  19. Process: com.example.app, PID: 11941 java.lang.VerifyError: com/example/app/ui/fragment/util/LoginFragment
  20. at com.example.app.util.NetworkUtility.login(NetworkUtility.java:41)
  21. at com.example.app.ui.activity.AbstractNavActivity.onOptionsItemSelected(AbstractNavActivity.java:68)
  22. at android.app.Activity.onMenuItemSelected(Activity.java:2600)
  23. at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:403)
  24. at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:189)
  25. at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:100)
  26. at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:100)
  27. at android.support.v7.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:69)
  28. at android.support.v7.widget.Toolbar$1.onMenuItemClick(Toolbar.java:169)
  29. at android.support.v7.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:760)
  30. at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:811)
  31. at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
  32. at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:958)
  33. at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:948)
  34. at android.support.v7.view.menu.MenuPopupHelper.onItemClick(MenuPopupHelper.java:191)
  35. at android.widget.AdapterView.performItemClick(AdapterView.java:299)
  36. at android.widget.AbsListView.performItemClick(AbsListView.java:1113)
  37. at android.widget.AbsListView$PerformClick.run(AbsListView.java:2904)
  38. at android.widget.AbsListView$3.run(AbsListView.java:3638)
  39. at android.os.Handler.handleCallback(Handler.java:733)
  40. at android.os.Handler.dispatchMessage(Handler.java:95)
  41. at android.os.Looper.loop(Looper.java:136)
  42. at android.app.ActivityThread.main(ActivityThread.java:5017)
  43. at java.lang.reflect.Method.invokeNative(Native Method)
  44. at java.lang.reflect.Method.invoke(Method.java:515)
  45. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
  46. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
  47. at dalvik.system.NativeStart.main(Native Method)
  48.  
  49. public static void login(FragmentManager manager) {
  50. manager.beginTransAction().add(LoginFragment.newInstance(), null).commit();
  51. }
  52.  
  53. public class LoginFragment extends DialogFragment
  54. implements TextView.OnEditorActionListener, FingerprintCallback.Callback {
  55.  
  56. ...
  57.  
  58. public static LoginFragment newInstance() {
  59. return newInstance(null);
  60. }
  61.  
  62. public static LoginFragment newInstance(Intent intent) {
  63. LoginFragment fragment = new LoginFragment();
  64.  
  65. Bundle args = new Bundle();
  66. args.putParcelable(EXTRA_INTENT, intent);
  67. fragment.setArguments(args);
  68.  
  69. return fragment;
  70. }
  71.  
  72. @Override
  73. public void onCreate(Bundle savedInstanceState) {
  74. super.onCreate(savedInstanceState);
  75. Injector.getContextComponent().inject(this);
  76. setStyle(STYLE_NO_TITLE, R.style.DialogTheme);
  77. setRetainInstance(true);
  78. setCancelable(false);
  79.  
  80. mSaveUsernamePreference = mPreferences.getBoolean(getString(R.string.key_auth_username_retain));
  81. mUseFingerprintPreference = mPreferences.getBoolean(getString(R.string.key_auth_fingerprint));
  82. mUsernamePreference = mPreferences.getString(getString(R.string.key_auth_username));
  83. mPasswordPreference = mPreferences.getString(getString(R.string.key_auth_password));
  84. }
  85.  
  86. @Override
  87. public View onCreateView(LayoutInflater inflater, ViewGroup container,
  88. Bundle savedInstanceState) {
  89. View view = inflater.inflate(R.layout.dialog_login_container, container, false);
  90. ButterKnife.bind(this, view);
  91.  
  92. mPasswordView.setOnEditorActionListener(this);
  93.  
  94. if(!mFingerprintManager.isHardwareDetected()) {
  95. mUseFingerprintToggle.setVisibility(View.GONE);
  96. } else {
  97. mGenerated = initializeKeyPair(false);
  98. }
  99.  
  100. if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  101. setStage(isFingerprintAvailable() ? Stage.FINGERPRINT : Stage.CREDENTIALS);
  102. } else {
  103. setStage(Stage.CREDENTIALS);
  104. }
  105.  
  106. return view;
  107. }
  108.  
  109. @Override
  110. public void onResume() {
  111. super.onResume();
  112.  
  113. ...
  114.  
  115. if(mStage == Stage.FINGERPRINT && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  116. startListening(initializeCipher(Cipher.DECRYPT_MODE));
  117. }
  118. }
  119.  
  120. @Override
  121. public void onPause() {
  122. super.onPause();
  123. stopListening();
  124. }
  125.  
  126. ...
  127.  
  128. @Override
  129. public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
  130. Timber.i("Fingerprint succeeded");
  131. showFingerprintSuccess();
  132.  
  133. mSubscriptions.add(
  134. mGenerated.subscribeOn(Schedulers.newThread())
  135. .observeOn(AndroidSchedulers.mainThread())
  136. .doOnCompleted(() -> {
  137. try {
  138. mUsername = mUsernamePreference.get();
  139. mPassword = decryptPassword(result.getCryptoObject().getCipher());
  140. initLoginAttempt();
  141. } catch (IllegalBlockSizeException | BadPaddingException exception) {
  142. Timber.e(exception, "Failed to decrypt password");
  143. }
  144. }).subscribe());
  145. }
  146.  
  147. @Override
  148. public void onAuthenticationHelp(int messageId, CharSequence message) {
  149. Timber.i("Fingerprint help id: " + messageId + " message: " + message);
  150. showFingerprintError(message);
  151. }
  152.  
  153. @Override
  154. public void onAuthenticationError(int messageId, CharSequence message) {
  155. Timber.i("Fingerprint error id: " + messageId + " message: " + message);
  156. if(messageId != 5) {
  157. showFingerprintError(message);
  158. }
  159. }
  160.  
  161. @Override
  162. public void onAuthenticationFailed() {
  163. Timber.i("Fingerprint failed");
  164. showFingerprintError(getResources().getString(R.string.msg_fingerprint_error_unknown));
  165. }
  166.  
  167. @OnClick(R.id.button_cancel)
  168. public void onCancel() {
  169. dismiss();
  170. }
  171.  
  172. @OnClick(R.id.button_continue)
  173. public void onContinue() {
  174. switch (mStage) {
  175. case CREDENTIALS:
  176. mUsername = mUsernameView.getText().toString();
  177. mPassword = mPasswordView.getText().toString();
  178. initLoginAttempt();
  179. break;
  180. case FINGERPRINT:
  181. setStage(Stage.CREDENTIALS);
  182. break;
  183. }
  184. }
  185.  
  186. private void showFingerprintSuccess() {
  187. int colorAccent = ThemeUtil.getColorAttribute(getContext(), android.R.attr.colorAccent);
  188. mFingerprintIcon.setImageResource(R.drawable.ic_done_white_24dp);
  189. mFingerprintIcon.setCircleColor(colorAccent);
  190. mFingerprintStatus.setText(R.string.msg_fingerprint_success);
  191. mFingerprintStatus.setTextColor(colorAccent);
  192. }
  193.  
  194. private void showFingerprintError(CharSequence message) {
  195. int colorError = ContextCompat.getColor(getContext(), R.color.material_deep_orange_600);
  196. mFingerprintIcon.setImageResource(R.drawable.ic_priority_high_white_24dp);
  197. mFingerprintIcon.setCircleColor(colorError);
  198. mFingerprintStatus.setText(message);
  199. mFingerprintStatus.setTextColor(colorError);
  200. resetFingerprintStatus();
  201. }
  202.  
  203. private void resetFingerprintStatus() {
  204. mSubscriptions.add(Observable.timer(1600, TimeUnit.MILLISECONDS)
  205. .subscribeOn(Schedulers.newThread())
  206. .observeOn(AndroidSchedulers.mainThread())
  207. .subscribe(finished -> {
  208. mFingerprintIcon.setImageResource(R.drawable.ic_fingerprint_white_24dp);
  209. mFingerprintIcon.setCircleColor(ContextCompat
  210. .getColor(getContext(), R.color.material_blue_gray_500));
  211. mFingerprintStatus.setText(R.string.msg_fingerprint_input);
  212. mFingerprintStatus.setTextColor(ThemeUtil
  213. .getColorAttribute(getContext(), android.R.attr.textColorHint));
  214. }));
  215. }
  216.  
  217. private void onSaveUsernameChanged(boolean checked) {
  218. if(!checked) {
  219. mUseFingerprintToggle.setChecked(false);
  220. }
  221. }
  222.  
  223. private void onUseFingerprintChanged(boolean checked) {
  224. if(checked) {
  225. mSaveUsernameToggle.setChecked(true);
  226.  
  227. if(!mFingerprintManager.hasEnrolledFingerprints()) {
  228. displaySettingsDialog();
  229. mUseFingerprintToggle.setChecked(false);
  230. }
  231. }
  232. }
  233.  
  234. public void setStage(Stage stage) {
  235. switch (stage) {
  236. case CREDENTIALS:
  237. Timber.d("Set stage Credentials");
  238. mPositiveButton.setText(R.string.btn_login);
  239. mFingerprintContent.setVisibility(View.GONE);
  240. mCredentialContent.setVisibility(View.VISIBLE);
  241. setForm();
  242. break;
  243. case FINGERPRINT:
  244. mPositiveButton.setText(R.string.btn_password);
  245. mCredentialContent.setVisibility(View.GONE);
  246. mFingerprintContent.setVisibility(View.VISIBLE);
  247. break;
  248. } mStage = stage;
  249. }
  250.  
  251. private void startListening(boolean cipher) {
  252. Timber.v("Start listening for fingerprint input");
  253. mCancellationSignal = new CancellationSignal();
  254. if(cipher) {
  255. mFingerprintManager.authenticate(new FingerprintManagerCompat.CryptoObject(mCipher),
  256. 0, mCancellationSignal, new FingerprintCallback(this), null);
  257. } else {
  258. setStage(Stage.CREDENTIALS);
  259. }
  260. }
  261.  
  262. private void stopListening() {
  263. if(mCancellationSignal != null) {
  264. mCancellationSignal.cancel();
  265. mCancellationSignal = null;
  266. }
  267. }
  268.  
  269. private void setForm() {
  270. if(mSaveUsernamePreference.isSet() && mSaveUsernamePreference.get()
  271. && mUsernamePreference.isSet()) {
  272. mUsernameView.setText(mUsernamePreference.get());
  273. mUsernameView.setSelectAllOnFocus(true);
  274. mPasswordView.requestFocus();
  275. } else {
  276. mUsernameView.requestFocus();
  277. }
  278. }
  279.  
  280. public void initLoginAttempt() {
  281. mProgressBar.setVisibility(View.VISIBLE);
  282. mAuthenticationService.getLoginForm().subscribeOn(Schedulers.newThread())
  283. .observeOn(AndroidSchedulers.mainThread())
  284. .subscribe(this::onLoginFormResponse, this::onError);
  285. }
  286.  
  287. private void onLoginFormResponse(ResponseBody response) {
  288. try {
  289. attemptLogin(LoginForm.parse(response.string()));
  290. } catch (IOException exception) {
  291. Timber.w(exception, "Failed to parse login form");
  292. }
  293. }
  294.  
  295. private void attemptLogin(LoginForm loginForm) {
  296. mAuthenticationService
  297. .login(loginForm.getLoginTicket(), loginForm.getExecution(), loginForm.getEventIdentifier(),
  298. mUsername, mPassword, loginForm.getSubmitValue())
  299. .subscribeOn(Schedulers.newThread())
  300. .observeOn(AndroidSchedulers.mainThread())
  301. .subscribe(this::onLoginResponse, this::onError);
  302. }
  303.  
  304. public void onLoginResponse(ResponseBody response) {
  305. Timber.d("LOGIN RESPONSE");
  306. try {
  307. Timber.d(response.string());
  308. } catch (IOException exception) {
  309. Timber.w(exception, "Failed to retrieve attemptLogin response");
  310. }
  311.  
  312. mSubscriptions.add(NetworkUtility.getAuthentication()
  313. .subscribeOn(Schedulers.newThread())
  314. .observeOn(AndroidSchedulers.mainThread())
  315. .subscribe(this::onAuthenticationChanged, this::onError));
  316. }
  317.  
  318. public void onAuthenticationChanged(Boolean authenticated) {
  319. if(authenticated) {
  320. Timber.d("Authentication success");
  321.  
  322. if(mStage == Stage.CREDENTIALS) {
  323. if (mSaveUsernameToggle.isChecked()) {
  324. storeUsername();
  325. } else {
  326. clearUsername();
  327. }
  328.  
  329. if (mUseFingerprintToggle.isChecked()) {
  330. mGenerated = initializeKeyPair(true);
  331. storePassword();
  332. } else {
  333. clearPassword();
  334. finishIntent();
  335. }
  336. } else {
  337. finishIntent();
  338. }
  339. } else {
  340. Timber.d("Authentication failed");
  341. setStage(Stage.CREDENTIALS);
  342. mCaptionView.setTextColor(ContextCompat.getColor(getContext(), R.color.material_deep_orange_600));
  343. mCaptionView.setText(getString(R.string.msg_login_failed));
  344. mPasswordView.setText("");
  345. }
  346. }
  347.  
  348. private void finishIntent() {
  349. mProgressBar.setVisibility(View.INVISIBLE);
  350. Intent intent = getArguments().getParcelable(EXTRA_INTENT);
  351. if(intent != null) {
  352. startActivity(intent);
  353. } dismiss();
  354. }
  355.  
  356. private void onError(Throwable throwable) {
  357. Timber.w(throwable, "Login attempt failed");
  358. mProgressBar.setVisibility(View.INVISIBLE);
  359. mCaptionView.setTextColor(ContextCompat.getColor(getContext(), R.color.material_deep_orange_600));
  360. mCaptionView.setText("Login attempt failednPlease check your internet connection and try again");
  361. mPasswordView.setText("");
  362. }
  363.  
  364. private void storeUsername() {
  365. String username = mUsernameView.getText().toString();
  366. mUsernamePreference.set(username);
  367. if(mPreferences.getBoolean(getString(R.string.key_auth_push), false).get()) {
  368. UAirship.shared().getPushManager().getNamedUser().setId(username);
  369. }
  370. }
  371.  
  372. private void clearUsername() {
  373. UAirship.shared().getPushManager().getNamedUser().setId(null);
  374. mUsernamePreference.delete();
  375. }
  376.  
  377. private void storePassword() {
  378. Timber.d("STORE PASSWORD");
  379. mSubscriptions.add(mGenerated.subscribeOn(Schedulers.newThread())
  380. .observeOn(AndroidSchedulers.mainThread())
  381. .doOnCompleted(() -> {
  382. try {
  383. Timber.d("Store password");
  384. initializeCipher(Cipher.ENCRYPT_MODE);
  385.  
  386. String password = mPasswordView.getText().toString();
  387. byte[] bytes = password.getBytes();
  388. byte[] encrypted = mCipher.doFinal(bytes);
  389. String encoded = Base64.encodeToString(encrypted, Base64.NO_WRAP);
  390.  
  391. mPasswordPreference.set(encoded);
  392.  
  393. finishIntent();
  394.  
  395. } catch (IllegalBlockSizeException | BadPaddingException exception) {
  396. Timber.e(exception, "Failed to encrypt password");
  397. }
  398. }).subscribe());
  399. }
  400.  
  401. private String decryptPassword(Cipher cipher) throws IllegalBlockSizeException, BadPaddingException {
  402. String encoded = mPasswordPreference.get();
  403.  
  404. Timber.d("ENCODED STRING " + encoded);
  405.  
  406. byte[] encrypted = Base64.decode(encoded, Base64.NO_WRAP);
  407.  
  408. byte[] bytes = cipher.doFinal(encrypted);
  409.  
  410. return new String(bytes);
  411. }
  412.  
  413. private void clearPassword() {
  414. mPasswordPreference.delete();
  415. }
  416.  
  417. private boolean isFingerprintAvailable() {
  418. return mUseFingerprintPreference.isSet() && mUseFingerprintPreference.get()
  419. && mFingerprintManager.hasEnrolledFingerprints()
  420. && mSaveUsernamePreference.isSet()
  421. && mPasswordPreference.isSet();
  422. }
  423.  
  424. private void displaySettingsDialog() {
  425. new AlertDialog.Builder(getContext())
  426. .setTitle(R.string.title_dialog_secure_lock)
  427. .setMessage(R.string.msg_fingerprint_unavailable)
  428. .setPositiveButton(R.string.btn_settings, (dialog, which) -> {
  429. startActivity(new Intent(android.provider.Settings.ACTION_SECURITY_SETTINGS));
  430. dialog.dismiss();
  431. }).setNegativeButton(R.string.btn_cancel, (dialog, which) -> {
  432. dialog.dismiss();
  433. }).create().show();
  434. }
  435.  
  436. @TargetApi(Build.VERSION_CODES.M)
  437. private boolean initializeCipher(int opmode) {
  438. try {
  439. mKeyStore.load(null);
  440.  
  441. /**
  442. * A known bug in the Android 6.0 (API Level 23) implementation of Bouncy Castle
  443. * RSA OAEP causes the cipher to default to an SHA-1 certificate, making the SHA-256
  444. * certificate of the public key incompatible
  445. * To work around this issue, explicitly provide a new OAEP specification upon
  446. * initialization
  447. * @see <a href="https://code.google.com/p/android/issues/detail?id=197719">Issue 197719</a>
  448. */
  449. AlgorithmParameterSpec spec = generateOAEPParameterSpec();
  450. Key key;
  451.  
  452. if(opmode == Cipher.ENCRYPT_MODE) {
  453. Key publicKey = mKeyStore.getCertificate(CIPHER_KEY_ALIAS).getPublicKey();
  454.  
  455. /**
  456. * A known bug in Android 6.0 (API Level 23) causes user authentication-related
  457. * authorizations to be enforced even for public keys
  458. * To work around this issue, extract the public key material to use outside of
  459. * the Android Keystore
  460. * @see <a href="http://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.html">KeyGenParameterSpec Known Issues</a>
  461. */
  462. key = KeyFactory.getInstance(publicKey.getAlgorithm())
  463. .generatePublic(new X509EncodedKeySpec(publicKey.getEncoded()));
  464. } else {
  465. key = mKeyStore.getKey(CIPHER_KEY_ALIAS, null);
  466. }
  467.  
  468. mCipher.init(opmode, key, spec);
  469. return true;
  470. } catch (KeyPermanentlyInvalidatedException exception) {
  471. Timber.w(exception, "Failed to initialize Cipher");
  472. handleKeyPermanentlyInvalidated();
  473. return false;
  474. } catch (IOException | KeyStoreException | UnrecoverableEntryException
  475. | InvalidKeySpecException | CertificateException | InvalidKeyException
  476. | NoSuchAlgorithmException | InvalidAlgorithmParameterException exception) {
  477. throw new RuntimeException("Failed to initialize Cipher", exception);
  478. }
  479. }
  480.  
  481. private OAEPParameterSpec generateOAEPParameterSpec() {
  482. return new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
  483. }
  484.  
  485. private void handleKeyPermanentlyInvalidated() {
  486. mCaptionView.setText(getString(R.string.msg_fingerprint_invalidated));
  487. mGenerated = initializeKeyPair(true);
  488. clearPassword();
  489. }
  490.  
  491. private Observable<KeyPair> initializeKeyPair(boolean generate) {
  492. return Observable.create(subscriber -> {
  493. try {
  494. mKeyStore.load(null);
  495.  
  496. if(!generate || mKeyStore.containsAlias(CIPHER_KEY_ALIAS)) {
  497. PublicKey publicKey = mKeyStore.getCertificate(CIPHER_KEY_ALIAS).getPublicKey();
  498. PrivateKey privateKey = (PrivateKey) mKeyStore.getKey(CIPHER_KEY_ALIAS, null);
  499. subscriber.onNext(new KeyPair(publicKey, privateKey));
  500. } else {
  501. subscriber.onNext(createKeyPair());
  502. }
  503.  
  504. subscriber.onCompleted();
  505. } catch (IOException | KeyStoreException | UnrecoverableKeyException
  506. | CertificateException | NoSuchAlgorithmException
  507. | InvalidAlgorithmParameterException exception) {
  508. Timber.e(exception, "Failed to generate key pair");
  509. subscriber.onError(exception);
  510. }
  511. });
  512. }
  513.  
  514. @TargetApi(Build.VERSION_CODES.M)
  515. private KeyPair createKeyPair() throws InvalidAlgorithmParameterException {
  516. // Set the alias of the entry in Android KeyStore where the key will appear
  517. // and the constrains (purposes) in the constructor of the Builder
  518. Timber.d("Initialize key pair");
  519. mKeyPairGenerator.initialize(
  520. new KeyGenParameterSpec.Builder(CIPHER_KEY_ALIAS, KeyProperties.PURPOSE_DECRYPT)
  521. .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
  522. .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
  523. .setUserAuthenticationRequired(true)
  524. .build());
  525.  
  526. return mKeyPairGenerator.generateKeyPair();
  527. }
  528.  
  529. }
  530.  
  531. catch (KeyPermanentlyInvalidatedException exception) {
  532. Timber.w(exception, "A new fingerprint was added to the device");
  533. handleKeyPermanentlyInvalidated();
  534. return false;
  535. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement