1 /* 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 17 package android.security.keystore2; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.hardware.security.keymint.KeyParameter; 22 import android.security.keymaster.KeymasterDefs; 23 import android.security.keystore.KeyProperties; 24 import android.system.keystore2.Authorization; 25 26 import java.security.AlgorithmParameters; 27 import java.security.InvalidAlgorithmParameterException; 28 import java.security.InvalidKeyException; 29 import java.security.Key; 30 import java.security.NoSuchAlgorithmException; 31 import java.security.PrivateKey; 32 import java.security.ProviderException; 33 import java.security.spec.AlgorithmParameterSpec; 34 import java.security.spec.InvalidParameterSpecException; 35 import java.security.spec.MGF1ParameterSpec; 36 import java.util.List; 37 38 import javax.crypto.Cipher; 39 import javax.crypto.CipherSpi; 40 import javax.crypto.spec.OAEPParameterSpec; 41 import javax.crypto.spec.PSource; 42 43 /** 44 * Base class for {@link CipherSpi} providing Android KeyStore backed RSA encryption/decryption. 45 * 46 * @hide 47 */ 48 abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase { 49 50 /** 51 * Raw RSA cipher without any padding. 52 */ 53 public static final class NoPadding extends AndroidKeyStoreRSACipherSpi { NoPadding()54 public NoPadding() { 55 super(KeymasterDefs.KM_PAD_NONE); 56 } 57 58 @Override adjustConfigForEncryptingWithPrivateKey()59 protected boolean adjustConfigForEncryptingWithPrivateKey() { 60 // RSA encryption with no padding using private key is a way to implement raw RSA 61 // signatures which JCA does not expose via Signature. We thus have to support this. 62 setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN); 63 return true; 64 } 65 66 @Override initAlgorithmSpecificParameters()67 protected void initAlgorithmSpecificParameters() throws InvalidKeyException {} 68 69 @Override initAlgorithmSpecificParameters(@ullable AlgorithmParameterSpec params)70 protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameterSpec params) 71 throws InvalidAlgorithmParameterException { 72 if (params != null) { 73 throw new InvalidAlgorithmParameterException( 74 "Unexpected parameters: " + params + ". No parameters supported"); 75 } 76 } 77 78 @Override initAlgorithmSpecificParameters(@ullable AlgorithmParameters params)79 protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params) 80 throws InvalidAlgorithmParameterException { 81 82 if (params != null) { 83 throw new InvalidAlgorithmParameterException( 84 "Unexpected parameters: " + params + ". No parameters supported"); 85 } 86 } 87 88 @Override engineGetParameters()89 protected AlgorithmParameters engineGetParameters() { 90 return null; 91 } 92 93 @Override getAdditionalEntropyAmountForBegin()94 protected final int getAdditionalEntropyAmountForBegin() { 95 return 0; 96 } 97 98 @Override getAdditionalEntropyAmountForFinish()99 protected final int getAdditionalEntropyAmountForFinish() { 100 return 0; 101 } 102 } 103 104 /** 105 * RSA cipher with PKCS#1 v1.5 encryption padding. 106 */ 107 public static final class PKCS1Padding extends AndroidKeyStoreRSACipherSpi { PKCS1Padding()108 public PKCS1Padding() { 109 super(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT); 110 } 111 112 @Override adjustConfigForEncryptingWithPrivateKey()113 protected boolean adjustConfigForEncryptingWithPrivateKey() { 114 // RSA encryption with PCKS#1 padding using private key is a way to implement RSA 115 // signatures with PKCS#1 padding. We have to support this for legacy reasons. 116 setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN); 117 setKeymasterPaddingOverride(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN); 118 return true; 119 } 120 121 @Override initAlgorithmSpecificParameters()122 protected void initAlgorithmSpecificParameters() throws InvalidKeyException {} 123 124 @Override initAlgorithmSpecificParameters(@ullable AlgorithmParameterSpec params)125 protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameterSpec params) 126 throws InvalidAlgorithmParameterException { 127 if (params != null) { 128 throw new InvalidAlgorithmParameterException( 129 "Unexpected parameters: " + params + ". No parameters supported"); 130 } 131 } 132 133 @Override initAlgorithmSpecificParameters(@ullable AlgorithmParameters params)134 protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params) 135 throws InvalidAlgorithmParameterException { 136 137 if (params != null) { 138 throw new InvalidAlgorithmParameterException( 139 "Unexpected parameters: " + params + ". No parameters supported"); 140 } 141 } 142 143 @Override engineGetParameters()144 protected AlgorithmParameters engineGetParameters() { 145 return null; 146 } 147 148 @Override getAdditionalEntropyAmountForBegin()149 protected final int getAdditionalEntropyAmountForBegin() { 150 return 0; 151 } 152 153 @Override getAdditionalEntropyAmountForFinish()154 protected final int getAdditionalEntropyAmountForFinish() { 155 return (isEncrypting()) ? getModulusSizeBytes() : 0; 156 } 157 } 158 159 /** 160 * RSA cipher with OAEP encryption padding. 161 */ 162 abstract static class OAEPWithMGF1Padding extends AndroidKeyStoreRSACipherSpi { 163 164 private static final String MGF_ALGORITHM_MGF1 = "MGF1"; 165 166 private int mKeymasterDigest = -1; 167 private int mDigestOutputSizeBytes; 168 private int mKeymasterMgf1Digest = KeymasterDefs.KM_DIGEST_SHA1; // Default MGF1 digest 169 OAEPWithMGF1Padding(int keymasterDigest)170 OAEPWithMGF1Padding(int keymasterDigest) { 171 super(KeymasterDefs.KM_PAD_RSA_OAEP); 172 mKeymasterDigest = keymasterDigest; 173 mDigestOutputSizeBytes = 174 (KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8; 175 } 176 177 @Override initAlgorithmSpecificParameters()178 protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {} 179 180 @Override initAlgorithmSpecificParameters( @ullable AlgorithmParameterSpec params)181 protected final void initAlgorithmSpecificParameters( 182 @Nullable AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { 183 if (params == null) { 184 return; 185 } 186 187 if (!(params instanceof OAEPParameterSpec)) { 188 throw new InvalidAlgorithmParameterException( 189 "Unsupported parameter spec: " + params 190 + ". Only OAEPParameterSpec supported"); 191 } 192 OAEPParameterSpec spec = (OAEPParameterSpec) params; 193 if (!MGF_ALGORITHM_MGF1.equalsIgnoreCase(spec.getMGFAlgorithm())) { 194 throw new InvalidAlgorithmParameterException( 195 "Unsupported MGF: " + spec.getMGFAlgorithm() 196 + ". Only " + MGF_ALGORITHM_MGF1 + " supported"); 197 } 198 String jcaDigest = spec.getDigestAlgorithm(); 199 int keymasterDigest; 200 try { 201 keymasterDigest = KeyProperties.Digest.toKeymaster(jcaDigest); 202 } catch (IllegalArgumentException e) { 203 throw new InvalidAlgorithmParameterException( 204 "Unsupported digest: " + jcaDigest, e); 205 } 206 switch (keymasterDigest) { 207 case KeymasterDefs.KM_DIGEST_SHA1: 208 case KeymasterDefs.KM_DIGEST_SHA_2_224: 209 case KeymasterDefs.KM_DIGEST_SHA_2_256: 210 case KeymasterDefs.KM_DIGEST_SHA_2_384: 211 case KeymasterDefs.KM_DIGEST_SHA_2_512: 212 // Permitted. 213 break; 214 default: 215 throw new InvalidAlgorithmParameterException( 216 "Unsupported digest: " + jcaDigest); 217 } 218 AlgorithmParameterSpec mgfParams = spec.getMGFParameters(); 219 if (mgfParams == null) { 220 throw new InvalidAlgorithmParameterException("MGF parameters must be provided"); 221 } 222 // Check whether MGF parameters match the OAEPParameterSpec 223 if (!(mgfParams instanceof MGF1ParameterSpec)) { 224 throw new InvalidAlgorithmParameterException("Unsupported MGF parameters" 225 + ": " + mgfParams + ". Only MGF1ParameterSpec supported"); 226 } 227 MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) mgfParams; 228 String mgf1JcaDigest = mgfSpec.getDigestAlgorithm(); 229 PSource pSource = spec.getPSource(); 230 if (!(pSource instanceof PSource.PSpecified)) { 231 throw new InvalidAlgorithmParameterException( 232 "Unsupported source of encoding input P: " + pSource 233 + ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported"); 234 } 235 PSource.PSpecified pSourceSpecified = (PSource.PSpecified) pSource; 236 byte[] pSourceValue = pSourceSpecified.getValue(); 237 if ((pSourceValue != null) && (pSourceValue.length > 0)) { 238 throw new InvalidAlgorithmParameterException( 239 "Unsupported source of encoding input P: " + pSource 240 + ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported"); 241 } 242 mKeymasterDigest = keymasterDigest; 243 mKeymasterMgf1Digest = KeyProperties.Digest.toKeymaster(mgf1JcaDigest); 244 mDigestOutputSizeBytes = 245 (KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8; 246 } 247 248 @Override initAlgorithmSpecificParameters(@ullable AlgorithmParameters params)249 protected final void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params) 250 throws InvalidAlgorithmParameterException { 251 if (params == null) { 252 return; 253 } 254 255 OAEPParameterSpec spec; 256 try { 257 spec = params.getParameterSpec(OAEPParameterSpec.class); 258 } catch (InvalidParameterSpecException e) { 259 throw new InvalidAlgorithmParameterException("OAEP parameters required" 260 + ", but not found in parameters: " + params, e); 261 } 262 if (spec == null) { 263 throw new InvalidAlgorithmParameterException("OAEP parameters required" 264 + ", but not provided in parameters: " + params); 265 } 266 initAlgorithmSpecificParameters(spec); 267 } 268 269 @Override engineGetParameters()270 protected final AlgorithmParameters engineGetParameters() { 271 OAEPParameterSpec spec = 272 new OAEPParameterSpec( 273 KeyProperties.Digest.fromKeymaster(mKeymasterDigest), 274 MGF_ALGORITHM_MGF1, 275 KeyProperties.Digest.fromKeymasterToMGF1ParameterSpec(mKeymasterMgf1Digest), 276 PSource.PSpecified.DEFAULT); 277 try { 278 AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP"); 279 params.init(spec); 280 return params; 281 } catch (NoSuchAlgorithmException e) { 282 throw new ProviderException( 283 "Failed to obtain OAEP AlgorithmParameters", e); 284 } catch (InvalidParameterSpecException e) { 285 throw new ProviderException( 286 "Failed to initialize OAEP AlgorithmParameters with an IV", 287 e); 288 } 289 } 290 isMgfDigestTagPresentInKeyProperties( Authorization[] keyCharacteristics)291 private static boolean isMgfDigestTagPresentInKeyProperties( 292 Authorization[] keyCharacteristics) { 293 for (Authorization authorization : keyCharacteristics) { 294 if (authorization.keyParameter.tag == KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST) { 295 return true; 296 } 297 } 298 299 return false; 300 } 301 302 @Override addAlgorithmSpecificParametersToBegin( @onNull List<KeyParameter> parameters, Authorization[] keyCharacteristics)303 protected final void addAlgorithmSpecificParametersToBegin( 304 @NonNull List<KeyParameter> parameters, Authorization[] keyCharacteristics) { 305 super.addAlgorithmSpecificParametersToBegin(parameters, keyCharacteristics); 306 parameters.add(KeyStore2ParameterUtils.makeEnum( 307 KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest 308 )); 309 // Only add the KM_TAG_RSA_OAEP_MGF_DIGEST tag to begin() if the MGF Digest is 310 // present in the key properties. Keys generated prior to Android 14 did not have 311 // this tag (Keystore didn't add it) so specifying any MGF digest tag would cause 312 // a begin() operation (on an Android 14 device) to fail (with a key that was generated 313 // on Android 13 or below). 314 if (isMgfDigestTagPresentInKeyProperties(keyCharacteristics)) { 315 parameters.add(KeyStore2ParameterUtils.makeEnum( 316 KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, mKeymasterMgf1Digest 317 )); 318 } 319 } 320 321 @Override loadAlgorithmSpecificParametersFromBeginResult( KeyParameter[] parameters)322 protected final void loadAlgorithmSpecificParametersFromBeginResult( 323 KeyParameter[] parameters) { 324 super.loadAlgorithmSpecificParametersFromBeginResult(parameters); 325 } 326 327 @Override getAdditionalEntropyAmountForBegin()328 protected final int getAdditionalEntropyAmountForBegin() { 329 return 0; 330 } 331 332 @Override getAdditionalEntropyAmountForFinish()333 protected final int getAdditionalEntropyAmountForFinish() { 334 return (isEncrypting()) ? mDigestOutputSizeBytes : 0; 335 } 336 337 @Override getTransform()338 protected final String getTransform() { 339 switch (mKeymasterDigest) { 340 case KeymasterDefs.KM_DIGEST_SHA1: 341 return "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; 342 case KeymasterDefs.KM_DIGEST_SHA_2_224: 343 return "RSA/ECB/OAEPWithSHA-224AndMGF1Padding"; 344 case KeymasterDefs.KM_DIGEST_SHA_2_256: 345 return "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; 346 case KeymasterDefs.KM_DIGEST_SHA_2_384: 347 return "RSA/ECB/OAEPWithSHA-384AndMGF1Padding"; 348 case KeymasterDefs.KM_DIGEST_SHA_2_512: 349 return "RSA/ECB/OAEPWithSHA-512AndMGF1Padding"; 350 default: 351 return "RSA/ECB/OAEPPadding"; 352 } 353 } 354 355 } 356 357 public static class OAEPWithSHA1AndMGF1Padding extends OAEPWithMGF1Padding { OAEPWithSHA1AndMGF1Padding()358 public OAEPWithSHA1AndMGF1Padding() { 359 super(KeymasterDefs.KM_DIGEST_SHA1); 360 } 361 } 362 363 public static class OAEPWithSHA224AndMGF1Padding extends OAEPWithMGF1Padding { OAEPWithSHA224AndMGF1Padding()364 public OAEPWithSHA224AndMGF1Padding() { 365 super(KeymasterDefs.KM_DIGEST_SHA_2_224); 366 } 367 } 368 369 public static class OAEPWithSHA256AndMGF1Padding extends OAEPWithMGF1Padding { OAEPWithSHA256AndMGF1Padding()370 public OAEPWithSHA256AndMGF1Padding() { 371 super(KeymasterDefs.KM_DIGEST_SHA_2_256); 372 } 373 } 374 375 public static class OAEPWithSHA384AndMGF1Padding extends OAEPWithMGF1Padding { OAEPWithSHA384AndMGF1Padding()376 public OAEPWithSHA384AndMGF1Padding() { 377 super(KeymasterDefs.KM_DIGEST_SHA_2_384); 378 } 379 } 380 381 public static class OAEPWithSHA512AndMGF1Padding extends OAEPWithMGF1Padding { OAEPWithSHA512AndMGF1Padding()382 public OAEPWithSHA512AndMGF1Padding() { 383 super(KeymasterDefs.KM_DIGEST_SHA_2_512); 384 } 385 } 386 387 private final int mKeymasterPadding; 388 private int mKeymasterPaddingOverride; 389 390 private int mModulusSizeBytes = -1; 391 AndroidKeyStoreRSACipherSpi(int keymasterPadding)392 AndroidKeyStoreRSACipherSpi(int keymasterPadding) { 393 mKeymasterPadding = keymasterPadding; 394 } 395 396 @Override getTransform()397 protected String getTransform() { 398 return "RSA/ECB/" + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding); 399 } 400 401 @Override initKey(int opmode, Key key)402 protected final void initKey(int opmode, Key key) throws InvalidKeyException { 403 if (key == null) { 404 throw new InvalidKeyException("Unsupported key: null"); 405 } 406 if (!KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(key.getAlgorithm())) { 407 throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm() 408 + ". Only " + KeyProperties.KEY_ALGORITHM_RSA + " supported"); 409 } 410 AndroidKeyStoreKey keystoreKey; 411 if (key instanceof AndroidKeyStorePrivateKey) { 412 keystoreKey = (AndroidKeyStoreKey) key; 413 } else if (key instanceof AndroidKeyStorePublicKey) { 414 keystoreKey = (AndroidKeyStoreKey) key; 415 } else { 416 throw new InvalidKeyException("Unsupported key type: " + key); 417 } 418 419 if (keystoreKey instanceof PrivateKey) { 420 // Private key 421 switch (opmode) { 422 case Cipher.DECRYPT_MODE: 423 case Cipher.UNWRAP_MODE: 424 // Permitted 425 break; 426 case Cipher.ENCRYPT_MODE: 427 case Cipher.WRAP_MODE: 428 if (!adjustConfigForEncryptingWithPrivateKey()) { 429 throw new InvalidKeyException( 430 "RSA private keys cannot be used with " + opmodeToString(opmode) 431 + " and padding " 432 + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding) 433 + ". Only RSA public keys supported for this mode"); 434 } 435 break; 436 default: 437 throw new InvalidKeyException( 438 "RSA private keys cannot be used with opmode: " + opmode); 439 } 440 } else { 441 // Public key 442 switch (opmode) { 443 case Cipher.ENCRYPT_MODE: 444 case Cipher.WRAP_MODE: 445 // Permitted 446 break; 447 case Cipher.DECRYPT_MODE: 448 case Cipher.UNWRAP_MODE: 449 throw new InvalidKeyException( 450 "RSA public keys cannot be used with " + opmodeToString(opmode) 451 + " and padding " 452 + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding) 453 + ". Only RSA private keys supported for this opmode."); 454 // break; 455 default: 456 throw new InvalidKeyException( 457 "RSA public keys cannot be used with " + opmodeToString(opmode)); 458 } 459 } 460 461 long keySizeBits = -1; 462 for (Authorization a : keystoreKey.getAuthorizations()) { 463 if (a.keyParameter.tag == KeymasterDefs.KM_TAG_KEY_SIZE) { 464 keySizeBits = KeyStore2ParameterUtils.getUnsignedInt(a); 465 } 466 } 467 468 if (keySizeBits == -1) { 469 throw new InvalidKeyException("Size of key not known"); 470 } else if (keySizeBits > Integer.MAX_VALUE) { 471 throw new InvalidKeyException("Key too large: " + keySizeBits + " bits"); 472 } 473 mModulusSizeBytes = (int) ((keySizeBits + 7) / 8); 474 475 setKey(keystoreKey); 476 } 477 478 /** 479 * Adjusts the configuration of this cipher for encrypting using the private key. 480 * 481 * <p>The default implementation does nothing and refuses to adjust the configuration. 482 * 483 * @return {@code true} if the configuration has been adjusted, {@code false} if encrypting 484 * using private key is not permitted for this cipher. 485 */ adjustConfigForEncryptingWithPrivateKey()486 protected boolean adjustConfigForEncryptingWithPrivateKey() { 487 return false; 488 } 489 490 @Override resetAll()491 protected final void resetAll() { 492 mModulusSizeBytes = -1; 493 mKeymasterPaddingOverride = -1; 494 super.resetAll(); 495 } 496 497 @Override resetWhilePreservingInitState()498 protected final void resetWhilePreservingInitState() { 499 super.resetWhilePreservingInitState(); 500 } 501 502 @Override addAlgorithmSpecificParametersToBegin( @onNull List<KeyParameter> parameters)503 protected void addAlgorithmSpecificParametersToBegin( 504 @NonNull List<KeyParameter> parameters) { 505 parameters.add(KeyStore2ParameterUtils.makeEnum( 506 KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA 507 )); 508 int keymasterPadding = getKeymasterPaddingOverride(); 509 if (keymasterPadding == -1) { 510 keymasterPadding = mKeymasterPadding; 511 } 512 parameters.add(KeyStore2ParameterUtils.makeEnum( 513 KeymasterDefs.KM_TAG_PADDING, keymasterPadding 514 )); 515 int purposeOverride = getKeymasterPurposeOverride(); 516 if ((purposeOverride != -1) 517 && ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN) 518 || (purposeOverride == KeymasterDefs.KM_PURPOSE_VERIFY))) { 519 // Keymaster sign/verify requires digest to be specified. 520 // For raw sign/verify it's NONE. 521 parameters.add(KeyStore2ParameterUtils.makeEnum( 522 KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE 523 )); 524 } 525 } 526 527 @Override loadAlgorithmSpecificParametersFromBeginResult( KeyParameter[] parameters)528 protected void loadAlgorithmSpecificParametersFromBeginResult( 529 KeyParameter[] parameters) { 530 } 531 532 @Override engineGetBlockSize()533 protected final int engineGetBlockSize() { 534 // Not a block cipher, according to the RI 535 return 0; 536 } 537 538 @Override engineGetIV()539 protected final byte[] engineGetIV() { 540 // IV never used 541 return null; 542 } 543 544 @Override engineGetOutputSize(int inputLen)545 protected final int engineGetOutputSize(int inputLen) { 546 return getModulusSizeBytes(); 547 } 548 getModulusSizeBytes()549 protected final int getModulusSizeBytes() { 550 if (mModulusSizeBytes == -1) { 551 throw new IllegalStateException("Not initialized"); 552 } 553 return mModulusSizeBytes; 554 } 555 556 /** 557 * Overrides the default padding of the crypto operation. 558 */ setKeymasterPaddingOverride(int keymasterPadding)559 protected final void setKeymasterPaddingOverride(int keymasterPadding) { 560 mKeymasterPaddingOverride = keymasterPadding; 561 } 562 getKeymasterPaddingOverride()563 protected final int getKeymasterPaddingOverride() { 564 return mKeymasterPaddingOverride; 565 } 566 } 567