This replaces int-based enums from KeyStoreKeyConstraints with String values commonly used in JCA API. As part of under the hood refactoring: * KeyStoreKeyCharacteristics and KeyStoreKeyConstraints have been merged into KeyStoreKeyProperties. * KeymasterUtils methods operating on KeymasterArguments and KeymasterCharacteristics have been moved to their respective classes. Bug: 18088752 Change-Id: I9c8b984cb3c28184adb617e34d87f2837bd1d3a1
343 lines
14 KiB
Java
343 lines
14 KiB
Java
/*
|
|
* Copyright (C) 2015 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;
|
|
|
|
import android.security.keymaster.KeymasterDefs;
|
|
|
|
import libcore.util.EmptyArray;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Locale;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public abstract class KeymasterUtils {
|
|
|
|
private KeymasterUtils() {}
|
|
|
|
public static int getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
|
|
if ("AES".equalsIgnoreCase(jcaKeyAlgorithm)) {
|
|
return KeymasterDefs.KM_ALGORITHM_AES;
|
|
} else if (jcaKeyAlgorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
|
|
return KeymasterDefs.KM_ALGORITHM_HMAC;
|
|
} else {
|
|
throw new IllegalArgumentException(
|
|
"Unsupported secret key algorithm: " + jcaKeyAlgorithm);
|
|
}
|
|
}
|
|
|
|
public static String getJcaSecretKeyAlgorithm(int keymasterAlgorithm, int keymasterDigest) {
|
|
switch (keymasterAlgorithm) {
|
|
case KeymasterDefs.KM_ALGORITHM_AES:
|
|
if (keymasterDigest != -1) {
|
|
throw new IllegalArgumentException(
|
|
"Digest not supported for AES key: " + keymasterDigest);
|
|
}
|
|
return "AES";
|
|
case KeymasterDefs.KM_ALGORITHM_HMAC:
|
|
switch (keymasterDigest) {
|
|
case KeymasterDefs.KM_DIGEST_SHA1:
|
|
return "HmacSHA1";
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_224:
|
|
return "HmacSHA224";
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_256:
|
|
return "HmacSHA256";
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_384:
|
|
return "HmacSHA384";
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_512:
|
|
return "HmacSHA512";
|
|
default:
|
|
throw new IllegalArgumentException(
|
|
"Unsupported HMAC digest: " + keymasterDigest);
|
|
}
|
|
default:
|
|
throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
|
|
}
|
|
}
|
|
|
|
public static String getJcaKeyPairAlgorithmFromKeymasterAlgorithm(int keymasterAlgorithm) {
|
|
switch (keymasterAlgorithm) {
|
|
case KeymasterDefs.KM_ALGORITHM_RSA:
|
|
return "RSA";
|
|
case KeymasterDefs.KM_ALGORITHM_EC:
|
|
return "EC";
|
|
default:
|
|
throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
|
|
}
|
|
}
|
|
|
|
public static int getKeymasterDigestfromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
|
|
String algorithmUpper = jcaKeyAlgorithm.toUpperCase(Locale.US);
|
|
if (algorithmUpper.startsWith("HMAC")) {
|
|
String digestUpper = algorithmUpper.substring("HMAC".length());
|
|
switch (digestUpper) {
|
|
case "MD5":
|
|
return KeymasterDefs.KM_DIGEST_MD5;
|
|
case "SHA1":
|
|
return KeymasterDefs.KM_DIGEST_SHA1;
|
|
case "SHA224":
|
|
return KeymasterDefs.KM_DIGEST_SHA_2_224;
|
|
case "SHA256":
|
|
return KeymasterDefs.KM_DIGEST_SHA_2_256;
|
|
case "SHA384":
|
|
return KeymasterDefs.KM_DIGEST_SHA_2_384;
|
|
case "SHA512":
|
|
return KeymasterDefs.KM_DIGEST_SHA_2_512;
|
|
default:
|
|
throw new IllegalArgumentException("Unsupported HMAC digest: " + digestUpper);
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public static int getKeymasterDigestFromJcaDigestAlgorithm(String jcaDigestAlgorithm) {
|
|
if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-1")) {
|
|
return KeymasterDefs.KM_DIGEST_SHA1;
|
|
} else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-224")) {
|
|
return KeymasterDefs.KM_DIGEST_SHA_2_224;
|
|
} else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-256")) {
|
|
return KeymasterDefs.KM_DIGEST_SHA_2_256;
|
|
} else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-384")) {
|
|
return KeymasterDefs.KM_DIGEST_SHA_2_384;
|
|
} else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-512")) {
|
|
return KeymasterDefs.KM_DIGEST_SHA_2_512;
|
|
} else if (jcaDigestAlgorithm.equalsIgnoreCase("NONE")) {
|
|
return KeymasterDefs.KM_DIGEST_NONE;
|
|
} else if (jcaDigestAlgorithm.equalsIgnoreCase("MD5")) {
|
|
return KeymasterDefs.KM_DIGEST_MD5;
|
|
} else {
|
|
throw new IllegalArgumentException(
|
|
"Unsupported digest algorithm: " + jcaDigestAlgorithm);
|
|
}
|
|
}
|
|
|
|
public static String getJcaDigestAlgorithmFromKeymasterDigest(int keymasterDigest) {
|
|
switch (keymasterDigest) {
|
|
case KeymasterDefs.KM_DIGEST_NONE:
|
|
return "NONE";
|
|
case KeymasterDefs.KM_DIGEST_MD5:
|
|
return "MD5";
|
|
case KeymasterDefs.KM_DIGEST_SHA1:
|
|
return "SHA-1";
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_224:
|
|
return "SHA-224";
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_256:
|
|
return "SHA-256";
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_384:
|
|
return "SHA-384";
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_512:
|
|
return "SHA-512";
|
|
default:
|
|
throw new IllegalArgumentException(
|
|
"Unsupported digest algorithm: " + keymasterDigest);
|
|
}
|
|
}
|
|
|
|
public static String[] getJcaDigestAlgorithmsFromKeymasterDigests(
|
|
Collection<Integer> keymasterDigests) {
|
|
if (keymasterDigests.isEmpty()) {
|
|
return EmptyArray.STRING;
|
|
}
|
|
String[] result = new String[keymasterDigests.size()];
|
|
int offset = 0;
|
|
for (int keymasterDigest : keymasterDigests) {
|
|
result[offset] = getJcaDigestAlgorithmFromKeymasterDigest(keymasterDigest);
|
|
offset++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static int[] getKeymasterDigestsFromJcaDigestAlgorithms(String[] jcaDigestAlgorithms) {
|
|
if ((jcaDigestAlgorithms == null) || (jcaDigestAlgorithms.length == 0)) {
|
|
return EmptyArray.INT;
|
|
}
|
|
int[] result = new int[jcaDigestAlgorithms.length];
|
|
int offset = 0;
|
|
for (String jcaDigestAlgorithm : jcaDigestAlgorithms) {
|
|
result[offset] = getKeymasterDigestFromJcaDigestAlgorithm(jcaDigestAlgorithm);
|
|
offset++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static int getDigestOutputSizeBytes(int keymasterDigest) {
|
|
switch (keymasterDigest) {
|
|
case KeymasterDefs.KM_DIGEST_NONE:
|
|
return -1;
|
|
case KeymasterDefs.KM_DIGEST_MD5:
|
|
return 128 / 8;
|
|
case KeymasterDefs.KM_DIGEST_SHA1:
|
|
return 160 / 8;
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_224:
|
|
return 224 / 8;
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_256:
|
|
return 256 / 8;
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_384:
|
|
return 384 / 8;
|
|
case KeymasterDefs.KM_DIGEST_SHA_2_512:
|
|
return 512 / 8;
|
|
default:
|
|
throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
|
|
}
|
|
}
|
|
|
|
public static int getKeymasterBlockModeFromJcaBlockMode(String jcaBlockMode) {
|
|
if ("ECB".equalsIgnoreCase(jcaBlockMode)) {
|
|
return KeymasterDefs.KM_MODE_ECB;
|
|
} else if ("CBC".equalsIgnoreCase(jcaBlockMode)) {
|
|
return KeymasterDefs.KM_MODE_CBC;
|
|
} else if ("CTR".equalsIgnoreCase(jcaBlockMode)) {
|
|
return KeymasterDefs.KM_MODE_CTR;
|
|
} else if ("GCM".equalsIgnoreCase(jcaBlockMode)) {
|
|
return KeymasterDefs.KM_MODE_GCM;
|
|
} else {
|
|
throw new IllegalArgumentException("Unsupported block mode: " + jcaBlockMode);
|
|
}
|
|
}
|
|
|
|
public static String getJcaBlockModeFromKeymasterBlockMode(int keymasterBlockMode) {
|
|
switch (keymasterBlockMode) {
|
|
case KeymasterDefs.KM_MODE_ECB:
|
|
return "ECB";
|
|
case KeymasterDefs.KM_MODE_CBC:
|
|
return "CBC";
|
|
case KeymasterDefs.KM_MODE_CTR:
|
|
return "CTR";
|
|
case KeymasterDefs.KM_MODE_GCM:
|
|
return "GCM";
|
|
default:
|
|
throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
|
|
}
|
|
}
|
|
|
|
public static String[] getJcaBlockModesFromKeymasterBlockModes(
|
|
Collection<Integer> keymasterBlockModes) {
|
|
if ((keymasterBlockModes == null) || (keymasterBlockModes.isEmpty())) {
|
|
return EmptyArray.STRING;
|
|
}
|
|
String[] result = new String[keymasterBlockModes.size()];
|
|
int offset = 0;
|
|
for (int keymasterBlockMode : keymasterBlockModes) {
|
|
result[offset] = getJcaBlockModeFromKeymasterBlockMode(keymasterBlockMode);
|
|
offset++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static int[] getKeymasterBlockModesFromJcaBlockModes(String[] jcaBlockModes) {
|
|
if ((jcaBlockModes == null) || (jcaBlockModes.length == 0)) {
|
|
return EmptyArray.INT;
|
|
}
|
|
int[] result = new int[jcaBlockModes.length];
|
|
for (int i = 0; i < jcaBlockModes.length; i++) {
|
|
result[i] = getKeymasterBlockModeFromJcaBlockMode(jcaBlockModes[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static boolean isKeymasterBlockModeIndCpaCompatible(int keymasterBlockMode) {
|
|
switch (keymasterBlockMode) {
|
|
case KeymasterDefs.KM_MODE_ECB:
|
|
return false;
|
|
case KeymasterDefs.KM_MODE_CBC:
|
|
case KeymasterDefs.KM_MODE_CTR:
|
|
case KeymasterDefs.KM_MODE_GCM:
|
|
return true;
|
|
default:
|
|
throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
|
|
}
|
|
}
|
|
|
|
public static int getKeymasterPaddingFromJcaEncryptionPadding(String jcaPadding) {
|
|
if ("NoPadding".equalsIgnoreCase(jcaPadding)) {
|
|
return KeymasterDefs.KM_PAD_NONE;
|
|
} else if ("PKCS7Padding".equalsIgnoreCase(jcaPadding)) {
|
|
return KeymasterDefs.KM_PAD_PKCS7;
|
|
} else if ("PKCS1Padding".equalsIgnoreCase(jcaPadding)) {
|
|
return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
|
|
} else if ("OEAPPadding".equalsIgnoreCase(jcaPadding)) {
|
|
return KeymasterDefs.KM_PAD_RSA_OAEP;
|
|
} else {
|
|
throw new IllegalArgumentException(
|
|
"Unsupported encryption padding scheme: " + jcaPadding);
|
|
}
|
|
}
|
|
|
|
public static String getJcaEncryptionPaddingFromKeymasterPadding(int keymasterPadding) {
|
|
switch (keymasterPadding) {
|
|
case KeymasterDefs.KM_PAD_NONE:
|
|
return "NoPadding";
|
|
case KeymasterDefs.KM_PAD_PKCS7:
|
|
return "PKCS7Padding";
|
|
case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
|
|
return "PKCS1Padding";
|
|
case KeymasterDefs.KM_PAD_RSA_OAEP:
|
|
return "OEAPPadding";
|
|
default:
|
|
throw new IllegalArgumentException(
|
|
"Unsupported encryption padding: " + keymasterPadding);
|
|
}
|
|
}
|
|
|
|
public static int getKeymasterPaddingFromJcaSignaturePadding(String jcaPadding) {
|
|
if ("PKCS#1".equalsIgnoreCase(jcaPadding)) {
|
|
return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
|
|
} if ("PSS".equalsIgnoreCase(jcaPadding)) {
|
|
return KeymasterDefs.KM_PAD_RSA_PSS;
|
|
} else {
|
|
throw new IllegalArgumentException(
|
|
"Unsupported signature padding scheme: " + jcaPadding);
|
|
}
|
|
}
|
|
|
|
public static String getJcaSignaturePaddingFromKeymasterPadding(int keymasterPadding) {
|
|
switch (keymasterPadding) {
|
|
case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
|
|
return "PKCS#1";
|
|
case KeymasterDefs.KM_PAD_RSA_PSS:
|
|
return "PSS";
|
|
default:
|
|
throw new IllegalArgumentException(
|
|
"Unsupported signature padding: " + keymasterPadding);
|
|
}
|
|
}
|
|
|
|
public static int[] getKeymasterPaddingsFromJcaEncryptionPaddings(String[] jcaPaddings) {
|
|
if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
|
|
return EmptyArray.INT;
|
|
}
|
|
int[] result = new int[jcaPaddings.length];
|
|
for (int i = 0; i < jcaPaddings.length; i++) {
|
|
result[i] = getKeymasterPaddingFromJcaEncryptionPadding(jcaPaddings[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static int[] getKeymasterPaddingsFromJcaSignaturePaddings(String[] jcaPaddings) {
|
|
if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
|
|
return EmptyArray.INT;
|
|
}
|
|
int[] result = new int[jcaPaddings.length];
|
|
for (int i = 0; i < jcaPaddings.length; i++) {
|
|
result[i] = getKeymasterPaddingFromJcaSignaturePadding(jcaPaddings[i]);
|
|
}
|
|
return result;
|
|
}
|
|
}
|