Loading api/current.txt +17 −0 Original line number Diff line number Diff line Loading @@ -37856,6 +37856,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isInvalidatedByBiometricEnrollment(); method public boolean isRandomizedEncryptionRequired(); method public boolean isStrongBoxBacked(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationValidWhileOnBody(); } Loading @@ -37873,6 +37874,7 @@ package android.security.keystore { method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setIsStrongBoxBacked(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int); method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date); method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); Loading Loading @@ -37933,6 +37935,7 @@ package android.security.keystore { field public static final java.lang.String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding"; field public static final java.lang.String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding"; field public static final java.lang.String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding"; field public static final deprecated java.lang.String KEY_ALGORITHM_3DES = "DESede"; field public static final java.lang.String KEY_ALGORITHM_AES = "AES"; field public static final java.lang.String KEY_ALGORITHM_EC = "EC"; field public static final java.lang.String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1"; Loading @@ -37943,11 +37946,13 @@ package android.security.keystore { field public static final java.lang.String KEY_ALGORITHM_RSA = "RSA"; field public static final int ORIGIN_GENERATED = 1; // 0x1 field public static final int ORIGIN_IMPORTED = 2; // 0x2 field public static final int ORIGIN_SECURELY_IMPORTED = 8; // 0x8 field public static final int ORIGIN_UNKNOWN = 4; // 0x4 field public static final int PURPOSE_DECRYPT = 2; // 0x2 field public static final int PURPOSE_ENCRYPT = 1; // 0x1 field public static final int PURPOSE_SIGN = 4; // 0x4 field public static final int PURPOSE_VERIFY = 8; // 0x8 field public static final int PURPOSE_WRAP_KEY = 32; // 0x20 field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1"; field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS"; } Loading Loading @@ -37987,12 +37992,24 @@ package android.security.keystore { method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); } public class StrongBoxUnavailableException extends java.security.ProviderException { ctor public StrongBoxUnavailableException(); } public class UserNotAuthenticatedException extends java.security.InvalidKeyException { ctor public UserNotAuthenticatedException(); ctor public UserNotAuthenticatedException(java.lang.String); ctor public UserNotAuthenticatedException(java.lang.String, java.lang.Throwable); } public class WrappedKeyEntry implements java.security.KeyStore.Entry { ctor public WrappedKeyEntry(byte[], java.lang.String, java.lang.String, java.security.spec.AlgorithmParameterSpec); method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); method public java.lang.String getTransformation(); method public byte[] getWrappedKeyBytes(); method public java.lang.String getWrappingKeyAlias(); } } package android.service.autofill { core/java/android/security/keymaster/KeymasterDefs.java +3 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,7 @@ public final class KeymasterDefs { public static final int KM_ALGORITHM_RSA = 1; public static final int KM_ALGORITHM_EC = 3; public static final int KM_ALGORITHM_AES = 32; public static final int KM_ALGORITHM_3DES = 33; public static final int KM_ALGORITHM_HMAC = 128; // Block modes. Loading Loading @@ -131,6 +132,7 @@ public final class KeymasterDefs { public static final int KM_ORIGIN_GENERATED = 0; public static final int KM_ORIGIN_IMPORTED = 2; public static final int KM_ORIGIN_UNKNOWN = 3; public static final int KM_ORIGIN_SECURELY_IMPORTED = 4; // Key usability requirements. public static final int KM_BLOB_STANDALONE = 0; Loading @@ -141,6 +143,7 @@ public final class KeymasterDefs { public static final int KM_PURPOSE_DECRYPT = 1; public static final int KM_PURPOSE_SIGN = 2; public static final int KM_PURPOSE_VERIFY = 3; public static final int KM_PURPOSE_WRAP = 5; // Key formats. public static final int KM_KEY_FORMAT_X509 = 0; Loading keystore/java/android/security/KeyStore.java +13 −0 Original line number Diff line number Diff line Loading @@ -510,6 +510,19 @@ public class KeyStore { return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics); } public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, KeyCharacteristics outCharacteristics) { try { return mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid, outCharacteristics); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; } } public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid) { try { Loading keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java 0 → 100644 +298 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * 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 android.security.keystore; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.ProviderException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.util.Arrays; import javax.crypto.CipherSpi; import javax.crypto.spec.IvParameterSpec; /** * Base class for Android Keystore 3DES {@link CipherSpi} implementations. * * @hide */ public class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase { private static final int BLOCK_SIZE_BYTES = 8; private final int mKeymasterBlockMode; private final int mKeymasterPadding; /** Whether this transformation requires an IV. */ private final boolean mIvRequired; private byte[] mIv; /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */ private boolean mIvHasBeenUsed; AndroidKeyStore3DESCipherSpi( int keymasterBlockMode, int keymasterPadding, boolean ivRequired) { mKeymasterBlockMode = keymasterBlockMode; mKeymasterPadding = keymasterPadding; mIvRequired = ivRequired; } abstract static class ECB extends AndroidKeyStore3DESCipherSpi { protected ECB(int keymasterPadding) { super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false); } public static class NoPadding extends ECB { public NoPadding() { super(KeymasterDefs.KM_PAD_NONE); } } public static class PKCS7Padding extends ECB { public PKCS7Padding() { super(KeymasterDefs.KM_PAD_PKCS7); } } } abstract static class CBC extends AndroidKeyStore3DESCipherSpi { protected CBC(int keymasterPadding) { super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true); } public static class NoPadding extends CBC { public NoPadding() { super(KeymasterDefs.KM_PAD_NONE); } } public static class PKCS7Padding extends CBC { public PKCS7Padding() { super(KeymasterDefs.KM_PAD_PKCS7); } } } @Override protected void initKey(int i, Key key) throws InvalidKeyException { if (!(key instanceof AndroidKeyStoreSecretKey)) { throw new InvalidKeyException( "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); } if (!KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(key.getAlgorithm())) { throw new InvalidKeyException( "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " + KeyProperties.KEY_ALGORITHM_3DES + " supported"); } setKey((AndroidKeyStoreSecretKey) key); } @Override protected int engineGetBlockSize() { return BLOCK_SIZE_BYTES; } @Override protected int engineGetOutputSize(int inputLen) { return inputLen + 3 * BLOCK_SIZE_BYTES; } @Override protected final byte[] engineGetIV() { return ArrayUtils.cloneIfNotEmpty(mIv); } @Override protected AlgorithmParameters engineGetParameters() { if (!mIvRequired) { return null; } if ((mIv != null) && (mIv.length > 0)) { try { AlgorithmParameters params = AlgorithmParameters.getInstance("DESede"); params.init(new IvParameterSpec(mIv)); return params; } catch (NoSuchAlgorithmException e) { throw new ProviderException( "Failed to obtain 3DES AlgorithmParameters", e); } catch (InvalidParameterSpecException e) { throw new ProviderException( "Failed to initialize 3DES AlgorithmParameters with an IV", e); } } return null; } @Override protected void initAlgorithmSpecificParameters() throws InvalidKeyException { if (!mIvRequired) { return; } // IV is used if (!isEncrypting()) { throw new InvalidKeyException("IV required when decrypting" + ". Use IvParameterSpec or AlgorithmParameters to provide it."); } } @Override protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { if (!mIvRequired) { if (params != null) { throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); } return; } // IV is used if (params == null) { if (!isEncrypting()) { // IV must be provided by the caller throw new InvalidAlgorithmParameterException( "IvParameterSpec must be provided when decrypting"); } return; } if (!(params instanceof IvParameterSpec)) { throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported"); } mIv = ((IvParameterSpec) params).getIV(); if (mIv == null) { throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec"); } } @Override protected void initAlgorithmSpecificParameters(AlgorithmParameters params) throws InvalidAlgorithmParameterException { if (!mIvRequired) { if (params != null) { throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); } return; } // IV is used if (params == null) { if (!isEncrypting()) { // IV must be provided by the caller throw new InvalidAlgorithmParameterException("IV required when decrypting" + ". Use IvParameterSpec or AlgorithmParameters to provide it."); } return; } if (!"DESede".equalsIgnoreCase(params.getAlgorithm())) { throw new InvalidAlgorithmParameterException( "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm() + ". Supported: DESede"); } IvParameterSpec ivSpec; try { ivSpec = params.getParameterSpec(IvParameterSpec.class); } catch (InvalidParameterSpecException e) { if (!isEncrypting()) { // IV must be provided by the caller throw new InvalidAlgorithmParameterException("IV required when decrypting" + ", but not found in parameters: " + params, e); } mIv = null; return; } mIv = ivSpec.getIV(); if (mIv == null) { throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters"); } } @Override protected final int getAdditionalEntropyAmountForBegin() { if ((mIvRequired) && (mIv == null) && (isEncrypting())) { // IV will need to be generated return BLOCK_SIZE_BYTES; } return 0; } @Override protected int getAdditionalEntropyAmountForFinish() { return 0; } @Override protected void addAlgorithmSpecificParametersToBegin(KeymasterArguments keymasterArgs) { if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) { // IV is being reused for encryption: this violates security best practices. throw new IllegalStateException( "IV has already been used. Reusing IV in encryption mode violates security best" + " practices."); } keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_3DES); keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode); keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding); if ((mIvRequired) && (mIv != null)) { keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv); } } @Override protected void loadAlgorithmSpecificParametersFromBeginResult( KeymasterArguments keymasterArgs) { mIvHasBeenUsed = true; // NOTE: Keymaster doesn't always return an IV, even if it's used. byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null); if ((returnedIv != null) && (returnedIv.length == 0)) { returnedIv = null; } if (mIvRequired) { if (mIv == null) { mIv = returnedIv; } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { throw new ProviderException("IV in use differs from provided IV"); } } else { if (returnedIv != null) { throw new ProviderException( "IV in use despite IV not being used by this transformation"); } } } @Override protected final void resetAll() { mIv = null; mIvHasBeenUsed = false; super.resetAll(); } } keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java +10 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,16 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { putSymmetricCipherImpl("AES/CTR/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding"); putSymmetricCipherImpl("DESede/CBC/NoPadding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding"); putSymmetricCipherImpl("DESede/CBC/PKCS7Padding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$PKCS7Padding"); putSymmetricCipherImpl("DESede/ECB/NoPadding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$NoPadding"); putSymmetricCipherImpl("DESede/ECB/PKCS7Padding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$PKCS7Padding"); putSymmetricCipherImpl("AES/GCM/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding"); Loading Loading
api/current.txt +17 −0 Original line number Diff line number Diff line Loading @@ -37856,6 +37856,7 @@ package android.security.keystore { method public boolean isDigestsSpecified(); method public boolean isInvalidatedByBiometricEnrollment(); method public boolean isRandomizedEncryptionRequired(); method public boolean isStrongBoxBacked(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationValidWhileOnBody(); } Loading @@ -37873,6 +37874,7 @@ package android.security.keystore { method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...); method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setIsStrongBoxBacked(boolean); method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int); method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date); method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); Loading Loading @@ -37933,6 +37935,7 @@ package android.security.keystore { field public static final java.lang.String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding"; field public static final java.lang.String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding"; field public static final java.lang.String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding"; field public static final deprecated java.lang.String KEY_ALGORITHM_3DES = "DESede"; field public static final java.lang.String KEY_ALGORITHM_AES = "AES"; field public static final java.lang.String KEY_ALGORITHM_EC = "EC"; field public static final java.lang.String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1"; Loading @@ -37943,11 +37946,13 @@ package android.security.keystore { field public static final java.lang.String KEY_ALGORITHM_RSA = "RSA"; field public static final int ORIGIN_GENERATED = 1; // 0x1 field public static final int ORIGIN_IMPORTED = 2; // 0x2 field public static final int ORIGIN_SECURELY_IMPORTED = 8; // 0x8 field public static final int ORIGIN_UNKNOWN = 4; // 0x4 field public static final int PURPOSE_DECRYPT = 2; // 0x2 field public static final int PURPOSE_ENCRYPT = 1; // 0x1 field public static final int PURPOSE_SIGN = 4; // 0x4 field public static final int PURPOSE_VERIFY = 8; // 0x8 field public static final int PURPOSE_WRAP_KEY = 32; // 0x20 field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1"; field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS"; } Loading Loading @@ -37987,12 +37992,24 @@ package android.security.keystore { method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); } public class StrongBoxUnavailableException extends java.security.ProviderException { ctor public StrongBoxUnavailableException(); } public class UserNotAuthenticatedException extends java.security.InvalidKeyException { ctor public UserNotAuthenticatedException(); ctor public UserNotAuthenticatedException(java.lang.String); ctor public UserNotAuthenticatedException(java.lang.String, java.lang.Throwable); } public class WrappedKeyEntry implements java.security.KeyStore.Entry { ctor public WrappedKeyEntry(byte[], java.lang.String, java.lang.String, java.security.spec.AlgorithmParameterSpec); method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); method public java.lang.String getTransformation(); method public byte[] getWrappedKeyBytes(); method public java.lang.String getWrappingKeyAlias(); } } package android.service.autofill {
core/java/android/security/keymaster/KeymasterDefs.java +3 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,7 @@ public final class KeymasterDefs { public static final int KM_ALGORITHM_RSA = 1; public static final int KM_ALGORITHM_EC = 3; public static final int KM_ALGORITHM_AES = 32; public static final int KM_ALGORITHM_3DES = 33; public static final int KM_ALGORITHM_HMAC = 128; // Block modes. Loading Loading @@ -131,6 +132,7 @@ public final class KeymasterDefs { public static final int KM_ORIGIN_GENERATED = 0; public static final int KM_ORIGIN_IMPORTED = 2; public static final int KM_ORIGIN_UNKNOWN = 3; public static final int KM_ORIGIN_SECURELY_IMPORTED = 4; // Key usability requirements. public static final int KM_BLOB_STANDALONE = 0; Loading @@ -141,6 +143,7 @@ public final class KeymasterDefs { public static final int KM_PURPOSE_DECRYPT = 1; public static final int KM_PURPOSE_SIGN = 2; public static final int KM_PURPOSE_VERIFY = 3; public static final int KM_PURPOSE_WRAP = 5; // Key formats. public static final int KM_KEY_FORMAT_X509 = 0; Loading
keystore/java/android/security/KeyStore.java +13 −0 Original line number Diff line number Diff line Loading @@ -510,6 +510,19 @@ public class KeyStore { return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics); } public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, KeyCharacteristics outCharacteristics) { try { return mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid, outCharacteristics); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; } } public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid) { try { Loading
keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java 0 → 100644 +298 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * 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 android.security.keystore; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.ProviderException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.util.Arrays; import javax.crypto.CipherSpi; import javax.crypto.spec.IvParameterSpec; /** * Base class for Android Keystore 3DES {@link CipherSpi} implementations. * * @hide */ public class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase { private static final int BLOCK_SIZE_BYTES = 8; private final int mKeymasterBlockMode; private final int mKeymasterPadding; /** Whether this transformation requires an IV. */ private final boolean mIvRequired; private byte[] mIv; /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */ private boolean mIvHasBeenUsed; AndroidKeyStore3DESCipherSpi( int keymasterBlockMode, int keymasterPadding, boolean ivRequired) { mKeymasterBlockMode = keymasterBlockMode; mKeymasterPadding = keymasterPadding; mIvRequired = ivRequired; } abstract static class ECB extends AndroidKeyStore3DESCipherSpi { protected ECB(int keymasterPadding) { super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false); } public static class NoPadding extends ECB { public NoPadding() { super(KeymasterDefs.KM_PAD_NONE); } } public static class PKCS7Padding extends ECB { public PKCS7Padding() { super(KeymasterDefs.KM_PAD_PKCS7); } } } abstract static class CBC extends AndroidKeyStore3DESCipherSpi { protected CBC(int keymasterPadding) { super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true); } public static class NoPadding extends CBC { public NoPadding() { super(KeymasterDefs.KM_PAD_NONE); } } public static class PKCS7Padding extends CBC { public PKCS7Padding() { super(KeymasterDefs.KM_PAD_PKCS7); } } } @Override protected void initKey(int i, Key key) throws InvalidKeyException { if (!(key instanceof AndroidKeyStoreSecretKey)) { throw new InvalidKeyException( "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); } if (!KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(key.getAlgorithm())) { throw new InvalidKeyException( "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " + KeyProperties.KEY_ALGORITHM_3DES + " supported"); } setKey((AndroidKeyStoreSecretKey) key); } @Override protected int engineGetBlockSize() { return BLOCK_SIZE_BYTES; } @Override protected int engineGetOutputSize(int inputLen) { return inputLen + 3 * BLOCK_SIZE_BYTES; } @Override protected final byte[] engineGetIV() { return ArrayUtils.cloneIfNotEmpty(mIv); } @Override protected AlgorithmParameters engineGetParameters() { if (!mIvRequired) { return null; } if ((mIv != null) && (mIv.length > 0)) { try { AlgorithmParameters params = AlgorithmParameters.getInstance("DESede"); params.init(new IvParameterSpec(mIv)); return params; } catch (NoSuchAlgorithmException e) { throw new ProviderException( "Failed to obtain 3DES AlgorithmParameters", e); } catch (InvalidParameterSpecException e) { throw new ProviderException( "Failed to initialize 3DES AlgorithmParameters with an IV", e); } } return null; } @Override protected void initAlgorithmSpecificParameters() throws InvalidKeyException { if (!mIvRequired) { return; } // IV is used if (!isEncrypting()) { throw new InvalidKeyException("IV required when decrypting" + ". Use IvParameterSpec or AlgorithmParameters to provide it."); } } @Override protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { if (!mIvRequired) { if (params != null) { throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); } return; } // IV is used if (params == null) { if (!isEncrypting()) { // IV must be provided by the caller throw new InvalidAlgorithmParameterException( "IvParameterSpec must be provided when decrypting"); } return; } if (!(params instanceof IvParameterSpec)) { throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported"); } mIv = ((IvParameterSpec) params).getIV(); if (mIv == null) { throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec"); } } @Override protected void initAlgorithmSpecificParameters(AlgorithmParameters params) throws InvalidAlgorithmParameterException { if (!mIvRequired) { if (params != null) { throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params); } return; } // IV is used if (params == null) { if (!isEncrypting()) { // IV must be provided by the caller throw new InvalidAlgorithmParameterException("IV required when decrypting" + ". Use IvParameterSpec or AlgorithmParameters to provide it."); } return; } if (!"DESede".equalsIgnoreCase(params.getAlgorithm())) { throw new InvalidAlgorithmParameterException( "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm() + ". Supported: DESede"); } IvParameterSpec ivSpec; try { ivSpec = params.getParameterSpec(IvParameterSpec.class); } catch (InvalidParameterSpecException e) { if (!isEncrypting()) { // IV must be provided by the caller throw new InvalidAlgorithmParameterException("IV required when decrypting" + ", but not found in parameters: " + params, e); } mIv = null; return; } mIv = ivSpec.getIV(); if (mIv == null) { throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters"); } } @Override protected final int getAdditionalEntropyAmountForBegin() { if ((mIvRequired) && (mIv == null) && (isEncrypting())) { // IV will need to be generated return BLOCK_SIZE_BYTES; } return 0; } @Override protected int getAdditionalEntropyAmountForFinish() { return 0; } @Override protected void addAlgorithmSpecificParametersToBegin(KeymasterArguments keymasterArgs) { if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) { // IV is being reused for encryption: this violates security best practices. throw new IllegalStateException( "IV has already been used. Reusing IV in encryption mode violates security best" + " practices."); } keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_3DES); keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode); keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding); if ((mIvRequired) && (mIv != null)) { keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv); } } @Override protected void loadAlgorithmSpecificParametersFromBeginResult( KeymasterArguments keymasterArgs) { mIvHasBeenUsed = true; // NOTE: Keymaster doesn't always return an IV, even if it's used. byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null); if ((returnedIv != null) && (returnedIv.length == 0)) { returnedIv = null; } if (mIvRequired) { if (mIv == null) { mIv = returnedIv; } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { throw new ProviderException("IV in use differs from provided IV"); } } else { if (returnedIv != null) { throw new ProviderException( "IV in use despite IV not being used by this transformation"); } } } @Override protected final void resetAll() { mIv = null; mIvHasBeenUsed = false; super.resetAll(); } }
keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java +10 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,16 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { putSymmetricCipherImpl("AES/CTR/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding"); putSymmetricCipherImpl("DESede/CBC/NoPadding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding"); putSymmetricCipherImpl("DESede/CBC/PKCS7Padding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$PKCS7Padding"); putSymmetricCipherImpl("DESede/ECB/NoPadding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$NoPadding"); putSymmetricCipherImpl("DESede/ECB/PKCS7Padding", PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$PKCS7Padding"); putSymmetricCipherImpl("AES/GCM/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding"); Loading