use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by crdroidandroid.
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 crdroidandroid.
the class KeyStoreTest method testAppId.
public void testAppId() throws Exception {
String name = "test";
byte[] id = new byte[] { 0x01, 0x02, 0x03 };
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_RSA);
args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
args.addBytes(KeymasterDefs.KM_TAG_APPLICATION_ID, id);
args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int result = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result);
assertEquals("getKeyCharacteristics should fail without application ID", KeymasterDefs.KM_ERROR_INVALID_KEY_BLOB, mKeyStore.getKeyCharacteristics(name, null, null, outCharacteristics));
assertEquals("getKeyCharacteristics should succeed with application ID", KeyStore.NO_ERROR, mKeyStore.getKeyCharacteristics(name, new KeymasterBlob(id), null, outCharacteristics));
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by crdroidandroid.
the class KeyStoreTest method testOperationPruning.
// This is a very implementation specific test and should be thrown out eventually, however it
// is nice for now to test that keystore is properly pruning operations.
public void testOperationPruning() 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_CTR);
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_CTR);
args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, null);
assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
IBinder first = result.token;
// Implementation detail: softkeymaster supports 16 concurrent operations
for (int i = 0; i < 16; i++) {
result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, null);
assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
}
// At this point the first operation should be pruned.
assertEquals("Operation should be pruned", KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, mKeyStore.update(first, null, new byte[] { 0x01 }).resultCode);
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by crdroidandroid.
the class KeyStoreTest method testAuthNeeded.
public void testAuthNeeded() 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_PKCS7);
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 1);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, null);
assertEquals("Begin should expect authorization", KeyStore.OP_AUTH_NEEDED, result.resultCode);
IBinder token = result.token;
result = mKeyStore.update(token, null, new byte[] { 0x01, 0x02, 0x03, 0x04 });
assertEquals("Update should require authorization", KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED, result.resultCode);
}
use of android.security.keymaster.KeyCharacteristics in project android_frameworks_base by crdroidandroid.
the class KeyStoreTest method importAesKey.
private int importAesKey(String name, byte[] key, int size, int mode) {
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.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mode);
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, size);
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return mKeyStore.importKey(name, args, KeymasterDefs.KM_KEY_FORMAT_RAW, key, 0, new KeyCharacteristics());
}
Aggregations