/*
 * 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.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.security.keystore.KeyProperties;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;

class RsaCipherProvider extends CipherProvider {
	RsaCipherProvider(@NonNull Context context, @Nullable String keyName) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException {
		this(context, keyName, true);
	}

	RsaCipherProvider(@NonNull Context context, @Nullable String keyName, boolean keyInvalidatedByBiometricEnrollment) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException {
		super(context, keyName, keyInvalidatedByBiometricEnrollment);
	}
	@Override
	@TargetApi(Build.VERSION_CODES.M)
	Cipher cipherForEncryption() throws GeneralSecurityException, IOException {
		KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE);

		keyGenerator.initialize(getKeyGenParameterSpecBuilder(keyName, KeyProperties.BLOCK_MODE_ECB, KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, invalidatedByBiometricEnrollment)
				.build());

		keyGenerator.generateKeyPair();

		KeyFactory keyFactory = KeyFactory.getInstance(KeyProperties.KEY_ALGORITHM_RSA);
		Cipher cipher = createCipher();
		cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(keyFactory, keyStore));

		return cipher;
	}

	Cipher getCipherForDecryption() throws GeneralSecurityException {
		Cipher cipher = createCipher();
		cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(keyStore, keyName));
		return cipher;
	}

	private PrivateKey getPrivateKey(KeyStore keyStore, String keyAlias) throws GeneralSecurityException {
		return (PrivateKey) keyStore.getKey(keyAlias, null);
	}

	private PublicKey getPublicKey(KeyFactory keyFactory, KeyStore keyStore) throws GeneralSecurityException {
		PublicKey publicKey = keyStore.getCertificate(keyName).getPublicKey();
		KeySpec spec = new X509EncodedKeySpec(publicKey.getEncoded());
		return keyFactory.generatePublic(spec);
	}

	@Override
	@TargetApi(Build.VERSION_CODES.M)
	Cipher createCipher() throws NoSuchPaddingException, NoSuchAlgorithmException {
		return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_RSA + "/"
				+ KeyProperties.BLOCK_MODE_ECB + "/"
				+ KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
	}
}