2626import android .content .Context ;
2727import android .os .Build ;
2828import android .security .KeyPairGeneratorSpec ;
29+ import android .security .keystore .KeyGenParameterSpec ;
30+ import android .security .keystore .KeyProperties ;
2931
3032import androidx .annotation .RequiresApi ;
3133
4446import java .security .KeyStore ;
4547import java .security .spec .AlgorithmParameterSpec ;
4648import java .util .Calendar ;
49+ import java .util .Date ;
4750import java .util .Locale ;
51+ import java .util .concurrent .TimeUnit ;
4852
4953import javax .crypto .SecretKey ;
5054import javax .security .auth .x500 .X500Principal ;
@@ -269,12 +273,13 @@ public void deleteSecretKeyFromStorage() throws ClientException {
269273 /**
270274 * Generate a self-signed cert and derive an AlgorithmParameterSpec from that.
271275 * This is for the key to be generated in {@link KeyStore} via {@link KeyPairGenerator}
276+ * Note : This is now only for API level < 28
272277 *
273278 * @param context an Android {@link Context} object.
274279 * @return a {@link AlgorithmParameterSpec} for the keystore key (that we'll use to wrap the secret key).
275280 */
276281 @ RequiresApi (api = Build .VERSION_CODES .JELLY_BEAN_MR2 )
277- private static AlgorithmParameterSpec getSpecForKeyStoreKey (@ NonNull final Context context ,
282+ private static AlgorithmParameterSpec getLegacySpecForKeyStoreKey (@ NonNull final Context context ,
278283 @ NonNull final String alias ) {
279284 // Generate a self-signed cert.
280285 final String certInfo = String .format (Locale .ROOT , "CN=%s, OU=%s" ,
@@ -295,6 +300,34 @@ private static AlgorithmParameterSpec getSpecForKeyStoreKey(@NonNull final Conte
295300 .build ();
296301 }
297302
303+ /**
304+ * Generate a self-signed cert and derive an AlgorithmParameterSpec from that.
305+ * This is for the key to be generated in {@link KeyStore} via {@link KeyPairGenerator}
306+ *
307+ * @param context an Android {@link Context} object.
308+ * @return a {@link AlgorithmParameterSpec} for the keystore key (that we'll use to wrap the secret key).
309+ */
310+ private static AlgorithmParameterSpec getSpecForKeyStoreKey (@ NonNull final Context context , @ NonNull final String alias ) {
311+ if (Build .VERSION .SDK_INT < Build .VERSION_CODES .P ) {
312+ return getLegacySpecForKeyStoreKey (context , alias );
313+ } else {
314+ final String certInfo = String .format (Locale .ROOT , "CN=%s, OU=%s" ,
315+ alias ,
316+ context .getPackageName ());
317+ final int certValidYears = 100 ;
318+ int purposes = KeyProperties .PURPOSE_WRAP_KEY | KeyProperties .PURPOSE_ENCRYPT | KeyProperties .PURPOSE_DECRYPT ;
319+ return new KeyGenParameterSpec .Builder (alias , purposes )
320+ .setCertificateSubject (new X500Principal (certInfo ))
321+ .setCertificateSerialNumber (BigInteger .ONE )
322+ .setCertificateNotBefore (new Date ())
323+ .setCertificateNotAfter (new Date (System .currentTimeMillis () + TimeUnit .DAYS .toMillis (365 * certValidYears )))
324+ .setKeySize (2048 )
325+ .setDigests (KeyProperties .DIGEST_SHA256 , KeyProperties .DIGEST_SHA512 )
326+ .setEncryptionPaddings (KeyProperties .ENCRYPTION_PADDING_RSA_PKCS1 )
327+ .build ();
328+ }
329+ }
330+
298331 /**
299332 * Get the file that stores the wrapped key.
300333 */
0 commit comments