use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by AOSPA.
the class AndroidKeyStoreSpi method setSecretKeyEntry.
private void setSecretKeyEntry(String entryAlias, SecretKey key, java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
if ((param != null) && (!(param instanceof KeyProtection))) {
throw new KeyStoreException("Unsupported protection parameter class: " + param.getClass().getName() + ". Supported: " + KeyProtection.class.getName());
}
KeyProtection params = (KeyProtection) param;
if (key instanceof AndroidKeyStoreSecretKey) {
// KeyStore-backed secret key. It cannot be duplicated into another entry and cannot
// overwrite its own entry.
String keyAliasInKeystore = ((AndroidKeyStoreSecretKey) key).getAlias();
if (keyAliasInKeystore == null) {
throw new KeyStoreException("KeyStore-backed secret key does not have an alias");
}
if (!keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
throw new KeyStoreException("KeyStore-backed secret key has invalid alias: " + keyAliasInKeystore);
}
String keyEntryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
if (!entryAlias.equals(keyEntryAlias)) {
throw new KeyStoreException("Can only replace KeyStore-backed keys with same" + " alias: " + entryAlias + " != " + keyEntryAlias);
}
// This is the entry where this key is already stored. No need to do anything.
if (params != null) {
throw new KeyStoreException("Modifying KeyStore-backed key using protection" + " parameters not supported");
}
return;
}
if (params == null) {
throw new KeyStoreException("Protection parameters must be specified when importing a symmetric key");
}
// Not a KeyStore-backed secret key -- import its key material into keystore.
String keyExportFormat = key.getFormat();
if (keyExportFormat == null) {
throw new KeyStoreException("Only secret keys that export their key material are supported");
} else if (!"RAW".equals(keyExportFormat)) {
throw new KeyStoreException("Unsupported secret key material export format: " + keyExportFormat);
}
byte[] keyMaterial = key.getEncoded();
if (keyMaterial == null) {
throw new KeyStoreException("Key did not export its key material despite supporting" + " RAW format export");
}
KeymasterArguments args = new KeymasterArguments();
try {
int keymasterAlgorithm = KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(key.getAlgorithm());
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
int[] keymasterDigests;
if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
// JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
// implies SHA-256 digest). Because keymaster HMAC key is authorized only for one
// digest, we don't let import parameters override the digest implied by the key.
// If the parameters specify digests at all, they must specify only one digest, the
// only implied by key algorithm.
int keymasterImpliedDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
if (keymasterImpliedDigest == -1) {
throw new ProviderException("HMAC key algorithm digest unknown for key algorithm " + key.getAlgorithm());
}
keymasterDigests = new int[] { keymasterImpliedDigest };
if (params.isDigestsSpecified()) {
// Digest(s) explicitly specified in params -- check that the list consists of
// exactly one digest, the one implied by key algorithm.
int[] keymasterDigestsFromParams = KeyProperties.Digest.allToKeymaster(params.getDigests());
if ((keymasterDigestsFromParams.length != 1) || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) {
throw new KeyStoreException("Unsupported digests specification: " + Arrays.asList(params.getDigests()) + ". Only " + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest) + " supported for HMAC key algorithm " + key.getAlgorithm());
}
}
} else {
// Key algorithm does not imply a digest.
if (params.isDigestsSpecified()) {
keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
} else {
keymasterDigests = EmptyArray.INT;
}
}
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
@KeyProperties.PurposeEnum int purposes = params.getPurposes();
int[] keymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0) && (params.isRandomizedEncryptionRequired())) {
for (int keymasterBlockMode : keymasterBlockModes) {
if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(keymasterBlockMode)) {
throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be violated by" + " block mode: " + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode) + ". See KeyProtection documentation.");
}
}
}
args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, KeyProperties.Purpose.allToKeymaster(purposes));
args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
if (params.getSignaturePaddings().length > 0) {
throw new KeyStoreException("Signature paddings not supported for symmetric keys");
}
int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(params.getEncryptionPaddings());
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
KeymasterUtils.addUserAuthArgs(args, params.isUserAuthenticationRequired(), params.getUserAuthenticationValidityDurationSeconds(), params.isUserAuthenticationValidWhileOnBody(), params.isInvalidatedByBiometricEnrollment());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(args, keymasterAlgorithm, keymasterBlockModes, keymasterDigests);
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, params.getKeyValidityForOriginationEnd());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, params.getKeyValidityForConsumptionEnd());
if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0) && (!params.isRandomizedEncryptionRequired())) {
// Permit caller-provided IV when encrypting with this key
args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
}
} catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException(e);
}
Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
String keyAliasInKeystore = Credentials.USER_SECRET_KEY + entryAlias;
int errorCode = mKeyStore.importKey(keyAliasInKeystore, args, KeymasterDefs.KM_KEY_FORMAT_RAW, keyMaterial, mUid, // flags
0, new KeyCharacteristics());
if (errorCode != KeyStore.NO_ERROR) {
throw new KeyStoreException("Failed to import secret key. Keystore error code: " + errorCode);
}
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by AOSPA.
the class AndroidKeyStoreProvider method loadAndroidKeyStoreSecretKeyFromKeystore.
@NonNull
public static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(@NonNull KeyStore keyStore, @NonNull String secretKeyAlias, int uid) throws UnrecoverableKeyException {
KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
int errorCode = keyStore.getKeyCharacteristics(secretKeyAlias, null, null, uid, keyCharacteristics);
if (errorCode != KeyStore.NO_ERROR) {
throw (UnrecoverableKeyException) new UnrecoverableKeyException("Failed to obtain information about key").initCause(KeyStore.getKeyStoreException(errorCode));
}
Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
if (keymasterAlgorithm == null) {
throw new UnrecoverableKeyException("Key algorithm unknown");
}
List<Integer> keymasterDigests = keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST);
int keymasterDigest;
if (keymasterDigests.isEmpty()) {
keymasterDigest = -1;
} else {
// More than one digest can be permitted for this key. Use the first one to form the
// JCA key algorithm name.
keymasterDigest = keymasterDigests.get(0);
}
@KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
try {
keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(keymasterAlgorithm, keymasterDigest);
} catch (IllegalArgumentException e) {
throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
}
return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by AOSPA.
the class AndroidKeyStoreKeyPairGeneratorSpi method generateKeystoreKeyPair.
private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args, byte[] additionalEntropy, final int flags) throws ProviderException {
KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy, mEntryUid, flags, resultingKeyCharacteristics);
if (errorCode != KeyStore.NO_ERROR) {
throw new ProviderException("Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
}
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by AOSPA.
the class KeyStoreTest method testGetKeyCharacteristicsSuccess.
public void testGetKeyCharacteristicsSuccess() throws Exception {
mKeyStore.onUserPasswordChanged(TEST_PASSWD);
String name = "test";
KeyCharacteristics gen = generateRsaKey(name);
KeyCharacteristics call = new KeyCharacteristics();
int result = mKeyStore.getKeyCharacteristics(name, null, null, call);
assertEquals("getKeyCharacteristics should succeed", KeyStore.NO_ERROR, result);
mKeyStore.delete("test");
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by AOSPA.
the class KeyStoreTest method testAesGcmEncryptSuccess.
public void testAesGcmEncryptSuccess() throws Exception {
String name = "test";
KeymasterArguments args = new KeymasterArguments();
args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
args = new KeymasterArguments();
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 128);
OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, null);
IBinder token = result.token;
assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
result = mKeyStore.update(token, null, new byte[] { 0x01, 0x02, 0x03, 0x04 });
assertEquals("Update should succeed", KeyStore.NO_ERROR, result.resultCode);
assertEquals("Finish should succeed", KeyStore.NO_ERROR, mKeyStore.finish(token, null, null).resultCode);
// TODO: Assert that an AEAD tag was returned by finish
}
Aggregations