package io.keybase.android.keystore;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.security.KeyChain;
import android.security.KeyPairGeneratorSpec;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;

import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Calendar;

import javax.security.auth.x500.X500Principal;

public class KeyStoreHelper {

    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static void generateRSAKeyPair(Context ctx, String keyAlias) throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");

        final AlgorithmParameterSpec spec;
        final boolean isOnHardware;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            // TODO: this this on android M
            spec = new KeyGenParameterSpec.Builder(
              keyAlias,
              KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
              .build();

            // TODO look at key info and see if crypto is hardware bounded
        } else {
            // TODO use this information
            isOnHardware = KeyChain.isBoundKeyAlgorithm("RSA");

            final Calendar endTime = Calendar.getInstance();
            endTime.add(Calendar.YEAR, 10);

            spec = new KeyPairGeneratorSpec.Builder(ctx)
              .setAlias(keyAlias)
              .setEncryptionRequired()
              .setSerialNumber(BigInteger.ONE)
              .setSubject(new X500Principal("CN=" + keyAlias))
              .setStartDate(Calendar.getInstance().getTime())
              .setEndDate(endTime.getTime())
              .setKeySize(4096)
              .build();
        }

        kpg.initialize(spec);
        KeyPair kp = kpg.generateKeyPair();
    }
}

@@ -255,24 +255,66 @@
 ameterSpec;%0A
+import android.security.keystore.KeyInfo;%0A
 import andro
@@ -509,39 +509,8 @@
 or;%0A
-import java.security.KeyStore;%0A
 impo
@@ -630,32 +630,65 @@
 viderException;%0A
+import java.security.PrivateKey;%0A
 import java.secu
@@ -737,23 +737,193 @@
 ava.
-util.Calendar;%0A
+security.spec.InvalidKeySpecException;%0Aimport java.security.spec.RSAKeyGenParameterSpec;%0Aimport java.util.Calendar;%0A%0Aimport javax.crypto.SecretKey;%0Aimport javax.crypto.SecretKeyFactory;
 %0Aimp
@@ -1402,28 +1402,89 @@
 nal 
-boolean isOnHardware
+Calendar endTime = Calendar.getInstance();%0A        endTime.add(Calendar.YEAR, 10)
 ;%0A%0A 
@@ -1570,52 +1570,8 @@
 ) %7B%0A
-            // TODO: this this on android M%0A
     
@@ -1738,253 +1738,300 @@
    .
-build();%0A%0A            // TODO look at key info and see if crypto is hardware bounded%0A        %7D else %7B%0A            // TODO use this information%0A            isOnHardware = KeyChain.isBoundKeyAlgorithm(%22RSA%22);%0A%0A            final Calendar endTime = 
+setBlockModes(KeyProperties.BLOCK_MODE_ECB)%0A              .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)%0A              .setCertificateSerialNumber(BigInteger.ONE)%0A              .setCertificateSubject(new X500Principal(%22CN=%22 + keyAlias))%0A              .setKeyValidityStart(
 Cale
@@ -2040,33 +2040,43 @@
 ar.getInstance()
-;
+.getTime())
 %0A            end
@@ -2076,40 +2076,120 @@
     
-endTime.add(Calendar.YEAR, 10);%0A
+  .setKeyValidityEnd(endTime.getTime())%0A              .setKeySize(4096)%0A              .build();%0A        %7D else %7B
 %0A   
@@ -2678,11 +2678,613 @@
 );%0A    %7D
+%0A%0A    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)%0A    public static boolean isOnHardware(PrivateKey privateKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException %7B%0A        if (Build.VERSION.SDK_INT %3E= Build.VERSION_CODES.M) %7B%0A            SecretKeyFactory factory = SecretKeyFactory.getInstance(privateKey.getAlgorithm(), %22AndroidKeyStore%22);%0A            final KeyInfo keyInfo = (KeyInfo) factory.getKeySpec((SecretKey) privateKey, KeyInfo.class);%0A            return keyInfo.isInsideSecureHardware();%0A        %7D%0A        return KeyChain.isBoundKeyAlgorithm(%22RSA%22);%0A%0A    %7D
 %0A%7D%0A

Support Android M's KeyStore