blob: 67f75c26b451c08733f00b02b9fe6165a47f401c [file] [log] [blame]
Alex Klyubincc21bb32015-03-31 16:50:37 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Alex Klyubind23a1f72015-03-27 14:39:28 -070017package android.security;
18
Alex Klyubin5927c9f2015-04-10 13:28:03 -070019import android.security.keymaster.KeymasterDefs;
Alex Klyubind23a1f72015-03-27 14:39:28 -070020
Alex Klyubin5927c9f2015-04-10 13:28:03 -070021import libcore.util.EmptyArray;
22
23import java.util.Collection;
24import java.util.Locale;
Alex Klyubinacc835f2015-03-31 15:26:56 -070025
Alex Klyubind23a1f72015-03-27 14:39:28 -070026/**
27 * @hide
28 */
29public abstract class KeymasterUtils {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070030
Alex Klyubind23a1f72015-03-27 14:39:28 -070031 private KeymasterUtils() {}
32
Alex Klyubin5927c9f2015-04-10 13:28:03 -070033 public static int getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
34 if ("AES".equalsIgnoreCase(jcaKeyAlgorithm)) {
35 return KeymasterDefs.KM_ALGORITHM_AES;
36 } else if (jcaKeyAlgorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
37 return KeymasterDefs.KM_ALGORITHM_HMAC;
Alex Klyubinacc835f2015-03-31 15:26:56 -070038 } else {
Alex Klyubin5927c9f2015-04-10 13:28:03 -070039 throw new IllegalArgumentException(
40 "Unsupported secret key algorithm: " + jcaKeyAlgorithm);
Alex Klyubinacc835f2015-03-31 15:26:56 -070041 }
42 }
43
Alex Klyubin5927c9f2015-04-10 13:28:03 -070044 public static String getJcaSecretKeyAlgorithm(int keymasterAlgorithm, int keymasterDigest) {
45 switch (keymasterAlgorithm) {
46 case KeymasterDefs.KM_ALGORITHM_AES:
47 if (keymasterDigest != -1) {
48 throw new IllegalArgumentException(
49 "Digest not supported for AES key: " + keymasterDigest);
50 }
51 return "AES";
52 case KeymasterDefs.KM_ALGORITHM_HMAC:
53 switch (keymasterDigest) {
54 case KeymasterDefs.KM_DIGEST_SHA1:
55 return "HmacSHA1";
56 case KeymasterDefs.KM_DIGEST_SHA_2_224:
57 return "HmacSHA224";
58 case KeymasterDefs.KM_DIGEST_SHA_2_256:
59 return "HmacSHA256";
60 case KeymasterDefs.KM_DIGEST_SHA_2_384:
61 return "HmacSHA384";
62 case KeymasterDefs.KM_DIGEST_SHA_2_512:
63 return "HmacSHA512";
64 default:
65 throw new IllegalArgumentException(
66 "Unsupported HMAC digest: " + keymasterDigest);
67 }
68 default:
69 throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
70 }
Alex Klyubinacc835f2015-03-31 15:26:56 -070071 }
72
Alex Klyubin5927c9f2015-04-10 13:28:03 -070073 public static String getJcaKeyPairAlgorithmFromKeymasterAlgorithm(int keymasterAlgorithm) {
74 switch (keymasterAlgorithm) {
75 case KeymasterDefs.KM_ALGORITHM_RSA:
76 return "RSA";
77 case KeymasterDefs.KM_ALGORITHM_EC:
78 return "EC";
79 default:
80 throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
81 }
82 }
83
84 public static int getKeymasterDigestfromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
85 String algorithmUpper = jcaKeyAlgorithm.toUpperCase(Locale.US);
86 if (algorithmUpper.startsWith("HMAC")) {
87 String digestUpper = algorithmUpper.substring("HMAC".length());
88 switch (digestUpper) {
89 case "MD5":
90 return KeymasterDefs.KM_DIGEST_MD5;
91 case "SHA1":
92 return KeymasterDefs.KM_DIGEST_SHA1;
93 case "SHA224":
94 return KeymasterDefs.KM_DIGEST_SHA_2_224;
95 case "SHA256":
96 return KeymasterDefs.KM_DIGEST_SHA_2_256;
97 case "SHA384":
98 return KeymasterDefs.KM_DIGEST_SHA_2_384;
99 case "SHA512":
100 return KeymasterDefs.KM_DIGEST_SHA_2_512;
101 default:
102 throw new IllegalArgumentException("Unsupported HMAC digest: " + digestUpper);
103 }
104 } else {
105 return -1;
106 }
107 }
108
109 public static int getKeymasterDigestFromJcaDigestAlgorithm(String jcaDigestAlgorithm) {
110 if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-1")) {
111 return KeymasterDefs.KM_DIGEST_SHA1;
112 } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-224")) {
113 return KeymasterDefs.KM_DIGEST_SHA_2_224;
114 } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-256")) {
115 return KeymasterDefs.KM_DIGEST_SHA_2_256;
116 } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-384")) {
117 return KeymasterDefs.KM_DIGEST_SHA_2_384;
118 } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-512")) {
119 return KeymasterDefs.KM_DIGEST_SHA_2_512;
120 } else if (jcaDigestAlgorithm.equalsIgnoreCase("NONE")) {
121 return KeymasterDefs.KM_DIGEST_NONE;
122 } else if (jcaDigestAlgorithm.equalsIgnoreCase("MD5")) {
123 return KeymasterDefs.KM_DIGEST_MD5;
124 } else {
125 throw new IllegalArgumentException(
126 "Unsupported digest algorithm: " + jcaDigestAlgorithm);
127 }
128 }
129
130 public static String getJcaDigestAlgorithmFromKeymasterDigest(int keymasterDigest) {
131 switch (keymasterDigest) {
132 case KeymasterDefs.KM_DIGEST_NONE:
133 return "NONE";
134 case KeymasterDefs.KM_DIGEST_MD5:
135 return "MD5";
136 case KeymasterDefs.KM_DIGEST_SHA1:
137 return "SHA-1";
138 case KeymasterDefs.KM_DIGEST_SHA_2_224:
139 return "SHA-224";
140 case KeymasterDefs.KM_DIGEST_SHA_2_256:
141 return "SHA-256";
142 case KeymasterDefs.KM_DIGEST_SHA_2_384:
143 return "SHA-384";
144 case KeymasterDefs.KM_DIGEST_SHA_2_512:
145 return "SHA-512";
146 default:
147 throw new IllegalArgumentException(
148 "Unsupported digest algorithm: " + keymasterDigest);
149 }
150 }
151
152 public static String[] getJcaDigestAlgorithmsFromKeymasterDigests(
153 Collection<Integer> keymasterDigests) {
154 if (keymasterDigests.isEmpty()) {
155 return EmptyArray.STRING;
156 }
157 String[] result = new String[keymasterDigests.size()];
158 int offset = 0;
159 for (int keymasterDigest : keymasterDigests) {
160 result[offset] = getJcaDigestAlgorithmFromKeymasterDigest(keymasterDigest);
161 offset++;
Alex Klyubinacc835f2015-03-31 15:26:56 -0700162 }
163 return result;
164 }
165
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700166 public static int[] getKeymasterDigestsFromJcaDigestAlgorithms(String[] jcaDigestAlgorithms) {
167 if ((jcaDigestAlgorithms == null) || (jcaDigestAlgorithms.length == 0)) {
168 return EmptyArray.INT;
Alex Klyubinacc835f2015-03-31 15:26:56 -0700169 }
Alex Klyubin5927c9f2015-04-10 13:28:03 -0700170 int[] result = new int[jcaDigestAlgorithms.length];
171 int offset = 0;
172 for (String jcaDigestAlgorithm : jcaDigestAlgorithms) {
173 result[offset] = getKeymasterDigestFromJcaDigestAlgorithm(jcaDigestAlgorithm);
174 offset++;
175 }
176 return result;
177 }
178
179 public static int getDigestOutputSizeBytes(int keymasterDigest) {
180 switch (keymasterDigest) {
181 case KeymasterDefs.KM_DIGEST_NONE:
182 return -1;
183 case KeymasterDefs.KM_DIGEST_MD5:
184 return 128 / 8;
185 case KeymasterDefs.KM_DIGEST_SHA1:
186 return 160 / 8;
187 case KeymasterDefs.KM_DIGEST_SHA_2_224:
188 return 224 / 8;
189 case KeymasterDefs.KM_DIGEST_SHA_2_256:
190 return 256 / 8;
191 case KeymasterDefs.KM_DIGEST_SHA_2_384:
192 return 384 / 8;
193 case KeymasterDefs.KM_DIGEST_SHA_2_512:
194 return 512 / 8;
195 default:
196 throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
197 }
198 }
199
200 public static int getKeymasterBlockModeFromJcaBlockMode(String jcaBlockMode) {
201 if ("ECB".equalsIgnoreCase(jcaBlockMode)) {
202 return KeymasterDefs.KM_MODE_ECB;
203 } else if ("CBC".equalsIgnoreCase(jcaBlockMode)) {
204 return KeymasterDefs.KM_MODE_CBC;
205 } else if ("CTR".equalsIgnoreCase(jcaBlockMode)) {
206 return KeymasterDefs.KM_MODE_CTR;
207 } else if ("GCM".equalsIgnoreCase(jcaBlockMode)) {
208 return KeymasterDefs.KM_MODE_GCM;
209 } else {
210 throw new IllegalArgumentException("Unsupported block mode: " + jcaBlockMode);
211 }
212 }
213
214 public static String getJcaBlockModeFromKeymasterBlockMode(int keymasterBlockMode) {
215 switch (keymasterBlockMode) {
216 case KeymasterDefs.KM_MODE_ECB:
217 return "ECB";
218 case KeymasterDefs.KM_MODE_CBC:
219 return "CBC";
220 case KeymasterDefs.KM_MODE_CTR:
221 return "CTR";
222 case KeymasterDefs.KM_MODE_GCM:
223 return "GCM";
224 default:
225 throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
226 }
227 }
228
229 public static String[] getJcaBlockModesFromKeymasterBlockModes(
230 Collection<Integer> keymasterBlockModes) {
231 if ((keymasterBlockModes == null) || (keymasterBlockModes.isEmpty())) {
232 return EmptyArray.STRING;
233 }
234 String[] result = new String[keymasterBlockModes.size()];
235 int offset = 0;
236 for (int keymasterBlockMode : keymasterBlockModes) {
237 result[offset] = getJcaBlockModeFromKeymasterBlockMode(keymasterBlockMode);
238 offset++;
239 }
240 return result;
241 }
242
243 public static int[] getKeymasterBlockModesFromJcaBlockModes(String[] jcaBlockModes) {
244 if ((jcaBlockModes == null) || (jcaBlockModes.length == 0)) {
245 return EmptyArray.INT;
246 }
247 int[] result = new int[jcaBlockModes.length];
248 for (int i = 0; i < jcaBlockModes.length; i++) {
249 result[i] = getKeymasterBlockModeFromJcaBlockMode(jcaBlockModes[i]);
250 }
251 return result;
252 }
253
254 public static boolean isKeymasterBlockModeIndCpaCompatible(int keymasterBlockMode) {
255 switch (keymasterBlockMode) {
256 case KeymasterDefs.KM_MODE_ECB:
257 return false;
258 case KeymasterDefs.KM_MODE_CBC:
259 case KeymasterDefs.KM_MODE_CTR:
260 case KeymasterDefs.KM_MODE_GCM:
261 return true;
262 default:
263 throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
264 }
265 }
266
267 public static int getKeymasterPaddingFromJcaEncryptionPadding(String jcaPadding) {
268 if ("NoPadding".equalsIgnoreCase(jcaPadding)) {
269 return KeymasterDefs.KM_PAD_NONE;
270 } else if ("PKCS7Padding".equalsIgnoreCase(jcaPadding)) {
271 return KeymasterDefs.KM_PAD_PKCS7;
272 } else if ("PKCS1Padding".equalsIgnoreCase(jcaPadding)) {
273 return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
274 } else if ("OEAPPadding".equalsIgnoreCase(jcaPadding)) {
275 return KeymasterDefs.KM_PAD_RSA_OAEP;
276 } else {
277 throw new IllegalArgumentException(
278 "Unsupported encryption padding scheme: " + jcaPadding);
279 }
280 }
281
282 public static String getJcaEncryptionPaddingFromKeymasterPadding(int keymasterPadding) {
283 switch (keymasterPadding) {
284 case KeymasterDefs.KM_PAD_NONE:
285 return "NoPadding";
286 case KeymasterDefs.KM_PAD_PKCS7:
287 return "PKCS7Padding";
288 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
289 return "PKCS1Padding";
290 case KeymasterDefs.KM_PAD_RSA_OAEP:
291 return "OEAPPadding";
292 default:
293 throw new IllegalArgumentException(
294 "Unsupported encryption padding: " + keymasterPadding);
295 }
296 }
297
298 public static int getKeymasterPaddingFromJcaSignaturePadding(String jcaPadding) {
299 if ("PKCS#1".equalsIgnoreCase(jcaPadding)) {
300 return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
301 } if ("PSS".equalsIgnoreCase(jcaPadding)) {
302 return KeymasterDefs.KM_PAD_RSA_PSS;
303 } else {
304 throw new IllegalArgumentException(
305 "Unsupported signature padding scheme: " + jcaPadding);
306 }
307 }
308
309 public static String getJcaSignaturePaddingFromKeymasterPadding(int keymasterPadding) {
310 switch (keymasterPadding) {
311 case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
312 return "PKCS#1";
313 case KeymasterDefs.KM_PAD_RSA_PSS:
314 return "PSS";
315 default:
316 throw new IllegalArgumentException(
317 "Unsupported signature padding: " + keymasterPadding);
318 }
319 }
320
321 public static int[] getKeymasterPaddingsFromJcaEncryptionPaddings(String[] jcaPaddings) {
322 if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
323 return EmptyArray.INT;
324 }
325 int[] result = new int[jcaPaddings.length];
326 for (int i = 0; i < jcaPaddings.length; i++) {
327 result[i] = getKeymasterPaddingFromJcaEncryptionPadding(jcaPaddings[i]);
328 }
329 return result;
330 }
331
332 public static int[] getKeymasterPaddingsFromJcaSignaturePaddings(String[] jcaPaddings) {
333 if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
334 return EmptyArray.INT;
335 }
336 int[] result = new int[jcaPaddings.length];
337 for (int i = 0; i < jcaPaddings.length; i++) {
338 result[i] = getKeymasterPaddingFromJcaSignaturePadding(jcaPaddings[i]);
339 }
340 return result;
Alex Klyubinacc835f2015-03-31 15:26:56 -0700341 }
Alex Klyubind23a1f72015-03-27 14:39:28 -0700342}