/* * Copyright 2017 Marvin Ramin. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * <http://www.apache.org/licenses/LICENSE-2.0> * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mtramin.rxfingerprint; import android.content.Context; import android.support.annotation.VisibleForTesting; import com.mtramin.rxfingerprint.data.FingerprintEncryptionResult; import com.mtramin.rxfingerprint.data.FingerprintResult; import com.mtramin.rxfingerprint.data.FingerprintUnavailableException; import javax.crypto.Cipher; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; class RsaEncryptionObservable implements ObservableOnSubscribe<FingerprintEncryptionResult> { private final FingerprintApiWrapper fingerprintApiWrapper; private final RsaCipherProvider cipherProvider; private final char[] toEncrypt; private final EncodingProvider encodingProvider; /** * Creates a new AesEncryptionObservable that will listen to fingerprint authentication * to encrypt the given data. * * @param context context to use * @param keyName name of the key in the keystore * @param toEncrypt data to encrypt @return Observable {@link FingerprintEncryptionResult} */ static Observable<FingerprintEncryptionResult> create(Context context, String keyName, char[] toEncrypt, boolean keyInvalidatedByBiometricEnrollment) { if (toEncrypt == null) { return Observable.error(new IllegalArgumentException("String to be encrypted is null. Can only encrypt valid strings")); } try { return Observable.create(new RsaEncryptionObservable(new FingerprintApiWrapper(context), new RsaCipherProvider(context, keyName, keyInvalidatedByBiometricEnrollment), toEncrypt, new Base64Provider())); } catch (Exception e) { return Observable.error(e); } } @VisibleForTesting RsaEncryptionObservable(FingerprintApiWrapper fingerprintApiWrapper, RsaCipherProvider cipherProvider, char[] toEncrypt, EncodingProvider encodingProvider) { this.fingerprintApiWrapper = fingerprintApiWrapper; this.cipherProvider = cipherProvider; this.toEncrypt = toEncrypt; this.encodingProvider = encodingProvider; } @Override public void subscribe(ObservableEmitter<FingerprintEncryptionResult> emitter) throws Exception { if (fingerprintApiWrapper.isUnavailable()) { emitter.onError(new FingerprintUnavailableException("Fingerprint authentication is not available on this device! Ensure that the device has a Fingerprint sensor and enrolled Fingerprints by calling RxFingerprint#isAvailable(Context) first")); return; } try { Cipher cipher = cipherProvider.getCipherForEncryption(); byte[] encryptedBytes = cipher.doFinal(ConversionUtils.toBytes(toEncrypt)); String encryptedString = encodingProvider.encode(encryptedBytes); emitter.onNext(new FingerprintEncryptionResult(FingerprintResult.AUTHENTICATED, null, encryptedString)); emitter.onComplete(); } catch (Exception e) { Logger.error(String.format("Error writing value for key: %s", cipherProvider.keyName), e); emitter.onError(e); } } }