aboutsummaryrefslogtreecommitdiff
path: root/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src
diff options
context:
space:
mode:
Diffstat (limited to 'ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src')
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java53
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java1578
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java198
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java17
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKeyPair.java55
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java138
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMError.java32
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java46
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java53
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKey.java10
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java10
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java75
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java415
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java665
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java140
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java289
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java782
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMType.java79
-rw-r--r--ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java30
19 files changed, 4665 insertions, 0 deletions
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java
new file mode 100644
index 0000000..41059bb
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright(C) 2020 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import javacard.security.AESKey;
+import org.globalplatform.upgrade.Element;
+
+/** This is a wrapper class for AESKey. */
+public class KMAESKey implements KMKey {
+
+ public AESKey aesKey;
+
+ public KMAESKey(AESKey key) {
+ aesKey = key;
+ }
+
+ public static void onSave(Element element, KMAESKey kmKey) {
+ element.write(kmKey.aesKey);
+ }
+
+ public static KMAESKey onRestore(AESKey aesKey) {
+ if (aesKey == null) {
+ return null;
+ }
+ return new KMAESKey(aesKey);
+ }
+
+ public static short getBackupPrimitiveByteCount() {
+ return (short) 0;
+ }
+
+ public static short getBackupObjectCount() {
+ return (short) 1;
+ }
+
+ @Override
+ public short getPublicKey(byte[] buf, short offset) {
+ return (short) 0;
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java
new file mode 100644
index 0000000..cb33272
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java
@@ -0,0 +1,1578 @@
+/*
+ * Copyright(C) 2020 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 com.android.javacard.seprovider;
+
+import javacard.framework.ISO7816;
+import javacard.framework.ISOException;
+import javacard.framework.JCSystem;
+import javacard.framework.Util;
+import javacard.security.AESKey;
+import javacard.security.CryptoException;
+import javacard.security.DESKey;
+import javacard.security.ECPrivateKey;
+import javacard.security.ECPublicKey;
+import javacard.security.HMACKey;
+import javacard.security.Key;
+import javacard.security.KeyAgreement;
+import javacard.security.KeyBuilder;
+import javacard.security.KeyPair;
+import javacard.security.MessageDigest;
+import javacard.security.RSAPrivateKey;
+import javacard.security.RandomData;
+import javacard.security.Signature;
+import javacardx.crypto.AEADCipher;
+import javacardx.crypto.Cipher;
+import org.globalplatform.upgrade.Element;
+import org.globalplatform.upgrade.UpgradeManager;
+
+/**
+ * This class implements KMSEProvider and provides all the necessary crypto operations required to
+ * support the KeyMint specification. This class supports AES, 3DES, HMAC, RSA, ECDSA, ECDH
+ * algorithms additionally it also supports ECDSA_NO_DIGEST, RSA_NO_DIGEST and RSA_OAEP_MGF1_SHA1
+ * and RSA_OAEP_MGF1_SHA256 algorithms. This class follows the pattern of Init-Update-Final for the
+ * crypto operations.
+ */
+public class KMAndroidSEProvider implements KMSEProvider {
+
+ // The tag length for AES GCM algorithm.
+ public static final byte AES_GCM_TAG_LENGTH = 16;
+ // The nonce length for AES GCM algorithm.
+ public static final byte AES_GCM_NONCE_LENGTH = 12;
+ // AES keysize offsets in aesKeys[] for 128 and 256 sizes respectively.
+ public static final byte KEYSIZE_128_OFFSET = 0x00;
+ public static final byte KEYSIZE_256_OFFSET = 0x01;
+ // The size of the temporary buffer.
+ public static final short TMP_ARRAY_SIZE = 300;
+ // The length of the rsa key in bytes.
+ private static final short RSA_KEY_SIZE = 256;
+ // Below are the flag to denote device reset events
+ public static final byte POWER_RESET_FALSE = (byte) 0xAA;
+ public static final byte POWER_RESET_TRUE = (byte) 0x00;
+ // The computed HMAC key size.
+ private static final byte COMPUTED_HMAC_KEY_SIZE = 32;
+ // The constant 'L' as defiend in
+ // https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf, page 12.
+ private static byte[] CMAC_KDF_CONSTANT_L;
+ // Constant to represent 0.
+ private static byte[] CMAC_KDF_CONSTANT_ZERO;
+ // KeyAgreement instance.
+ private static KeyAgreement keyAgreement;
+
+ // AESKey
+ private AESKey aesKeys[];
+ // DES3Key
+ private DESKey triDesKey;
+ // HMACKey
+ private HMACKey hmacKey;
+ // RSA Key Pair
+ private KeyPair rsaKeyPair;
+ // EC Key Pair.
+ private KeyPair ecKeyPair;
+ // Temporary array.
+ public byte[] tmpArray;
+ // This is used for internal encryption/decryption operations.
+ private static AEADCipher aesGcmCipher;
+ // Instance of Signature algorithm used in KDF.
+ private Signature kdf;
+ // Flag used to denote the power reset event.
+ public static byte[] resetFlag;
+ // Instance of HMAC Signature algorithm.
+ private Signature hmacSignature;
+ // For ImportwrappedKey operations.
+ private KMRsaOAEPEncoding rsaOaepDecipher;
+ // Instance of pool manager.
+ private KMPoolManager poolMgr;
+ // Instance of KMOperationImpl used only to encrypt/decrypt the KeyBlobs.
+ private KMOperationImpl globalOperation;
+ // Entropy
+ private RandomData rng;
+ // Singleton instance.
+ private static KMAndroidSEProvider androidSEProvider = null;
+
+ public static KMAndroidSEProvider getInstance() {
+ return androidSEProvider;
+ }
+
+ public KMAndroidSEProvider() {
+ initStatics();
+ // Re-usable AES,DES and HMAC keys in persisted memory.
+ aesKeys = new AESKey[2];
+ aesKeys[KEYSIZE_128_OFFSET] =
+ (AESKey)
+ KeyBuilder.buildKey(
+ KeyBuilder.TYPE_AES_TRANSIENT_RESET, KeyBuilder.LENGTH_AES_128, false);
+ aesKeys[KEYSIZE_256_OFFSET] =
+ (AESKey)
+ KeyBuilder.buildKey(
+ KeyBuilder.TYPE_AES_TRANSIENT_RESET, KeyBuilder.LENGTH_AES_256, false);
+ triDesKey =
+ (DESKey)
+ KeyBuilder.buildKey(
+ KeyBuilder.TYPE_DES_TRANSIENT_RESET, KeyBuilder.LENGTH_DES3_3KEY, false);
+ hmacKey =
+ (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC_TRANSIENT_RESET, (short) 512, false);
+ rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048);
+ ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
+ keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false);
+ poolMgr = KMPoolManager.getInstance();
+ poolMgr.initECKey(ecKeyPair);
+ // RsaOAEP Decipher
+ rsaOaepDecipher = new KMRsaOAEPEncoding(KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1);
+
+ kdf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false);
+ hmacSignature = Signature.getInstance(Signature.ALG_HMAC_SHA_256, false);
+
+ globalOperation = new KMOperationImpl();
+
+ // Temporary transient array created to use locally inside functions.
+ tmpArray = JCSystem.makeTransientByteArray(TMP_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT);
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, TMP_ARRAY_SIZE, (byte) 0);
+ // Random number generator initialisation.
+ rng = RandomData.getInstance(RandomData.ALG_KEYGENERATION);
+ androidSEProvider = this;
+ resetFlag = JCSystem.makeTransientByteArray((short) 1, JCSystem.CLEAR_ON_RESET);
+ resetFlag[0] = (byte) POWER_RESET_FALSE;
+ }
+
+ void initStatics() {
+ CMAC_KDF_CONSTANT_L = new byte[] {0x00, 0x00, 0x01, 0x00};
+ CMAC_KDF_CONSTANT_ZERO = new byte[] {0x00};
+ }
+
+ public void clean() {
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, TMP_ARRAY_SIZE, (byte) 0);
+ }
+
+ public AESKey createAESKey(short keysize) {
+ try {
+ if (keysize > TMP_ARRAY_SIZE) {
+ KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
+ }
+ newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8));
+ return createAESKey(tmpArray, (short) 0, (short) (keysize / 8));
+ } finally {
+ clean();
+ }
+ }
+
+ public AESKey createAESKey(byte[] buf, short startOff, short length) {
+ AESKey key = null;
+ short keysize = (short) (length * 8);
+ if (keysize == 128) {
+ key = (AESKey) aesKeys[KEYSIZE_128_OFFSET];
+ key.setKey(buf, (short) startOff);
+ } else if (keysize == 256) {
+ key = (AESKey) aesKeys[KEYSIZE_256_OFFSET];
+ key.setKey(buf, (short) startOff);
+ } else {
+ KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
+ }
+ return key;
+ }
+
+ public DESKey createTDESKey() {
+ try {
+ newRandomNumber(tmpArray, (short) 0, (short) (KeyBuilder.LENGTH_DES3_3KEY / 8));
+ return createTDESKey(tmpArray, (short) 0, (short) (KeyBuilder.LENGTH_DES3_3KEY / 8));
+ } finally {
+ clean();
+ }
+ }
+
+ public DESKey createTDESKey(byte[] secretBuffer, short secretOff, short secretLength) {
+ triDesKey.setKey(secretBuffer, secretOff);
+ return triDesKey;
+ }
+
+ public HMACKey createHMACKey(short keysize) {
+ // As per the KeyMint2.0 specification
+ // The minimum supported HMAC key size is 64 bits
+ // The maximum supported HMAC key size is 512 bits
+ // The keysize should be a multiple of 8.
+ if ((keysize % 8 != 0) || !(keysize >= 64 && keysize <= 512)) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ try {
+ newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8));
+ return createHMACKey(tmpArray, (short) 0, (short) (keysize / 8));
+ } finally {
+ clean();
+ }
+ }
+
+ public HMACKey createHMACKey(byte[] secretBuffer, short secretOff, short secretLength) {
+ hmacKey.setKey(secretBuffer, secretOff, secretLength);
+ return hmacKey;
+ }
+
+ public KeyPair createRsaKeyPair() {
+ rsaKeyPair.genKeyPair();
+ return rsaKeyPair;
+ }
+
+ public RSAPrivateKey createRsaKey(
+ byte[] modBuffer,
+ short modOff,
+ short modLength,
+ byte[] privBuffer,
+ short privOff,
+ short privLength) {
+ RSAPrivateKey privKey = (RSAPrivateKey) rsaKeyPair.getPrivate();
+ privKey.setExponent(privBuffer, privOff, privLength);
+ privKey.setModulus(modBuffer, modOff, modLength);
+ return privKey;
+ }
+
+ public KeyPair createECKeyPair() {
+ ecKeyPair.genKeyPair();
+ return ecKeyPair;
+ }
+
+ public ECPrivateKey createEcKey(byte[] privBuffer, short privOff, short privLength) {
+ ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate();
+ privKey.setS(privBuffer, privOff, privLength);
+ return privKey;
+ }
+
+ @Override
+ public short createSymmetricKey(byte alg, short keysize, byte[] buf, short startOff) {
+ switch (alg) {
+ case KMType.AES:
+ AESKey aesKey = createAESKey(keysize);
+ return aesKey.getKey(buf, startOff);
+ case KMType.DES:
+ DESKey desKey = createTDESKey();
+ return desKey.getKey(buf, startOff);
+ case KMType.HMAC:
+ HMACKey hmacKey = createHMACKey(keysize);
+ return hmacKey.getKey(buf, startOff);
+ default:
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ break;
+ }
+ return 0;
+ }
+
+ @Override
+ public void createAsymmetricKey(
+ byte alg,
+ byte[] privKeyBuf,
+ short privKeyStart,
+ short privKeyLength,
+ byte[] pubModBuf,
+ short pubModStart,
+ short pubModLength,
+ short[] lengths) {
+ switch (alg) {
+ case KMType.RSA:
+ if (RSA_KEY_SIZE != privKeyLength || RSA_KEY_SIZE != pubModLength) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ KeyPair rsaKey = createRsaKeyPair();
+ RSAPrivateKey privKey = (RSAPrivateKey) rsaKey.getPrivate();
+ // Copy exponent.
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, RSA_KEY_SIZE, (byte) 0);
+ lengths[0] = privKey.getExponent(tmpArray, (short) 0);
+ if (lengths[0] > privKeyLength) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ Util.arrayFillNonAtomic(privKeyBuf, privKeyStart, privKeyLength, (byte) 0);
+ Util.arrayCopyNonAtomic(
+ tmpArray,
+ (short) 0,
+ privKeyBuf,
+ (short) (privKeyStart + privKeyLength - lengths[0]),
+ lengths[0]);
+ // Copy modulus
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, RSA_KEY_SIZE, (byte) 0);
+ lengths[1] = privKey.getModulus(tmpArray, (short) 0);
+ if (lengths[1] > pubModLength) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ Util.arrayFillNonAtomic(pubModBuf, pubModStart, pubModLength, (byte) 0);
+ Util.arrayCopyNonAtomic(
+ tmpArray,
+ (short) 0,
+ pubModBuf,
+ (short) (pubModStart + pubModLength - lengths[1]),
+ lengths[1]);
+ break;
+ case KMType.EC:
+ KeyPair ecKey = createECKeyPair();
+ ECPublicKey ecPubKey = (ECPublicKey) ecKey.getPublic();
+ ECPrivateKey ecPrivKey = (ECPrivateKey) ecKey.getPrivate();
+ lengths[0] = ecPrivKey.getS(privKeyBuf, privKeyStart);
+ lengths[1] = ecPubKey.getW(pubModBuf, pubModStart);
+ if (lengths[0] > privKeyLength || lengths[1] > pubModLength) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ break;
+ default:
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ break;
+ }
+ }
+
+ @Override
+ public boolean importSymmetricKey(
+ byte alg, short keysize, byte[] buf, short startOff, short length) {
+ switch (alg) {
+ case KMType.AES:
+ createAESKey(buf, startOff, length);
+ break;
+ case KMType.DES:
+ createTDESKey(buf, startOff, length);
+ break;
+ case KMType.HMAC:
+ createHMACKey(buf, startOff, length);
+ break;
+ default:
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean importAsymmetricKey(
+ byte alg,
+ byte[] privKeyBuf,
+ short privKeyStart,
+ short privKeyLength,
+ byte[] pubModBuf,
+ short pubModStart,
+ short pubModLength) {
+ switch (alg) {
+ case KMType.RSA:
+ createRsaKey(pubModBuf, pubModStart, pubModLength, privKeyBuf, privKeyStart, privKeyLength);
+ break;
+ case KMType.EC:
+ createEcKey(privKeyBuf, privKeyStart, privKeyLength);
+ break;
+ default:
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public void getTrueRandomNumber(byte[] buf, short start, short length) {
+ newRandomNumber(buf, start, length);
+ }
+
+ @Override
+ public void newRandomNumber(byte[] num, short startOff, short length) {
+ rng.nextBytes(num, startOff, length);
+ }
+
+ @Override
+ public void addRngEntropy(byte[] num, short offset, short length) {
+ rng.setSeed(num, offset, length);
+ }
+
+ public short aesGCMEncrypt(
+ AESKey key,
+ byte[] secret,
+ short secretStart,
+ short secretLen,
+ byte[] encSecret,
+ short encSecretStart,
+ byte[] nonce,
+ short nonceStart,
+ short nonceLen,
+ byte[] authData,
+ short authDataStart,
+ short authDataLen,
+ byte[] authTag,
+ short authTagStart,
+ short authTagLen) {
+ if (authTagLen != AES_GCM_TAG_LENGTH) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ if (nonceLen != AES_GCM_NONCE_LENGTH) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ if (aesGcmCipher == null) {
+ aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, false);
+ }
+ aesGcmCipher.init(key, Cipher.MODE_ENCRYPT, nonce, nonceStart, nonceLen);
+ if (authDataLen != 0) {
+ aesGcmCipher.updateAAD(authData, authDataStart, authDataLen);
+ }
+ short ciphLen = aesGcmCipher.doFinal(secret, secretStart, secretLen, encSecret, encSecretStart);
+ aesGcmCipher.retrieveTag(authTag, authTagStart, authTagLen);
+ return ciphLen;
+ }
+
+ @Override
+ public short aesGCMEncrypt(
+ byte[] aesKey,
+ short aesKeyStart,
+ short aesKeyLen,
+ byte[] secret,
+ short secretStart,
+ short secretLen,
+ byte[] encSecret,
+ short encSecretStart,
+ byte[] nonce,
+ short nonceStart,
+ short nonceLen,
+ byte[] authData,
+ short authDataStart,
+ short authDataLen,
+ byte[] authTag,
+ short authTagStart,
+ short authTagLen) {
+
+ AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen);
+ return aesGCMEncrypt(
+ key,
+ secret,
+ secretStart,
+ secretLen,
+ encSecret,
+ encSecretStart,
+ nonce,
+ nonceStart,
+ nonceLen,
+ authData,
+ authDataStart,
+ authDataLen,
+ authTag,
+ authTagStart,
+ authTagLen);
+ }
+
+ @Override
+ public boolean aesGCMDecrypt(
+ byte[] aesKey,
+ short aesKeyStart,
+ short aesKeyLen,
+ byte[] encSecret,
+ short encSecretStart,
+ short encSecretLen,
+ byte[] secret,
+ short secretStart,
+ byte[] nonce,
+ short nonceStart,
+ short nonceLen,
+ byte[] authData,
+ short authDataStart,
+ short authDataLen,
+ byte[] authTag,
+ short authTagStart,
+ short authTagLen) {
+ if (aesGcmCipher == null) {
+ aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, false);
+ }
+ boolean verification = false;
+ AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen);
+ aesGcmCipher.init(key, Cipher.MODE_DECRYPT, nonce, nonceStart, nonceLen);
+ if (authDataLen != 0) {
+ aesGcmCipher.updateAAD(authData, authDataStart, authDataLen);
+ }
+ // encrypt the secret
+ aesGcmCipher.doFinal(encSecret, encSecretStart, encSecretLen, secret, secretStart);
+ verification =
+ aesGcmCipher.verifyTag(
+ authTag, authTagStart, (short) authTagLen, (short) AES_GCM_TAG_LENGTH);
+ return verification;
+ }
+
+ public HMACKey cmacKdf(
+ KMKey preSharedKey,
+ byte[] label,
+ short labelStart,
+ short labelLen,
+ byte[] context,
+ short contextStart,
+ short contextLength) {
+ // Note: the variables i and L correspond to i and L in the standard. See page 12 of
+ // http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf.
+ try {
+ // This is hardcoded to requirement - 32 byte output with two concatenated
+ // 16 bytes K1 and K2.
+ final byte n = 2; // hardcoded
+
+ // [i] counter - 32 bits
+ short iBufLen = 4;
+ short keyOutLen = n * 16;
+ // Convert Hmackey to AES Key as the algorithm is ALG_AES_CMAC_128.
+ KMHmacKey hmacKey = ((KMHmacKey) preSharedKey);
+ hmacKey.hmacKey.getKey(tmpArray, (short) 0);
+ aesKeys[KEYSIZE_256_OFFSET].setKey(tmpArray, (short) 0);
+ // Initialize the key derivation function.
+ kdf.init(aesKeys[KEYSIZE_256_OFFSET], Signature.MODE_SIGN);
+ // Clear the tmpArray buffer.
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0);
+
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, iBufLen, (byte) 0);
+ Util.arrayFillNonAtomic(tmpArray, (short) iBufLen, keyOutLen, (byte) 0);
+
+ byte i = 1;
+ short pos = 0;
+ while (i <= n) {
+ tmpArray[3] = i;
+ // 4 bytes of iBuf with counter in it
+ kdf.update(tmpArray, (short) 0, (short) iBufLen);
+ kdf.update(label, labelStart, (short) labelLen); // label
+ kdf.update(
+ CMAC_KDF_CONSTANT_ZERO,
+ (short) 0,
+ (short) CMAC_KDF_CONSTANT_ZERO.length); // 1 byte of 0x00
+ kdf.update(context, contextStart, contextLength); // context
+ // 4 bytes of L - signature of 16 bytes
+ pos =
+ kdf.sign(
+ CMAC_KDF_CONSTANT_L,
+ (short) 0,
+ (short) CMAC_KDF_CONSTANT_L.length,
+ tmpArray,
+ (short) (iBufLen + pos));
+ i++;
+ }
+ return createHMACKey(tmpArray, (short) iBufLen, (short) keyOutLen);
+ } finally {
+ clean();
+ }
+ }
+
+ public short hmacSign(
+ HMACKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) {
+ hmacSignature.init(key, Signature.MODE_SIGN);
+ return hmacSignature.sign(data, dataStart, dataLength, mac, macStart);
+ }
+
+ @Override
+ public short hmacSign(
+ byte[] keyBuf,
+ short keyStart,
+ short keyLength,
+ byte[] data,
+ short dataStart,
+ short dataLength,
+ byte[] mac,
+ short macStart) {
+ HMACKey key = createHMACKey(keyBuf, keyStart, keyLength);
+ return hmacSign(key, data, dataStart, dataLength, mac, macStart);
+ }
+
+ @Override
+ public short hmacSign(
+ Object key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) {
+ if (!(key instanceof KMHmacKey)) {
+ KMException.throwIt(KMError.INVALID_ARGUMENT);
+ }
+ KMHmacKey hmacKey = (KMHmacKey) key;
+ return hmacSign(hmacKey.hmacKey, data, dataStart, dataLength, mac, macStart);
+ }
+
+ @Override
+ public short hmacKDF(
+ KMKey masterkey,
+ byte[] data,
+ short dataStart,
+ short dataLength,
+ byte[] signature,
+ short signatureStart) {
+ try {
+ KMAESKey aesKey = (KMAESKey) masterkey;
+ short keyLen = (short) (aesKey.aesKey.getSize() / 8);
+ aesKey.aesKey.getKey(tmpArray, (short) 0);
+ return hmacSign(
+ tmpArray, (short) 0, keyLen, data, dataStart, dataLength, signature, signatureStart);
+ } finally {
+ clean();
+ }
+ }
+
+ @Override
+ public boolean hmacVerify(
+ KMKey key,
+ byte[] data,
+ short dataStart,
+ short dataLength,
+ byte[] mac,
+ short macStart,
+ short macLength) {
+ KMHmacKey hmacKey = (KMHmacKey) key;
+ hmacSignature.init(hmacKey.hmacKey, Signature.MODE_VERIFY);
+ return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength);
+ }
+
+ @Override
+ public short rsaDecipherOAEP256(
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ byte[] modBuffer,
+ short modOff,
+ short modLength,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart) {
+ RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate();
+ key.setExponent(secret, (short) secretStart, (short) secretLength);
+ key.setModulus(modBuffer, (short) modOff, (short) modLength);
+ rsaOaepDecipher.init(key, Cipher.MODE_DECRYPT);
+ return rsaOaepDecipher.doFinal(
+ inputDataBuf,
+ (short) inputDataStart,
+ (short) inputDataLength,
+ outputDataBuf,
+ (short) outputDataStart);
+ }
+
+ private byte mapSignature256Alg(byte alg, byte padding, byte digest) {
+ switch (alg) {
+ case KMType.RSA:
+ switch (padding) {
+ case KMType.RSA_PKCS1_1_5_SIGN:
+ {
+ if (digest == KMType.DIGEST_NONE) {
+ return KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST;
+ } else {
+ return Signature.ALG_RSA_SHA_256_PKCS1;
+ }
+ }
+ case KMType.RSA_PSS:
+ return Signature.ALG_RSA_SHA_256_PKCS1_PSS;
+ case KMType.PADDING_NONE:
+ return KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD;
+ }
+ break;
+ case KMType.EC:
+ if (digest == KMType.DIGEST_NONE) {
+ return KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST;
+ } else {
+ return Signature.ALG_ECDSA_SHA_256;
+ }
+ case KMType.HMAC:
+ return Signature.ALG_HMAC_SHA_256;
+ }
+ return -1;
+ }
+
+ private byte mapCipherAlg(byte alg, byte padding, byte blockmode, byte digest) {
+ switch (alg) {
+ case KMType.AES:
+ switch (blockmode) {
+ case KMType.ECB:
+ return Cipher.ALG_AES_BLOCK_128_ECB_NOPAD;
+ case KMType.CBC:
+ return Cipher.ALG_AES_BLOCK_128_CBC_NOPAD;
+ case KMType.CTR:
+ return Cipher.ALG_AES_CTR;
+ case KMType.GCM:
+ return AEADCipher.ALG_AES_GCM;
+ }
+ break;
+ case KMType.DES:
+ switch (blockmode) {
+ case KMType.ECB:
+ return Cipher.ALG_DES_ECB_NOPAD;
+ case KMType.CBC:
+ return Cipher.ALG_DES_CBC_NOPAD;
+ }
+ break;
+ case KMType.RSA:
+ switch (padding) {
+ case KMType.PADDING_NONE:
+ return Cipher.ALG_RSA_NOPAD;
+ case KMType.RSA_PKCS1_1_5_ENCRYPT:
+ return Cipher.ALG_RSA_PKCS1;
+ case KMType.RSA_OAEP:
+ {
+ if (digest == KMType.SHA1) {
+ /* MGF Digest is SHA1 */
+ return KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1;
+ } else if (digest == KMType.SHA2_256) {
+ /* MGF Digest is SHA256 */
+ return KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256;
+ } else {
+ KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
+ }
+ }
+ }
+ break;
+ }
+ return -1;
+ }
+
+ public KMOperation createSymmetricCipher(
+ short alg,
+ short purpose,
+ short macLength,
+ short blockMode,
+ short padding,
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ byte[] ivBuffer,
+ short ivStart,
+ short ivLength,
+ boolean isRkp) {
+
+ short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode, (byte) 0);
+ KMOperation operation = null;
+ if (isRkp) {
+ operation = poolMgr.getRKpOperation(purpose, cipherAlg, alg, padding, blockMode, macLength);
+ } else {
+ operation =
+ poolMgr.getOperationImpl(
+ purpose, cipherAlg, alg, padding, blockMode, macLength, secretLength, false);
+ }
+ // Get the KeyObject from the operation and update the key with the secret key material.
+ KMKeyObject keyObj = operation.getKeyObject();
+ Key key = (Key) keyObj.keyObjectInst;
+ switch (secretLength) {
+ case 32:
+ case 16:
+ ((AESKey) key).setKey(secret, secretStart);
+ break;
+ case 24:
+ ((DESKey) key).setKey(secret, secretStart);
+ break;
+ default:
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ break;
+ }
+ ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, ivBuffer, ivStart, ivLength);
+ return operation;
+ }
+
+ public KMOperation createHmacSignerVerifier(
+ short purpose,
+ short digest,
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ boolean isRkp) {
+ KMOperation operation = null;
+ if (digest != KMType.SHA2_256) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ if (isRkp) {
+ operation =
+ poolMgr.getRKpOperation(
+ purpose,
+ Signature.ALG_HMAC_SHA_256,
+ KMType.HMAC,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE);
+ } else {
+ operation =
+ poolMgr.getOperationImpl(
+ purpose,
+ Signature.ALG_HMAC_SHA_256,
+ KMType.HMAC,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ (short) 0,
+ false);
+ }
+ // Get the KeyObject from the operation and update the key with the secret key material.
+ KMKeyObject keyObj = operation.getKeyObject();
+ HMACKey key = (HMACKey) keyObj.keyObjectInst;
+ key.setKey(secret, secretStart, secretLength);
+ ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0);
+ return operation;
+ }
+
+ private KMOperation createHmacSignerVerifier(
+ short purpose, short digest, HMACKey hmacKey, boolean isTrustedConf) {
+ if (digest != KMType.SHA2_256) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ KMOperation operation =
+ poolMgr.getOperationImpl(
+ purpose,
+ Signature.ALG_HMAC_SHA_256,
+ KMType.HMAC,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ (short) 0,
+ isTrustedConf);
+ // Get the KeyObject from the operation and update the key with the secret key material.
+ KMKeyObject keyObj = operation.getKeyObject();
+ HMACKey key = (HMACKey) keyObj.keyObjectInst;
+ short len = hmacKey.getKey(tmpArray, (short) 0);
+ key.setKey(tmpArray, (short) 0, len);
+ ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0);
+ return operation;
+ }
+
+ @Override
+ public KMOperation getRkpOperation(
+ byte purpose,
+ byte alg,
+ byte digest,
+ byte padding,
+ byte blockMode,
+ byte[] keyBuf,
+ short keyStart,
+ short keyLength,
+ byte[] ivBuf,
+ short ivStart,
+ short ivLength,
+ short macLength) {
+ KMOperation opr = null;
+ switch (alg) {
+ case KMType.AES:
+ // Convert macLength to bytes
+ macLength = (short) (macLength / 8);
+ opr =
+ createSymmetricCipher(
+ alg,
+ purpose,
+ macLength,
+ blockMode,
+ padding,
+ keyBuf,
+ keyStart,
+ keyLength,
+ ivBuf,
+ ivStart,
+ ivLength,
+ true /* isRKP */);
+ break;
+ case KMType.HMAC:
+ opr =
+ createHmacSignerVerifier(
+ purpose, digest, keyBuf, keyStart, keyLength, true /* isRKP */);
+ break;
+ default:
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ break;
+ }
+ return opr;
+ }
+
+ @Override
+ public KMOperation initSymmetricOperation(
+ byte purpose,
+ byte alg,
+ byte digest,
+ byte padding,
+ byte blockMode,
+ byte[] keyBuf,
+ short keyStart,
+ short keyLength,
+ byte[] ivBuf,
+ short ivStart,
+ short ivLength,
+ short macLength) {
+ KMOperation opr = null;
+ switch (alg) {
+ case KMType.AES:
+ case KMType.DES:
+ // Convert macLength to bytes
+ macLength = (short) (macLength / 8);
+ opr =
+ createSymmetricCipher(
+ alg,
+ purpose,
+ macLength,
+ blockMode,
+ padding,
+ keyBuf,
+ keyStart,
+ keyLength,
+ ivBuf,
+ ivStart,
+ ivLength,
+ false /* isRKP */);
+ break;
+ case KMType.HMAC:
+ opr =
+ createHmacSignerVerifier(
+ purpose, digest, keyBuf, keyStart, keyLength, false /* isRKP */);
+ break;
+ default:
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ break;
+ }
+ return opr;
+ }
+
+ @Override
+ public KMOperation initSymmetricOperation(
+ byte purpose,
+ byte alg,
+ byte digest,
+ byte padding,
+ byte blockMode,
+ Object key,
+ byte interfaceType,
+ byte[] ivBuf,
+ short ivStart,
+ short ivLength,
+ short macLength,
+ boolean oneShot) {
+ short keyLen = 0;
+ globalOperation.setPurpose(purpose);
+ globalOperation.setAlgorithmType(alg);
+ globalOperation.setPaddingAlgorithm(padding);
+ globalOperation.setBlockMode(blockMode);
+ try {
+ switch (interfaceType) {
+ case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY:
+ KMAESKey aesKey = (KMAESKey) key;
+ keyLen = (short) (aesKey.aesKey.getSize() / 8);
+ aesKey.aesKey.getKey(tmpArray, (short) 0);
+ break;
+
+ default:
+ KMException.throwIt(KMError.INVALID_ARGUMENT);
+ }
+
+ switch (alg) {
+ case KMType.HMAC:
+ HMACKey hmackey = createHMACKey(tmpArray, (short) 0, keyLen);
+ globalOperation.setSignature(hmacSignature);
+ globalOperation.init(hmackey, digest, null, (short) 0, (short) 0);
+ break;
+
+ default:
+ KMException.throwIt(KMError.INVALID_ARGUMENT);
+ }
+ } finally {
+ clean();
+ }
+ return globalOperation;
+ }
+
+ @Override
+ public KMOperation initTrustedConfirmationSymmetricOperation(KMKey computedHmacKey) {
+ KMHmacKey key = (KMHmacKey) computedHmacKey;
+ return createHmacSignerVerifier(KMType.VERIFY, KMType.SHA2_256, key.hmacKey, true);
+ }
+
+ public KMOperation createRsaSigner(
+ short digest,
+ short padding,
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ byte[] modBuffer,
+ short modOff,
+ short modLength) {
+ byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest);
+ KMOperation operation =
+ poolMgr.getOperationImpl(
+ KMType.SIGN,
+ alg,
+ KMType.RSA,
+ padding,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ secretLength,
+ false);
+ // Get the KeyObject from the operation and update the key with the secret key material.
+ KMKeyObject keyObj = operation.getKeyObject();
+ RSAPrivateKey key = (RSAPrivateKey) ((KeyPair) (keyObj.keyObjectInst)).getPrivate();
+ key.setExponent(secret, secretStart, secretLength);
+ key.setModulus(modBuffer, modOff, modLength);
+ ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0);
+ return operation;
+ }
+
+ public KMOperation createRsaDecipher(
+ short padding,
+ short mgfDigest,
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ byte[] modBuffer,
+ short modOff,
+ short modLength) {
+ byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte) mgfDigest);
+ KMOperation operation =
+ poolMgr.getOperationImpl(
+ KMType.DECRYPT,
+ cipherAlg,
+ KMType.RSA,
+ padding,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ secretLength,
+ false);
+ // Get the KeyObject from the operation and update the key with the secret key material.
+ KMKeyObject keyObj = operation.getKeyObject();
+ RSAPrivateKey key = (RSAPrivateKey) ((KeyPair) (keyObj.keyObjectInst)).getPrivate();
+ key.setExponent(secret, secretStart, secretLength);
+ key.setModulus(modBuffer, modOff, modLength);
+ ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0);
+ return operation;
+ }
+
+ public KMOperation createEcSigner(
+ short digest, byte[] secret, short secretStart, short secretLength) {
+ byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest);
+ KMOperation operation =
+ poolMgr.getOperationImpl(
+ KMType.SIGN,
+ alg,
+ KMType.EC,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ secretLength,
+ false);
+ KMKeyObject keyObj = operation.getKeyObject();
+ ECPrivateKey key = (ECPrivateKey) ((KeyPair) (keyObj.keyObjectInst)).getPrivate();
+ key.setS(secret, secretStart, secretLength);
+ ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0);
+ return operation;
+ }
+
+ public KMOperation createKeyAgreement(byte[] secret, short secretStart, short secretLength) {
+ KMOperation operation =
+ poolMgr.getOperationImpl(
+ KMType.AGREE_KEY,
+ KeyAgreement.ALG_EC_SVDP_DH_PLAIN,
+ KMType.EC,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ KMType.INVALID_VALUE,
+ (short) 0,
+ false);
+ KMKeyObject keyObj = operation.getKeyObject();
+ ECPrivateKey key = (ECPrivateKey) ((KeyPair) (keyObj.keyObjectInst)).getPrivate();
+ key.setS(secret, secretStart, secretLength);
+ ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0);
+ return operation;
+ }
+
+ @Override
+ public KMOperation initAsymmetricOperation(
+ byte purpose,
+ byte alg,
+ byte padding,
+ byte digest,
+ byte mgfDigest,
+ byte[] privKeyBuf,
+ short privKeyStart,
+ short privKeyLength,
+ byte[] pubModBuf,
+ short pubModStart,
+ short pubModLength) {
+ KMOperation opr = null;
+ if (alg == KMType.RSA) {
+ switch (purpose) {
+ case KMType.SIGN:
+ opr =
+ createRsaSigner(
+ digest,
+ padding,
+ privKeyBuf,
+ privKeyStart,
+ privKeyLength,
+ pubModBuf,
+ pubModStart,
+ pubModLength);
+ break;
+ case KMType.DECRYPT:
+ opr =
+ createRsaDecipher(
+ padding,
+ mgfDigest,
+ privKeyBuf,
+ privKeyStart,
+ privKeyLength,
+ pubModBuf,
+ pubModStart,
+ pubModLength);
+ break;
+ default:
+ KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
+ break;
+ }
+ } else if (alg == KMType.EC) {
+ switch (purpose) {
+ case KMType.SIGN:
+ opr = createEcSigner(digest, privKeyBuf, privKeyStart, privKeyLength);
+ break;
+
+ case KMType.AGREE_KEY:
+ opr = createKeyAgreement(privKeyBuf, privKeyStart, privKeyLength);
+ break;
+ default:
+ KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
+ break;
+ }
+ } else {
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ }
+ return opr;
+ }
+
+ @Override
+ public short cmacKDF(
+ KMKey pSharedKey,
+ byte[] label,
+ short labelStart,
+ short labelLen,
+ byte[] context,
+ short contextStart,
+ short contextLength,
+ byte[] keyBuf,
+ short keyStart) {
+ HMACKey key =
+ cmacKdf(pSharedKey, label, labelStart, labelLen, context, contextStart, contextLength);
+ return key.getKey(keyBuf, keyStart);
+ }
+
+ @Override
+ public boolean isUpgrading() {
+ return UpgradeManager.isUpgrading();
+ }
+
+ @Override
+ public KMKey createMasterKey(KMKey masterKey, short keySizeBits) {
+ try {
+ if (masterKey == null) {
+ AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, keySizeBits, false);
+ masterKey = new KMAESKey(key);
+ }
+ short keyLen = (short) (keySizeBits / 8);
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, keyLen, (byte) 0);
+ getTrueRandomNumber(tmpArray, (short) 0, keyLen);
+ ((KMAESKey) masterKey).aesKey.setKey(tmpArray, (short) 0);
+ return (KMKey) masterKey;
+ } finally {
+ clean();
+ }
+ }
+
+ @Override
+ public KMKey createPreSharedKey(KMKey preSharedKey, byte[] keyData, short offset, short length) {
+ short lengthInBits = (short) (length * 8);
+ if ((lengthInBits % 8 != 0) || !(lengthInBits >= 64 && lengthInBits <= 512)) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ if (preSharedKey == null) {
+ HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, lengthInBits, false);
+ preSharedKey = new KMHmacKey(key);
+ }
+ ((KMHmacKey) preSharedKey).hmacKey.setKey(keyData, offset, length);
+ return (KMKey) preSharedKey;
+ }
+
+ @Override
+ public KMKey createComputedHmacKey(
+ KMKey computedHmacKey, byte[] keyData, short offset, short length) {
+ if (length != COMPUTED_HMAC_KEY_SIZE) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ if (computedHmacKey == null) {
+ HMACKey key =
+ (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) (length * 8), false);
+ computedHmacKey = new KMHmacKey(key);
+ }
+ ((KMHmacKey) computedHmacKey).hmacKey.setKey(keyData, offset, length);
+ return (KMKey) computedHmacKey;
+ }
+
+ @Override
+ public short ecSign256(
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart) {
+
+ ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate();
+ key.setS(secret, secretStart, secretLength);
+
+ Signature.OneShot signer = null;
+ try {
+
+ signer =
+ Signature.OneShot.open(
+ MessageDigest.ALG_SHA_256, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL);
+ signer.init(key, Signature.MODE_SIGN);
+ return signer.sign(
+ inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart);
+ } finally {
+ if (signer != null) {
+ signer.close();
+ }
+ }
+ }
+
+ @Override
+ public short rsaSign256Pkcs1(
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ byte[] modBuf,
+ short modStart,
+ short modLength,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart) {
+
+ Signature.OneShot signer = null;
+ try {
+
+ signer =
+ Signature.OneShot.open(
+ MessageDigest.ALG_SHA_256, Signature.SIG_CIPHER_RSA, Cipher.PAD_PKCS1);
+
+ RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate();
+ ;
+ key.setExponent(secret, secretStart, secretLength);
+ key.setModulus(modBuf, modStart, modLength);
+
+ signer.init(key, Signature.MODE_SIGN);
+ return signer.sign(
+ inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart);
+ } finally {
+ if (signer != null) {
+ signer.close();
+ }
+ }
+ }
+
+ @Override
+ public boolean isAttestationKeyProvisioned() {
+ return false;
+ }
+
+ @Override
+ public short getAttestationKeyAlgorithm() {
+ return KMType.INVALID_VALUE;
+ }
+
+ @Override
+ public short hkdf(
+ byte[] ikm,
+ short ikmOff,
+ short ikmLen,
+ byte[] salt,
+ short saltOff,
+ short saltLen,
+ byte[] info,
+ short infoOff,
+ short infoLen,
+ byte[] out,
+ short outOff,
+ short outLen) {
+ // HMAC_extract
+ hkdfExtract(ikm, ikmOff, ikmLen, salt, saltOff, saltLen, tmpArray, (short) 0);
+ // HMAC_expand
+ return hkdfExpand(tmpArray, (short) 0, (short) 32, info, infoOff, infoLen, out, outOff, outLen);
+ }
+
+ private short hkdfExtract(
+ byte[] ikm,
+ short ikmOff,
+ short ikmLen,
+ byte[] salt,
+ short saltOff,
+ short saltLen,
+ byte[] out,
+ short off) {
+ // https://tools.ietf.org/html/rfc5869#section-2.2
+ HMACKey hmacKey = createHMACKey(salt, saltOff, saltLen);
+ hmacSignature.init(hmacKey, Signature.MODE_SIGN);
+ return hmacSignature.sign(ikm, ikmOff, ikmLen, out, off);
+ }
+
+ private short hkdfExpand(
+ byte[] prk,
+ short prkOff,
+ short prkLen,
+ byte[] info,
+ short infoOff,
+ short infoLen,
+ byte[] out,
+ short outOff,
+ short outLen) {
+ // https://tools.ietf.org/html/rfc5869#section-2.3
+ short digestLen = (short) 32; // SHA256 digest length.
+ // Calculate no of iterations N.
+ short n = (short) ((short) (outLen + digestLen - 1) / digestLen);
+ if (n > 255) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ HMACKey hmacKey = createHMACKey(prk, prkOff, prkLen);
+ Util.arrayFill(tmpArray, (short) 0, (short) 33, (byte) 0);
+ short bytesCopied = 0;
+ short len = 0;
+ for (short i = 0; i < n; i++) {
+ tmpArray[0]++;
+ hmacSignature.init(hmacKey, Signature.MODE_SIGN);
+ if (i != 0) {
+ hmacSignature.update(tmpArray, (short) 1, (short) 32);
+ }
+ hmacSignature.update(info, infoOff, infoLen);
+ len = hmacSignature.sign(tmpArray, (short) 0, (short) 1, tmpArray, (short) 1);
+ if ((short) (bytesCopied + len) > outLen) {
+ len = (short) (outLen - bytesCopied);
+ }
+ Util.arrayCopyNonAtomic(tmpArray, (short) 1, out, (short) (outOff + bytesCopied), len);
+ bytesCopied += len;
+ }
+ return outLen;
+ }
+
+ @Override
+ public short ecdhKeyAgreement(
+ byte[] privKey,
+ short privKeyOff,
+ short privKeyLen,
+ byte[] publicKey,
+ short publicKeyOff,
+ short publicKeyLen,
+ byte[] secret,
+ short secretOff) {
+ keyAgreement.init(createEcKey(privKey, privKeyOff, privKeyLen));
+ return keyAgreement.generateSecret(publicKey, publicKeyOff, publicKeyLen, secret, secretOff);
+ }
+
+ @Override
+ public boolean ecVerify256(
+ byte[] pubKey,
+ short pubKeyOffset,
+ short pubKeyLen,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] signatureDataBuf,
+ short signatureDataStart,
+ short signatureDataLen) {
+ Signature.OneShot signer = null;
+ try {
+ signer =
+ Signature.OneShot.open(
+ MessageDigest.ALG_SHA_256, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL);
+ ECPublicKey key = (ECPublicKey) ecKeyPair.getPublic();
+ key.setW(pubKey, pubKeyOffset, pubKeyLen);
+ signer.init(key, Signature.MODE_VERIFY);
+ return signer.verify(
+ inputDataBuf,
+ inputDataStart,
+ inputDataLength,
+ signatureDataBuf,
+ signatureDataStart,
+ (short) (signatureDataBuf[(short) (signatureDataStart + 1)] + 2));
+ } finally {
+ if (signer != null) {
+ signer.close();
+ }
+ }
+ }
+
+ @Override
+ public short signWithDeviceUniqueKey(
+ KMKey ecPrivKey,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart) {
+ Signature.OneShot signer = null;
+ try {
+ signer =
+ Signature.OneShot.open(
+ MessageDigest.ALG_SHA_256, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL);
+ signer.init(
+ ((KMECDeviceUniqueKeyPair) ecPrivKey).ecKeyPair.getPrivate(), Signature.MODE_SIGN);
+ return signer.sign(
+ inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart);
+ } finally {
+ if (signer != null) {
+ signer.close();
+ }
+ }
+ }
+
+ @Override
+ public KMKey createRkpDeviceUniqueKeyPair(
+ KMKey key,
+ byte[] pubKey,
+ short pubKeyOff,
+ short pubKeyLen,
+ byte[] privKey,
+ short privKeyOff,
+ short privKeyLen) {
+ if (key == null) {
+ KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
+ poolMgr.initECKey(ecKeyPair);
+ key = new KMECDeviceUniqueKeyPair(ecKeyPair);
+ }
+ ECPrivateKey ecKeyPair = (ECPrivateKey) ((KMECDeviceUniqueKeyPair) key).ecKeyPair.getPrivate();
+ ECPublicKey ecPublicKey = (ECPublicKey) ((KMECDeviceUniqueKeyPair) key).ecKeyPair.getPublic();
+ ecKeyPair.setS(privKey, privKeyOff, privKeyLen);
+ ecPublicKey.setW(pubKey, pubKeyOff, pubKeyLen);
+ return (KMKey) key;
+ }
+
+ @Override
+ public KMKey createRkpMacKey(KMKey rkpMacKey, byte[] keyData, short offset, short length) {
+ if (rkpMacKey == null) {
+ HMACKey key =
+ (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) (length * 8), false);
+ rkpMacKey = new KMHmacKey(key);
+ }
+ ((KMHmacKey) rkpMacKey).hmacKey.setKey(keyData, offset, length);
+ return rkpMacKey;
+ }
+
+ @Override
+ public short messageDigest256(
+ byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset) {
+ MessageDigest.OneShot mDigest = null;
+ short len = 0;
+ try {
+ mDigest = MessageDigest.OneShot.open(MessageDigest.ALG_SHA_256);
+ len = mDigest.doFinal(inBuff, inOffset, inLength, outBuff, outOffset);
+ } finally {
+ if (mDigest != null) {
+ mDigest.close();
+ mDigest = null;
+ }
+ }
+ return len;
+ }
+
+ public boolean isPowerReset() {
+ boolean flag = false;
+ if (resetFlag[0] == POWER_RESET_TRUE) {
+ resetFlag[0] = POWER_RESET_FALSE;
+ flag = true;
+ if (poolMgr != null) {
+ poolMgr.powerReset();
+ }
+ }
+ return flag;
+ }
+
+ @Override
+ public void onSave(Element element, byte interfaceType, Object object) {
+ element.write(interfaceType);
+ if (object == null) {
+ element.write(null);
+ return;
+ }
+ switch (interfaceType) {
+ case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY:
+ KMAESKey.onSave(element, (KMAESKey) object);
+ break;
+ case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY:
+ KMHmacKey.onSave(element, (KMHmacKey) object);
+ break;
+ case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR:
+ KMECDeviceUniqueKeyPair.onSave(element, (KMECDeviceUniqueKeyPair) object);
+ break;
+ case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY:
+ KMHmacKey.onSave(element, (KMHmacKey) object);
+ break;
+ default:
+ ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
+ }
+ }
+
+ @Override
+ public Object onRestore(Element element) {
+ if (element == null) {
+ return null;
+ }
+ byte interfaceType = element.readByte();
+ switch (interfaceType) {
+ case KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY:
+ return KMHmacKey.onRestore((HMACKey) element.readObject());
+ case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY:
+ return KMAESKey.onRestore((AESKey) element.readObject());
+ case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY:
+ return KMHmacKey.onRestore((HMACKey) element.readObject());
+ case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR:
+ return KMECDeviceUniqueKeyPair.onRestore((KeyPair) element.readObject());
+ case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY:
+ return KMHmacKey.onRestore((HMACKey) element.readObject());
+ default:
+ ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
+ }
+ return null;
+ }
+
+ @Override
+ public short getBackupPrimitiveByteCount(byte interfaceType) {
+ short primitiveCount = 1; // interface type
+ switch (interfaceType) {
+ case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY:
+ primitiveCount += KMAESKey.getBackupPrimitiveByteCount();
+ break;
+ case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY:
+ primitiveCount += KMHmacKey.getBackupPrimitiveByteCount();
+ break;
+ case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR:
+ primitiveCount += KMECDeviceUniqueKeyPair.getBackupPrimitiveByteCount();
+ break;
+ case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY:
+ primitiveCount += KMHmacKey.getBackupPrimitiveByteCount();
+ break;
+ default:
+ ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
+ }
+ return primitiveCount;
+ }
+
+ @Override
+ public short getBackupObjectCount(byte interfaceType) {
+ switch (interfaceType) {
+ case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY:
+ return KMAESKey.getBackupObjectCount();
+ case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY:
+ return KMHmacKey.getBackupObjectCount();
+ case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR:
+ return KMECDeviceUniqueKeyPair.getBackupObjectCount();
+ case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY:
+ return KMHmacKey.getBackupObjectCount();
+ default:
+ ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean isBootSignalEventSupported() {
+ return false;
+ }
+
+ @Override
+ public boolean isDeviceRebooted() {
+ return false;
+ }
+
+ @Override
+ public void clearDeviceBooted(boolean resetBootFlag) {
+ // To be filled
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java
new file mode 100644
index 0000000..05801b0
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAttestationCert.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright(C) 2020 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 com.android.javacard.seprovider;
+
+/**
+ * The KMAttestationCert interface represents a X509 compliant attestation certificate required to
+ * support keymaster's attestKey function. This cert will be created according to the specifications
+ * given in android keymaster hal documentation. KMSeProvider has to provide the instance of this
+ * certificate. This interface is designed based on builder pattern and hence each method returns
+ * instance of cert.
+ */
+public interface KMAttestationCert {
+
+ /**
+ * Set verified boot hash.
+ *
+ * @param obj This is a KMByteBlob containing hash
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert verifiedBootHash(short obj);
+
+ /**
+ * Set verified boot key received during booting up.
+ *
+ * @param obj This is a KMByteBlob containing verified boot key.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert verifiedBootKey(short obj);
+
+ /**
+ * Set verified boot state received during booting up.
+ *
+ * @param val This is a byte containing verified boot state value.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert verifiedBootState(byte val);
+
+ /**
+ * Set uniqueId received from CA certificate during provisioning.
+ *
+ * @param scratchpad Buffer to store intermediate results.
+ * @param scratchPadOff Start offset of the scratchpad buffer.
+ * @param creationTime This buffer contains the CREATION_TIME value.
+ * @param creationTimeOff Start offset of creattionTime buffer.
+ * @param creationTimeLen Length of the creationTime buffer.
+ * @param attestAppId This buffer contains the ATTESTATION_APPLICATION_ID value.
+ * @param attestAppIdOff Start offset of the attestAppId buffer.
+ * @param attestAppIdLen Length of the attestAppId buffer.
+ * @param resetSinceIdRotation This holds the information of RESET_SINCE_ID_ROTATION.
+ * @param masterKey
+ * @return instance of KMAttestationCert.
+ */
+ KMAttestationCert makeUniqueId(
+ byte[] scratchpad,
+ short scratchPadOff,
+ byte[] creationTime,
+ short creationTimeOff,
+ short creationTimeLen,
+ byte[] attestAppId,
+ short attestAppIdOff,
+ short attestAppIdLen,
+ byte resetSinceIdRotation,
+ KMKey masterKey);
+
+ /**
+ * Set start time received from creation/activation time tag. Used for certificate's valid period.
+ *
+ * @param obj This is a KMByteBlob object containing start time.
+ * @param scratchpad Buffer to store intermediate results.
+ * @return instance of KMAttestationCert.
+ */
+ KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratchpad);
+
+ /**
+ * Set expiry time received from expiry time tag or ca certificates expiry time. Used for
+ * certificate's valid period.
+ *
+ * @param usageExpiryTimeObj This is a KMByteBlob containing expiry time. certificate.
+ * @param scratchPad Buffer to store intermediate results.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, byte[] scratchPad);
+
+ /**
+ * Set device lock status received during booting time or due to device lock command.
+ *
+ * @param val This is true if device is locked.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert deviceLocked(boolean val);
+
+ /**
+ * Set public key to be attested received from attestKey command.
+ *
+ * @param obj This is KMByteBlob containing the public key.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert publicKey(short obj);
+
+ /**
+ * Set attestation challenge received from attestKey command.
+ *
+ * @param obj This is KMByteBlob containing the attestation challenge.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert attestationChallenge(short obj);
+
+ /**
+ * Set extension tag received from key characteristics which needs to be added to android
+ * extension. This method will called once for each tag.
+ *
+ * @param tag is the KMByteBlob containing KMTag.
+ * @param hwEnforced is true if the tag has to be added to hw enforced list or else added to sw
+ * enforced list.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert extensionTag(short tag, boolean hwEnforced);
+
+ /**
+ * Set ASN.1 encoded X509 issuer field received from attestation key CA cert.
+ *
+ * @param obj This is KMByteBlob containing the issuer.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert issuer(short obj);
+
+ /**
+ * Set byte buffer to be used to generate certificate.
+ *
+ * @param buf This is byte[] buffer.
+ * @param bufStart This is short start offset.
+ * @param maxLen This is short length of the buffer.
+ * @return instance of KMAttestationCert
+ */
+ KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen);
+
+ /**
+ * Get the start of the certificate
+ *
+ * @return start of the attestation cert.
+ */
+ short getCertStart();
+
+ /**
+ * Get the length of the certificate
+ *
+ * @return length of the attestation cert.
+ */
+ short getCertLength();
+
+ /**
+ * Build a fake signed certificate. After this method executes the certificate is ready with the
+ * signature equal to 1 byte which is 0 and with rsa signature algorithm.
+ */
+ void build();
+
+ /**
+ * Set the Serial number in the certificate. If no serial number is set then serial number is 1.
+ *
+ * @param serialNumber
+ */
+ boolean serialNumber(short serialNumber);
+
+ /**
+ * Set the Subject Name in the certificate.
+ *
+ * @param subject
+ */
+ boolean subjectName(short subject);
+
+ /**
+ * Set attestation key and mode.
+ *
+ * @param attestKey KMByteBlob of the key
+ * @param mode
+ */
+ KMAttestationCert ecAttestKey(short attestKey, byte mode);
+ /**
+ * Set attestation key and mode.
+ *
+ * @param attestKey KMByteBlob of the key
+ * @param mode
+ */
+ KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte mode);
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java
new file mode 100644
index 0000000..61ddb36
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMDataStoreConstants.java
@@ -0,0 +1,17 @@
+package com.android.javacard.seprovider;
+
+/**
+ * This class holds different interface type constants to differentiate between the instances of
+ * Computed Hmac key, device unique key pair, RKP Mac key, and master key when passed as generic
+ * objects. These constants are used in upgrade flow to retrieve the size of the object and
+ * primitive types saved and restored for respective key types.
+ */
+public class KMDataStoreConstants {
+ // INTERFACE Types
+ public static final byte INTERFACE_TYPE_COMPUTED_HMAC_KEY = 0x01;
+ // 0x02 reserved for INTERFACE_TYPE_ATTESTATION_KEY
+ public static final byte INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR = 0x03;
+ public static final byte INTERFACE_TYPE_MASTER_KEY = 0x04;
+ public static final byte INTERFACE_TYPE_PRE_SHARED_KEY = 0x05;
+ public static final byte INTERFACE_TYPE_RKP_MAC_KEY = 0x06;
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKeyPair.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKeyPair.java
new file mode 100644
index 0000000..0e430a3
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKeyPair.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright(C) 2021 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import javacard.security.ECPublicKey;
+import javacard.security.KeyPair;
+import org.globalplatform.upgrade.Element;
+
+/** This is a wrapper class for KeyPair. */
+public class KMECDeviceUniqueKeyPair implements KMKey {
+
+ public KeyPair ecKeyPair;
+
+ @Override
+ public short getPublicKey(byte[] buf, short offset) {
+ ECPublicKey publicKey = (ECPublicKey) ecKeyPair.getPublic();
+ return publicKey.getW(buf, offset);
+ }
+
+ public KMECDeviceUniqueKeyPair(KeyPair ecPair) {
+ ecKeyPair = ecPair;
+ }
+
+ public static void onSave(Element element, KMECDeviceUniqueKeyPair kmKey) {
+ element.write(kmKey.ecKeyPair);
+ }
+
+ public static KMECDeviceUniqueKeyPair onRestore(KeyPair ecKey) {
+ if (ecKey == null) {
+ return null;
+ }
+ return new KMECDeviceUniqueKeyPair(ecKey);
+ }
+
+ public static short getBackupPrimitiveByteCount() {
+ return (short) 0;
+ }
+
+ public static short getBackupObjectCount() {
+ return (short) 1;
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java
new file mode 100644
index 0000000..83774ab
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMEcdsa256NoDigestSignature.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright(C) 2020 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import javacard.framework.Util;
+import javacard.security.CryptoException;
+import javacard.security.Key;
+import javacard.security.MessageDigest;
+import javacard.security.Signature;
+import javacardx.crypto.Cipher;
+
+/**
+ * This class provides support for ECDSA_NO_DIGEST signature algorithm. Added this because javacard
+ * 3.0.5 does not support this
+ */
+public class KMEcdsa256NoDigestSignature extends Signature {
+
+ public static final byte ALG_ECDSA_NODIGEST = (byte) 0x67;
+ public static final byte MAX_NO_DIGEST_MSG_LEN = 32;
+ private byte algorithm;
+ private Signature inst;
+
+ public KMEcdsa256NoDigestSignature(byte alg) {
+ algorithm = alg;
+ // There is no constant for no digest so ALG_ECDSA_SHA_256 is used. However,
+ // signPreComputedHash is used for signing which is equivalent to no digest sign.
+ inst = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
+ }
+
+ @Override
+ public void init(Key key, byte b) throws CryptoException {
+ inst.init(key, b);
+ }
+
+ @Override
+ public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException {
+ inst.init(key, b, bytes, i, i1);
+ }
+
+ @Override
+ public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3)
+ throws CryptoException {}
+
+ @Override
+ public byte getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public byte getMessageDigestAlgorithm() {
+ return MessageDigest.ALG_NULL;
+ }
+
+ @Override
+ public byte getCipherAlgorithm() {
+ return 0;
+ }
+
+ @Override
+ public byte getPaddingAlgorithm() {
+ return Cipher.PAD_NULL;
+ }
+
+ @Override
+ public short getLength() throws CryptoException {
+ return inst.getLength();
+ }
+
+ @Override
+ public void update(byte[] message, short msgStart, short messageLength) throws CryptoException {
+ // HAL accumulates the data and send it at finish operation.
+ }
+
+ @Override
+ public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2)
+ throws CryptoException {
+ try {
+ if (i1 > MAX_NO_DIGEST_MSG_LEN) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_USE);
+ }
+ // add zeros to the left
+ if (i1 < MAX_NO_DIGEST_MSG_LEN) {
+ Util.arrayFillNonAtomic(
+ KMAndroidSEProvider.getInstance().tmpArray,
+ (short) 0,
+ (short) MAX_NO_DIGEST_MSG_LEN,
+ (byte) 0);
+ }
+ Util.arrayCopyNonAtomic(
+ bytes,
+ i,
+ KMAndroidSEProvider.getInstance().tmpArray,
+ (short) (MAX_NO_DIGEST_MSG_LEN - i1),
+ i1);
+ return inst.signPreComputedHash(
+ KMAndroidSEProvider.getInstance().tmpArray,
+ (short) 0,
+ (short) MAX_NO_DIGEST_MSG_LEN,
+ bytes1,
+ i2);
+ } finally {
+ KMAndroidSEProvider.getInstance().clean();
+ }
+ }
+
+ @Override
+ public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2)
+ throws CryptoException {
+ return inst.sign(bytes, i, i1, bytes1, i2);
+ }
+
+ @Override
+ public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3)
+ throws CryptoException {
+ // Verification is handled inside HAL
+ return false;
+ }
+
+ @Override
+ public boolean verifyPreComputedHash(
+ byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException {
+ // Verification is handled inside HAL
+ return false;
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMError.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMError.java
new file mode 100644
index 0000000..69cb069
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMError.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright(C) 2020 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 com.android.javacard.seprovider;
+
+/**
+ * KMError includes all the error codes from android keymaster hal specifications. The values are
+ * positive unlike negative values in keymaster hal.
+ */
+public class KMError {
+
+ public static final short OK = 0;
+ public static final short UNSUPPORTED_PURPOSE = 2;
+ public static final short UNSUPPORTED_ALGORITHM = 4;
+ public static final short INVALID_INPUT_LENGTH = 21;
+ public static final short VERIFICATION_FAILED = 30;
+ public static final short TOO_MANY_OPERATIONS = 31;
+ public static final short INVALID_ARGUMENT = 38;
+ public static final short UNKNOWN_ERROR = 1000;
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java
new file mode 100644
index 0000000..79983a2
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright(C) 2020 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 com.android.javacard.seprovider;
+
+import javacard.framework.JCSystem;
+
+/**
+ * KMException is shared instance of exception used for all exceptions in the applet. It is used to
+ * throw EMError errors.
+ */
+public class KMException extends RuntimeException {
+
+ private static short[] reason;
+ private static KMException exception;
+
+ private KMException() {}
+
+ public static short reason() {
+ return reason[0];
+ }
+
+ public static void throwIt(short e) {
+ if (reason == null) {
+ reason = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_DESELECT);
+ }
+ if (exception == null) {
+ exception = new KMException();
+ }
+ reason[0] = e;
+ throw exception;
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java
new file mode 100644
index 0000000..e938a2b
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright(C) 2020 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import javacard.security.HMACKey;
+import org.globalplatform.upgrade.Element;
+
+/** This is a wrapper class for HMACKey. */
+public class KMHmacKey implements KMKey {
+
+ public HMACKey hmacKey;
+
+ public KMHmacKey(HMACKey key) {
+ hmacKey = key;
+ }
+
+ public static void onSave(Element element, KMHmacKey kmKey) {
+ element.write(kmKey.hmacKey);
+ }
+
+ public static KMHmacKey onRestore(HMACKey hmacKey) {
+ if (hmacKey == null) {
+ return null;
+ }
+ return new KMHmacKey(hmacKey);
+ }
+
+ public static short getBackupPrimitiveByteCount() {
+ return (short) 0;
+ }
+
+ public static short getBackupObjectCount() {
+ return (short) 1;
+ }
+
+ @Override
+ public short getPublicKey(byte[] buf, short offset) {
+ return (short) 0;
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKey.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKey.java
new file mode 100644
index 0000000..9894382
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKey.java
@@ -0,0 +1,10 @@
+package com.android.javacard.seprovider;
+
+/**
+ * This interface helps to decouple Javacard internal key objects from the keymaster package. Using
+ * Javacard key objects provides security by providing protection against side channel attacks.
+ * KMAESKey, KMECDeviceUniqueKey and KMHmacKey implements this interface.
+ */
+public interface KMKey {
+ short getPublicKey(byte[] buf, short offset);
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java
new file mode 100644
index 0000000..a37da08
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java
@@ -0,0 +1,10 @@
+package com.android.javacard.seprovider;
+
+/**
+ * This class holds the KeyObject and its associated algorithm value. Each KMKeyObject is tied to
+ * one of the crypto operations.
+ */
+public class KMKeyObject {
+ public byte algorithm;
+ public Object keyObjectInst;
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java
new file mode 100644
index 0000000..12e691e
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright(C) 2020 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 com.android.javacard.seprovider;
+
+/**
+ * KMOperation represents a persistent operation started by keymaster hal's beginOperation function.
+ * This operation is persistent i.e. it will be stored in non volatile memory of se card. It will be
+ * returned back to KMSEProvider for the reuse when the operation is finished.
+ */
+public interface KMOperation {
+
+ // Used for cipher operations
+ short update(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart);
+
+ // Used for signature operations
+ short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength);
+
+ // Used for finishing cipher operations or ecdh keyAgreement.
+ short finish(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart);
+
+ // Used for finishing signing operations.
+ short sign(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] signBuf,
+ short signStart);
+
+ // Used for finishing verifying operations.
+ boolean verify(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] signBuf,
+ short signStart,
+ short signLength);
+
+ // Used for aborting the ongoing operations.
+ void abort();
+
+ // Used for AES GCM cipher operation.
+ void updateAAD(byte[] dataBuf, short dataStart, short dataLength);
+
+ // Used for getting output size before finishing a AES GCM cipher operation. For encryption this
+ // will
+ // include the auth tag which is appended at the end of the encrypted data. For decryption this
+ // will be
+ // size of the decrypted data only.
+ short getAESGCMOutputSize(short dataSize, short macLength);
+
+ KMKeyObject getKeyObject();
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java
new file mode 100644
index 0000000..8059e44
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright(C) 2020 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import javacard.framework.JCSystem;
+import javacard.framework.Util;
+import javacard.security.CryptoException;
+import javacard.security.Key;
+import javacard.security.KeyAgreement;
+import javacard.security.PrivateKey;
+import javacard.security.Signature;
+import javacardx.crypto.AEADCipher;
+import javacardx.crypto.Cipher;
+
+/**
+ * This class contains the actual implementation of all the crypto operations. It internally uses
+ * the Javacard crypto library to perform the operations.
+ */
+public class KMOperationImpl implements KMOperation {
+
+ private static final byte ALG_TYPE_OFFSET = 0x00;
+ private static final byte PADDING_OFFSET = 0x01;
+ private static final byte PURPOSE_OFFSET = 0x02;
+ private static final byte BLOCK_MODE_OFFSET = 0x03;
+ private static final byte MAC_LENGTH_OFFSET = 0x04;
+ private final byte[] EMPTY = {};
+ // This will hold the length of the buffer stored inside the
+ // Java Card after the GCM update operation.
+ private static final byte AES_GCM_UPDATE_LEN_OFFSET = 0x05;
+ private static final byte PARAMETERS_LENGTH = 6;
+ private short[] parameters;
+ // Either one of Cipher/Signature instance is stored.
+ private Object[] operationInst;
+
+ public KMOperationImpl() {
+ parameters = JCSystem.makeTransientShortArray(PARAMETERS_LENGTH, JCSystem.CLEAR_ON_RESET);
+ operationInst = JCSystem.makeTransientObjectArray((short) 2, JCSystem.CLEAR_ON_RESET);
+ reset();
+ }
+
+ public short getPurpose() {
+ return parameters[PURPOSE_OFFSET];
+ }
+
+ public void setPurpose(short mode) {
+ parameters[PURPOSE_OFFSET] = mode;
+ }
+
+ public short getMacLength() {
+ return parameters[MAC_LENGTH_OFFSET];
+ }
+
+ public void setMacLength(short macLength) {
+ parameters[MAC_LENGTH_OFFSET] = macLength;
+ }
+
+ public short getPaddingAlgorithm() {
+ return parameters[PADDING_OFFSET];
+ }
+
+ public void setPaddingAlgorithm(short alg) {
+ parameters[PADDING_OFFSET] = alg;
+ }
+
+ public void setBlockMode(short mode) {
+ parameters[BLOCK_MODE_OFFSET] = mode;
+ }
+
+ public short getBlockMode() {
+ return parameters[BLOCK_MODE_OFFSET];
+ }
+
+ public short getAlgorithmType() {
+ return parameters[ALG_TYPE_OFFSET];
+ }
+
+ public void setAlgorithmType(short cipherAlg) {
+ parameters[ALG_TYPE_OFFSET] = cipherAlg;
+ }
+
+ public void setCipher(Cipher cipher) {
+ operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] = cipher;
+ }
+
+ public void setSignature(Signature signer) {
+ operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] = signer;
+ }
+
+ public void setKeyAgreement(KeyAgreement keyAgreement) {
+ operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] = keyAgreement;
+ }
+
+ public boolean isResourceMatches(Object object, byte resourceType) {
+ return operationInst[resourceType] == object;
+ }
+
+ public void setKeyObject(KMKeyObject keyObject) {
+ operationInst[KMPoolManager.RESOURCE_TYPE_KEY] = keyObject;
+ }
+
+ public KMKeyObject getKeyObject() {
+ return (KMKeyObject) operationInst[KMPoolManager.RESOURCE_TYPE_KEY];
+ }
+
+ private void reset() {
+ operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] = null;
+ operationInst[KMPoolManager.RESOURCE_TYPE_KEY] = null;
+ parameters[MAC_LENGTH_OFFSET] = KMType.INVALID_VALUE;
+ parameters[AES_GCM_UPDATE_LEN_OFFSET] = 0;
+ parameters[BLOCK_MODE_OFFSET] = KMType.INVALID_VALUE;
+ parameters[PURPOSE_OFFSET] = KMType.INVALID_VALUE;
+ parameters[ALG_TYPE_OFFSET] = KMType.INVALID_VALUE;
+ parameters[PADDING_OFFSET] = KMType.INVALID_VALUE;
+ }
+
+ private byte mapPurpose(short purpose) {
+ switch (purpose) {
+ case KMType.ENCRYPT:
+ return Cipher.MODE_ENCRYPT;
+ case KMType.DECRYPT:
+ return Cipher.MODE_DECRYPT;
+ case KMType.SIGN:
+ return Signature.MODE_SIGN;
+ case KMType.VERIFY:
+ return Signature.MODE_VERIFY;
+ }
+ return -1;
+ }
+
+ private void initSymmetricCipher(Key key, byte[] ivBuffer, short ivStart, short ivLength) {
+ Cipher symmCipher = (Cipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO];
+ byte cipherAlg = symmCipher.getAlgorithm();
+ switch (cipherAlg) {
+ case Cipher.ALG_AES_BLOCK_128_CBC_NOPAD:
+ case Cipher.ALG_AES_CTR:
+ symmCipher.init(key, mapPurpose(getPurpose()), ivBuffer, ivStart, ivLength);
+ break;
+ case Cipher.ALG_AES_BLOCK_128_ECB_NOPAD:
+ case Cipher.ALG_DES_ECB_NOPAD:
+ symmCipher.init(key, mapPurpose(getPurpose()));
+ break;
+ case Cipher.ALG_DES_CBC_NOPAD:
+ // Consume only 8 bytes of iv. the random number for iv is of 16 bytes.
+ // While sending back the iv, send only 8 bytes.
+ symmCipher.init(key, mapPurpose(getPurpose()), ivBuffer, ivStart, (short) 8);
+ break;
+ case AEADCipher.ALG_AES_GCM:
+ ((AEADCipher) symmCipher).init(key, mapPurpose(getPurpose()), ivBuffer, ivStart, ivLength);
+ break;
+ default: // This should never happen
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ break;
+ }
+ }
+
+ private void initRsa(Key key, short digest) {
+ if (KMType.SIGN == getPurpose()) {
+ byte mode;
+ if (getPaddingAlgorithm() == KMType.PADDING_NONE
+ || (getPaddingAlgorithm() == KMType.RSA_PKCS1_1_5_SIGN && digest == KMType.DIGEST_NONE)) {
+ mode = Cipher.MODE_DECRYPT;
+ } else {
+ mode = Signature.MODE_SIGN;
+ }
+ ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]).init((PrivateKey) key, mode);
+ } else { // RSA Cipher
+ ((Cipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .init((PrivateKey) key, mapPurpose(getPurpose()));
+ }
+ }
+
+ private void initEc(Key key) {
+ if (KMType.AGREE_KEY == getPurpose()) {
+ ((KeyAgreement) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]).init((PrivateKey) key);
+ } else {
+ ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .init((PrivateKey) key, mapPurpose(getPurpose()));
+ }
+ }
+
+ public void init(Key key, short digest, byte[] buf, short start, short length) {
+ switch (getAlgorithmType()) {
+ case KMType.AES:
+ case KMType.DES:
+ initSymmetricCipher(key, buf, start, length);
+ break;
+ case KMType.HMAC:
+ ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .init(key, mapPurpose(getPurpose()));
+ break;
+ case KMType.RSA:
+ initRsa(key, digest);
+ break;
+ case KMType.EC:
+ initEc(key);
+ break;
+ default: // This should never happen
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ break;
+ }
+ }
+
+ @Override
+ public short update(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart) {
+ short len =
+ ((Cipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .update(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart);
+ if (parameters[ALG_TYPE_OFFSET] == KMType.AES && parameters[BLOCK_MODE_OFFSET] == KMType.GCM) {
+ // Every time Block size data is stored as intermediate result.
+ parameters[AES_GCM_UPDATE_LEN_OFFSET] += (short) (inputDataLength - len);
+ }
+ return len;
+ }
+
+ @Override
+ public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength) {
+ ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .update(inputDataBuf, inputDataStart, inputDataLength);
+ return 0;
+ }
+
+ private short finishKeyAgreement(
+ byte[] publicKey, short start, short len, byte[] output, short outputStart) {
+ return ((KeyAgreement) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .generateSecret(publicKey, start, len, output, outputStart);
+ }
+
+ private short finishCipher(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLen,
+ byte[] outputDataBuf,
+ short outputDataStart) {
+ short len = 0;
+ try {
+ byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray;
+ Cipher cipher = (Cipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO];
+ short cipherAlg = parameters[ALG_TYPE_OFFSET];
+ short blockMode = parameters[BLOCK_MODE_OFFSET];
+ short mode = parameters[PURPOSE_OFFSET];
+ short macLength = parameters[MAC_LENGTH_OFFSET];
+ short padding = parameters[PADDING_OFFSET];
+
+ if (cipherAlg == KMType.AES && blockMode == KMType.GCM) {
+ if (mode == KMType.DECRYPT) {
+ inputDataLen = (short) (inputDataLen - macLength);
+ }
+ } else if ((cipherAlg == KMType.DES || cipherAlg == KMType.AES)
+ && padding == KMType.PKCS7
+ && mode == KMType.ENCRYPT) {
+ byte blkSize = 16;
+ byte paddingBytes;
+ short inputlen = inputDataLen;
+ if (cipherAlg == KMType.DES) {
+ blkSize = 8;
+ }
+ // padding bytes
+ if (inputlen % blkSize == 0) {
+ paddingBytes = blkSize;
+ } else {
+ paddingBytes = (byte) (blkSize - (inputlen % blkSize));
+ }
+ // final len with padding
+ inputlen = (short) (inputlen + paddingBytes);
+ // intermediate buffer to copy input data+padding
+ // fill in the padding
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, inputlen, paddingBytes);
+ // copy the input data
+ Util.arrayCopyNonAtomic(inputDataBuf, inputDataStart, tmpArray, (short) 0, inputDataLen);
+ inputDataBuf = tmpArray;
+ inputDataLen = inputlen;
+ inputDataStart = 0;
+ }
+ len =
+ cipher.doFinal(
+ inputDataBuf, inputDataStart, inputDataLen, outputDataBuf, outputDataStart);
+ if ((cipherAlg == KMType.AES || cipherAlg == KMType.DES)
+ && padding == KMType.PKCS7
+ && mode == KMType.DECRYPT) {
+ byte blkSize = 16;
+ if (cipherAlg == KMType.DES) {
+ blkSize = 8;
+ }
+ if (len > 0) {
+ // verify if padding is corrupted.
+ byte paddingByte = outputDataBuf[(short) (outputDataStart + len - 1)];
+ // padding byte always should be <= block size
+ if ((short) paddingByte > blkSize || (short) paddingByte <= 0) {
+ KMException.throwIt(KMError.INVALID_ARGUMENT);
+ }
+
+ for (short j = 1; j <= paddingByte; ++j) {
+ if (outputDataBuf[(short) (outputDataStart + len - j)] != paddingByte) {
+ KMException.throwIt(KMError.INVALID_ARGUMENT);
+ }
+ }
+ len = (short) (len - (short) paddingByte); // remove the padding bytes
+ }
+ } else if (cipherAlg == KMType.AES && blockMode == KMType.GCM) {
+ if (mode == KMType.ENCRYPT) {
+ len +=
+ ((AEADCipher) cipher)
+ .retrieveTag(outputDataBuf, (short) (outputDataStart + len), macLength);
+ } else {
+ boolean verified =
+ ((AEADCipher) cipher)
+ .verifyTag(
+ inputDataBuf, (short) (inputDataStart + inputDataLen), macLength, macLength);
+ if (!verified) {
+ KMException.throwIt(KMError.VERIFICATION_FAILED);
+ }
+ }
+ }
+ } finally {
+ KMAndroidSEProvider.getInstance().clean();
+ }
+ return len;
+ }
+
+ @Override
+ public short finish(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLen,
+ byte[] outputDataBuf,
+ short outputDataStart) {
+ if (parameters[PURPOSE_OFFSET] == KMType.AGREE_KEY) {
+ return finishKeyAgreement(
+ inputDataBuf, inputDataStart, inputDataLen, outputDataBuf, outputDataStart);
+ } else {
+ return finishCipher(
+ inputDataBuf, inputDataStart, inputDataLen, outputDataBuf, outputDataStart);
+ }
+ }
+
+ @Override
+ public short sign(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] signBuf,
+ short signStart) {
+ return ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .sign(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart);
+ }
+
+ @Override
+ public boolean verify(
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] signBuf,
+ short signStart,
+ short signLength) {
+ return ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .verify(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart, signLength);
+ }
+
+ @Override
+ public void abort() {
+ // Few simulators does not reset the Hmac signer instance on init so as
+ // a workaround to reset the hmac signer instance in case of abort/failure of the operation
+ // the corresponding sign / verify function is called.
+ if (operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] != null) {
+ if ((parameters[PURPOSE_OFFSET] == KMType.SIGN || parameters[PURPOSE_OFFSET] == KMType.VERIFY)
+ && (((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]).getAlgorithm()
+ == Signature.ALG_HMAC_SHA_256)) {
+ Signature signer = (Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO];
+ try {
+ if (parameters[PURPOSE_OFFSET] == KMType.SIGN) {
+ signer.sign(EMPTY, (short) 0, (short) 0, EMPTY, (short) 0);
+ } else {
+ signer.verify(EMPTY, (short) 0, (short) 0, EMPTY, (short) 0, (short) 0);
+ }
+ } catch (Exception e) {
+ // Ignore.
+ }
+ }
+ }
+ reset();
+ }
+
+ @Override
+ public void updateAAD(byte[] dataBuf, short dataStart, short dataLength) {
+ ((AEADCipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO])
+ .updateAAD(dataBuf, dataStart, dataLength);
+ }
+
+ @Override
+ public short getAESGCMOutputSize(short dataSize, short macLength) {
+ if (parameters[PURPOSE_OFFSET] == KMType.ENCRYPT) {
+ return (short) (parameters[AES_GCM_UPDATE_LEN_OFFSET] + dataSize + macLength);
+ } else {
+ return (short) (parameters[AES_GCM_UPDATE_LEN_OFFSET] + dataSize - macLength);
+ }
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java
new file mode 100644
index 0000000..8ca2664
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java
@@ -0,0 +1,665 @@
+/*
+ * Copyright(C) 2021 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import javacard.framework.JCSystem;
+import javacard.security.AESKey;
+import javacard.security.CryptoException;
+import javacard.security.DESKey;
+import javacard.security.ECPrivateKey;
+import javacard.security.ECPublicKey;
+import javacard.security.HMACKey;
+import javacard.security.KeyAgreement;
+import javacard.security.KeyBuilder;
+import javacard.security.KeyPair;
+import javacard.security.Signature;
+import javacardx.crypto.AEADCipher;
+import javacardx.crypto.Cipher;
+
+/**
+ * This class creates and manages all the cipher, signer, key agreement, operation and trusted
+ * confirmation pool instances. Each cipher or signer pool can hold a maximum of 4 instances per
+ * algorithm; however, only one instance of each algorithm is created initially and if required more
+ * instances are created dynamically. A maximum of four operations can be performed simultaneously.
+ * Upon reaching the maximum limit of 4, further operations or crypto instances will throw a
+ * TOO_MANY_OPERATIONS error. TrustedConfirmation pool is to support any operation which has the
+ * TRUSTED_CONFIRMATION tag in its key parameters.
+ */
+public class KMPoolManager {
+
+ public static final byte MAX_OPERATION_INSTANCES = 4;
+ private static final byte HMAC_MAX_OPERATION_INSTANCES = 8;
+ public static final byte AES_128 = 0x04;
+ public static final byte AES_256 = 0x05;
+ // Resource type constants
+ public static final byte RESOURCE_TYPE_CRYPTO = 0x00;
+ public static final byte RESOURCE_TYPE_KEY = 0x01;
+ // static final variables
+ // --------------------------------------------------------------
+ // P-256 Curve Parameters
+ static byte[] secp256r1_P;
+ static byte[] secp256r1_A;
+
+ static byte[] secp256r1_B;
+ static byte[] secp256r1_S;
+
+ // Uncompressed form
+ static byte[] secp256r1_UCG;
+ static byte[] secp256r1_N;
+ static final short secp256r1_H = 1;
+ // --------------------------------------------------------------
+
+ // Cipher pool
+ private Object[] cipherPool;
+ // Signature pool
+ private Object[] signerPool;
+ // Keyagreement pool
+ private Object[] keyAgreementPool;
+ // KMOperationImpl pool
+ private Object[] operationPool;
+ // Hmac signer pool which is used to support TRUSTED_CONFIRMATION_REQUIRED tag.
+ private Object[] hmacSignOperationPool;
+
+ private Object[] keysPool;
+ // RKP uses AESGCM and HMAC in generateCSR flow.
+ KMOperation rkpOPeration;
+ Cipher rkpAesGcm;
+ Signature rkpHmac;
+ KMKeyObject rkpHmacKey;
+ KMKeyObject rkpAesKey;
+
+ final byte[] KEY_ALGS = {
+ AES_128, AES_256, KMType.DES, KMType.RSA, KMType.EC, KMType.HMAC,
+ };
+
+ final byte[] CIPHER_ALGS = {
+ Cipher.ALG_AES_BLOCK_128_CBC_NOPAD,
+ Cipher.ALG_AES_BLOCK_128_ECB_NOPAD,
+ Cipher.ALG_DES_CBC_NOPAD,
+ Cipher.ALG_DES_ECB_NOPAD,
+ Cipher.ALG_AES_CTR,
+ Cipher.ALG_RSA_PKCS1,
+ KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1,
+ KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256,
+ Cipher.ALG_RSA_NOPAD,
+ AEADCipher.ALG_AES_GCM
+ };
+
+ final byte[] SIG_ALGS = {
+ Signature.ALG_RSA_SHA_256_PKCS1,
+ Signature.ALG_RSA_SHA_256_PKCS1_PSS,
+ Signature.ALG_ECDSA_SHA_256,
+ Signature.ALG_HMAC_SHA_256,
+ KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD,
+ KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST,
+ KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST
+ };
+
+ final byte[] KEY_AGREE_ALGS = {KeyAgreement.ALG_EC_SVDP_DH_PLAIN};
+
+ private static KMPoolManager poolManager;
+
+ public static KMPoolManager getInstance() {
+ if (poolManager == null) {
+ poolManager = new KMPoolManager();
+ }
+ return poolManager;
+ }
+
+ public static void initStatics() {
+ secp256r1_P =
+ new byte[] {
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF
+ };
+
+ secp256r1_A =
+ new byte[] {
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFC
+ };
+
+ secp256r1_B =
+ new byte[] {
+ (byte) 0x5A, (byte) 0xC6, (byte) 0x35, (byte) 0xD8, (byte) 0xAA, (byte) 0x3A,
+ (byte) 0x93, (byte) 0xE7, (byte) 0xB3, (byte) 0xEB, (byte) 0xBD, (byte) 0x55,
+ (byte) 0x76, (byte) 0x98, (byte) 0x86, (byte) 0xBC, (byte) 0x65, (byte) 0x1D,
+ (byte) 0x06, (byte) 0xB0, (byte) 0xCC, (byte) 0x53, (byte) 0xB0, (byte) 0xF6,
+ (byte) 0x3B, (byte) 0xCE, (byte) 0x3C, (byte) 0x3E, (byte) 0x27, (byte) 0xD2,
+ (byte) 0x60, (byte) 0x4B
+ };
+
+ secp256r1_S =
+ new byte[] {
+ (byte) 0xC4, (byte) 0x9D, (byte) 0x36, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
+ (byte) 0x04, (byte) 0x93, (byte) 0x6A, (byte) 0x66, (byte) 0x78, (byte) 0xE1,
+ (byte) 0x13, (byte) 0x9D, (byte) 0x26, (byte) 0xB7, (byte) 0x81, (byte) 0x9F,
+ (byte) 0x7E, (byte) 0x90
+ };
+
+ // Uncompressed form
+ secp256r1_UCG =
+ new byte[] {
+ (byte) 0x04, (byte) 0x6B, (byte) 0x17, (byte) 0xD1, (byte) 0xF2, (byte) 0xE1,
+ (byte) 0x2C, (byte) 0x42, (byte) 0x47, (byte) 0xF8, (byte) 0xBC, (byte) 0xE6,
+ (byte) 0xE5, (byte) 0x63, (byte) 0xA4, (byte) 0x40, (byte) 0xF2, (byte) 0x77,
+ (byte) 0x03, (byte) 0x7D, (byte) 0x81, (byte) 0x2D, (byte) 0xEB, (byte) 0x33,
+ (byte) 0xA0, (byte) 0xF4, (byte) 0xA1, (byte) 0x39, (byte) 0x45, (byte) 0xD8,
+ (byte) 0x98, (byte) 0xC2, (byte) 0x96, (byte) 0x4F, (byte) 0xE3, (byte) 0x42,
+ (byte) 0xE2, (byte) 0xFE, (byte) 0x1A, (byte) 0x7F, (byte) 0x9B, (byte) 0x8E,
+ (byte) 0xE7, (byte) 0xEB, (byte) 0x4A, (byte) 0x7C, (byte) 0x0F, (byte) 0x9E,
+ (byte) 0x16, (byte) 0x2B, (byte) 0xCE, (byte) 0x33, (byte) 0x57, (byte) 0x6B,
+ (byte) 0x31, (byte) 0x5E, (byte) 0xCE, (byte) 0xCB, (byte) 0xB6, (byte) 0x40,
+ (byte) 0x68, (byte) 0x37, (byte) 0xBF, (byte) 0x51, (byte) 0xF5
+ };
+
+ secp256r1_N =
+ new byte[] {
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xBC, (byte) 0xE6,
+ (byte) 0xFA, (byte) 0xAD, (byte) 0xA7, (byte) 0x17, (byte) 0x9E, (byte) 0x84,
+ (byte) 0xF3, (byte) 0xB9, (byte) 0xCA, (byte) 0xC2, (byte) 0xFC, (byte) 0x63,
+ (byte) 0x25, (byte) 0x51
+ };
+ }
+
+ private KMPoolManager() {
+ initStatics();
+ cipherPool = new Object[(short) (CIPHER_ALGS.length * MAX_OPERATION_INSTANCES)];
+ // Extra 4 algorithms are used to support TRUSTED_CONFIRMATION_REQUIRED feature.
+ signerPool =
+ new Object[(short) ((SIG_ALGS.length * MAX_OPERATION_INSTANCES) + MAX_OPERATION_INSTANCES)];
+ keyAgreementPool = new Object[(short) (KEY_AGREE_ALGS.length * MAX_OPERATION_INSTANCES)];
+
+ keysPool =
+ new Object[(short) ((KEY_ALGS.length * MAX_OPERATION_INSTANCES) + MAX_OPERATION_INSTANCES)];
+ operationPool = new Object[MAX_OPERATION_INSTANCES];
+ hmacSignOperationPool = new Object[MAX_OPERATION_INSTANCES];
+ /* Initialize pools */
+ initializeOperationPool();
+ initializeHmacSignOperationPool();
+ initializeSignerPool();
+ initializeCipherPool();
+ initializeKeyAgreementPool();
+ initializeKeysPool();
+ // Initialize the Crypto and Key objects required for RKP flow.
+ initializeRKpObjects();
+ }
+
+ private void initializeRKpObjects() {
+ rkpOPeration = new KMOperationImpl();
+ rkpAesGcm = Cipher.getInstance(AEADCipher.ALG_AES_GCM, false);
+ rkpHmac = Signature.getInstance(Signature.ALG_HMAC_SHA_256, false);
+ rkpAesKey = createKeyObjectInstance(AES_256);
+ rkpHmacKey = createKeyObjectInstance(KMType.HMAC);
+ }
+
+ private void initializeKeysPool() {
+ for (short index = 0; index < KEY_ALGS.length; index++) {
+ keysPool[index] = createKeyObjectInstance(KEY_ALGS[index]);
+ }
+ }
+
+ private void initializeOperationPool() {
+ for (short index = 0; index < MAX_OPERATION_INSTANCES; index++) {
+ operationPool[index] = new KMOperationImpl();
+ }
+ }
+
+ private void initializeHmacSignOperationPool() {
+ for (short index = 0; index < MAX_OPERATION_INSTANCES; index++) {
+ hmacSignOperationPool[index] = new KMOperationImpl();
+ }
+ }
+
+ // Create a signature instance of each algorithm once.
+ private void initializeSignerPool() {
+ short index;
+ for (index = 0; index < SIG_ALGS.length; index++) {
+ signerPool[index] = getSignatureInstance(SIG_ALGS[index]);
+ }
+
+ // Allocate extra 4 HMAC signer instances required for trusted confirmation
+ for (short len = (short) (index + 4); index < len; index++) {
+ signerPool[index] = getSignatureInstance(Signature.ALG_HMAC_SHA_256);
+ }
+ }
+
+ // Create a cipher instance of each algorithm once.
+ private void initializeCipherPool() {
+ for (short index = 0; index < CIPHER_ALGS.length; index++) {
+ cipherPool[index] = getCipherInstance(CIPHER_ALGS[index]);
+ }
+ }
+
+ private void initializeKeyAgreementPool() {
+ for (short index = 0; index < KEY_AGREE_ALGS.length; index++) {
+ keyAgreementPool[index] = getKeyAgreementInstance(KEY_AGREE_ALGS[index]);
+ }
+ }
+
+ private Object[] getCryptoPoolInstance(short purpose) {
+ switch (purpose) {
+ case KMType.AGREE_KEY:
+ return keyAgreementPool;
+
+ case KMType.ENCRYPT:
+ case KMType.DECRYPT:
+ return cipherPool;
+
+ case KMType.SIGN:
+ case KMType.VERIFY:
+ return signerPool;
+
+ default:
+ KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
+ }
+ return null;
+ }
+
+ private Object createInstance(short purpose, short alg) {
+ switch (purpose) {
+ case KMType.AGREE_KEY:
+ return getKeyAgreementInstance((byte) alg);
+
+ case KMType.ENCRYPT:
+ case KMType.DECRYPT:
+ return getCipherInstance((byte) alg);
+
+ case KMType.SIGN:
+ case KMType.VERIFY:
+ return getSignatureInstance((byte) alg);
+
+ default:
+ KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
+ }
+ return null;
+ }
+
+ private KeyAgreement getKeyAgreementInstance(byte alg) {
+ return KeyAgreement.getInstance(alg, false);
+ }
+
+ private Signature getSignatureInstance(byte alg) {
+ if (KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD == alg
+ || KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST == alg) {
+ return new KMRsa2048NoDigestSignature(alg);
+ } else if (KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST == alg) {
+ return new KMEcdsa256NoDigestSignature(alg);
+ } else {
+ return Signature.getInstance(alg, false);
+ }
+ }
+
+ private KMKeyObject createKeyObjectInstance(byte alg) {
+ Object keyObject = null;
+ switch (alg) {
+ case AES_128:
+ keyObject =
+ (AESKey)
+ KeyBuilder.buildKey(
+ KeyBuilder.TYPE_AES_TRANSIENT_RESET, KeyBuilder.LENGTH_AES_128, false);
+ break;
+ case AES_256:
+ keyObject =
+ (AESKey)
+ KeyBuilder.buildKey(
+ KeyBuilder.TYPE_AES_TRANSIENT_RESET, KeyBuilder.LENGTH_AES_256, false);
+ break;
+ case KMType.DES:
+ keyObject =
+ (DESKey)
+ KeyBuilder.buildKey(
+ KeyBuilder.TYPE_DES_TRANSIENT_RESET, KeyBuilder.LENGTH_DES3_3KEY, false);
+ break;
+ case KMType.RSA:
+ keyObject = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048);
+ break;
+ case KMType.EC:
+ keyObject = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
+ initECKey((KeyPair) keyObject);
+ break;
+ case KMType.HMAC:
+ keyObject =
+ (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC_TRANSIENT_RESET, (short) 512, false);
+ break;
+ default:
+ KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
+ }
+ KMKeyObject ptr = new KMKeyObject();
+ ptr.algorithm = alg;
+ ptr.keyObjectInst = keyObject;
+ return ptr;
+ }
+
+ private Cipher getCipherInstance(byte alg) {
+ if ((KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1 == alg)
+ || (KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256 == alg)) {
+ return new KMRsaOAEPEncoding(alg);
+ } else {
+ return Cipher.getInstance(alg, false);
+ }
+ }
+
+ /**
+ * Returns the first available resource from operation pool.
+ *
+ * @return instance of the available resource or null if no resource is available.
+ */
+ public KMOperation getResourceFromOperationPool(boolean isTrustedConfOpr) {
+ short index = 0;
+ KMOperationImpl impl;
+ Object[] oprPool;
+ if (isTrustedConfOpr) {
+ oprPool = hmacSignOperationPool;
+ } else {
+ oprPool = operationPool;
+ }
+ while (index < oprPool.length) {
+ impl = (KMOperationImpl) oprPool[index];
+ // Mode is always set. so compare using mode value.
+ if (impl.getPurpose() == KMType.INVALID_VALUE) {
+ return impl;
+ }
+ index++;
+ }
+ return null;
+ }
+
+ private byte getAlgorithm(short purpose, Object object) {
+ switch (purpose) {
+ case KMType.AGREE_KEY:
+ return ((KeyAgreement) object).getAlgorithm();
+
+ case KMType.ENCRYPT:
+ case KMType.DECRYPT:
+ return ((Cipher) object).getAlgorithm();
+
+ case KMType.SIGN:
+ case KMType.VERIFY:
+ return ((Signature) object).getAlgorithm();
+
+ default:
+ KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
+ }
+ return 0;
+ }
+
+ private boolean isResourceBusy(Object obj, byte resourceType) {
+ short index = 0;
+ while (index < MAX_OPERATION_INSTANCES) {
+ if (((KMOperationImpl) operationPool[index]).isResourceMatches(obj, resourceType)
+ || ((KMOperationImpl) hmacSignOperationPool[index])
+ .isResourceMatches(obj, resourceType)) {
+ return true;
+ }
+ index++;
+ }
+ return false;
+ }
+
+ private void setObject(short purpose, KMOperation operation, Object obj) {
+ switch (purpose) {
+ case KMType.AGREE_KEY:
+ ((KMOperationImpl) operation).setKeyAgreement((KeyAgreement) obj);
+ break;
+ case KMType.ENCRYPT:
+ case KMType.DECRYPT:
+ ((KMOperationImpl) operation).setCipher((Cipher) obj);
+ break;
+ case KMType.SIGN:
+ case KMType.VERIFY:
+ ((KMOperationImpl) operation).setSignature((Signature) obj);
+ break;
+ default:
+ KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
+ }
+ }
+
+ private void reserveOperation(
+ KMOperation operation,
+ short purpose,
+ short strongboxAlgType,
+ short padding,
+ short blockMode,
+ short macLength,
+ Object obj,
+ KMKeyObject keyObject) {
+ ((KMOperationImpl) operation).setPurpose(purpose);
+ ((KMOperationImpl) operation).setAlgorithmType(strongboxAlgType);
+ ((KMOperationImpl) operation).setPaddingAlgorithm(padding);
+ ((KMOperationImpl) operation).setBlockMode(blockMode);
+ ((KMOperationImpl) operation).setMacLength(macLength);
+ ((KMOperationImpl) operation).setKeyObject(keyObject);
+ setObject(purpose, operation, obj);
+ }
+
+ public KMOperation getRKpOperation(
+ short purpose,
+ short alg,
+ short strongboxAlgType,
+ short padding,
+ short blockMode,
+ short macLength) {
+ if (((KMOperationImpl) rkpOPeration).getPurpose() != KMType.INVALID_VALUE) {
+ // Should not come here.
+ KMException.throwIt(KMError.UNKNOWN_ERROR);
+ }
+ Object cryptoObj = null;
+ KMKeyObject keyObject = null;
+
+ switch (alg) {
+ case AEADCipher.ALG_AES_GCM:
+ cryptoObj = rkpAesGcm;
+ keyObject = rkpAesKey;
+ break;
+ case Signature.ALG_HMAC_SHA_256:
+ cryptoObj = rkpHmac;
+ keyObject = rkpHmacKey;
+ break;
+ default:
+ // Should not come here.
+ KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
+ break;
+ }
+ reserveOperation(
+ rkpOPeration,
+ purpose,
+ strongboxAlgType,
+ padding,
+ blockMode,
+ macLength,
+ cryptoObj,
+ keyObject);
+ return rkpOPeration;
+ }
+
+ public KMOperation getOperationImpl(
+ short purpose,
+ short alg,
+ short strongboxAlgType,
+ short padding,
+ short blockMode,
+ short macLength,
+ short secretLength,
+ boolean isTrustedConfOpr) {
+ KMOperation operation;
+ // Throw exception if no resource from operation pool is available.
+ if (null == (operation = getResourceFromOperationPool(isTrustedConfOpr))) {
+ KMException.throwIt(KMError.TOO_MANY_OPERATIONS);
+ }
+ // Get one of the pool instances (cipher / signer / keyAgreement) based on purpose.
+ Object[] pool = getCryptoPoolInstance(purpose);
+ short index = 0;
+ short usageCount = 0;
+ short maxOperations = MAX_OPERATION_INSTANCES;
+ if (Signature.ALG_HMAC_SHA_256 == alg) {
+ maxOperations = HMAC_MAX_OPERATION_INSTANCES;
+ }
+
+ KMKeyObject keyObject = getKeyObjectFromPool(alg, secretLength, maxOperations);
+ while (index < pool.length) {
+ if (usageCount >= maxOperations) {
+ KMException.throwIt(KMError.TOO_MANY_OPERATIONS);
+ }
+ if (pool[index] == null) {
+ // Create one of the instance (Cipher / Signer / KeyAgreement] based on purpose.
+ Object cipherObject = createInstance(purpose, alg);
+ JCSystem.beginTransaction();
+ pool[index] = cipherObject;
+ JCSystem.commitTransaction();
+ reserveOperation(
+ operation,
+ purpose,
+ strongboxAlgType,
+ padding,
+ blockMode,
+ macLength,
+ pool[index],
+ keyObject);
+ break;
+ }
+ if (alg == getAlgorithm(purpose, pool[index])) {
+ // Check if the crypto instance is not busy and free to use.
+ if (!isResourceBusy(pool[index], RESOURCE_TYPE_CRYPTO)) {
+ reserveOperation(
+ operation,
+ purpose,
+ strongboxAlgType,
+ padding,
+ blockMode,
+ macLength,
+ pool[index],
+ keyObject);
+ break;
+ }
+ usageCount++;
+ }
+ index++;
+ }
+ return operation;
+ }
+
+ public KMKeyObject getKeyObjectFromPool(short alg, short secretLength, short maxOperations) {
+ KMKeyObject keyObject = null;
+ byte algo = mapAlgorithm(alg, secretLength);
+ short index = 0;
+ short usageCount = 0;
+ while (index < keysPool.length) {
+ if (usageCount >= maxOperations) {
+ KMException.throwIt(KMError.TOO_MANY_OPERATIONS);
+ }
+ if (keysPool[index] == null) {
+ keyObject = createKeyObjectInstance(algo);
+ JCSystem.beginTransaction();
+ keysPool[index] = keyObject;
+ JCSystem.commitTransaction();
+ break;
+ }
+ keyObject = (KMKeyObject) keysPool[index];
+ if (algo == keyObject.algorithm) {
+ // Check if the Object instance is not busy and free to use.
+ if (!isResourceBusy(keyObject, RESOURCE_TYPE_KEY)) {
+ break;
+ }
+ usageCount++;
+ }
+ index++;
+ }
+ return keyObject;
+ }
+
+ private byte mapAlgorithm(short alg, short secretLength) {
+ byte algo = 0;
+ switch (alg) {
+ case Cipher.ALG_AES_BLOCK_128_CBC_NOPAD:
+ case Cipher.ALG_AES_BLOCK_128_ECB_NOPAD:
+ case Cipher.ALG_AES_CTR:
+ case AEADCipher.ALG_AES_GCM:
+ if (secretLength == 16) {
+ algo = AES_128;
+ } else if (secretLength == 32) {
+ algo = AES_256;
+ } else {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ break;
+ case Cipher.ALG_DES_CBC_NOPAD:
+ case Cipher.ALG_DES_ECB_NOPAD:
+ algo = KMType.DES;
+ break;
+ case Cipher.ALG_RSA_PKCS1:
+ case KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1:
+ case KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256:
+ case Cipher.ALG_RSA_NOPAD:
+ case Signature.ALG_RSA_SHA_256_PKCS1:
+ case Signature.ALG_RSA_SHA_256_PKCS1_PSS:
+ case KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD:
+ case KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST:
+ algo = KMType.RSA;
+ break;
+ case Signature.ALG_ECDSA_SHA_256:
+ case KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST:
+ case KeyAgreement.ALG_EC_SVDP_DH_PLAIN:
+ algo = KMType.EC;
+ break;
+ case Signature.ALG_HMAC_SHA_256:
+ algo = KMType.HMAC;
+ break;
+ default:
+ KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
+ }
+ return algo;
+ }
+
+ public void initECKey(KeyPair ecKeyPair) {
+ ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate();
+ ECPublicKey pubkey = (ECPublicKey) ecKeyPair.getPublic();
+ pubkey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length);
+ pubkey.setA(secp256r1_A, (short) 0, (short) secp256r1_A.length);
+ pubkey.setB(secp256r1_B, (short) 0, (short) secp256r1_B.length);
+ pubkey.setG(secp256r1_UCG, (short) 0, (short) secp256r1_UCG.length);
+ pubkey.setK(secp256r1_H);
+ pubkey.setR(secp256r1_N, (short) 0, (short) secp256r1_N.length);
+
+ privKey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length);
+ privKey.setA(secp256r1_A, (short) 0, (short) secp256r1_A.length);
+ privKey.setB(secp256r1_B, (short) 0, (short) secp256r1_B.length);
+ privKey.setG(secp256r1_UCG, (short) 0, (short) secp256r1_UCG.length);
+ privKey.setK(secp256r1_H);
+ privKey.setR(secp256r1_N, (short) 0, (short) secp256r1_N.length);
+ }
+
+ public void powerReset() {
+ short index = 0;
+ while (index < operationPool.length) {
+ ((KMOperationImpl) operationPool[index]).abort();
+ ((KMOperationImpl) hmacSignOperationPool[index]).abort();
+ index++;
+ }
+ // release rkp operation
+ rkpOPeration.abort();
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java
new file mode 100644
index 0000000..4890ce2
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsa2048NoDigestSignature.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright(C) 2020 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import javacard.framework.Util;
+import javacard.security.CryptoException;
+import javacard.security.Key;
+import javacard.security.MessageDigest;
+import javacard.security.Signature;
+import javacardx.crypto.Cipher;
+
+/** This class provides support for RSA_NO_DIGEST signature algorithm. */
+public class KMRsa2048NoDigestSignature extends Signature {
+
+ public static final byte ALG_RSA_SIGN_NOPAD = (byte) 0x65;
+ public static final byte ALG_RSA_PKCS1_NODIGEST = (byte) 0x66;
+ private byte algorithm;
+ private Cipher inst;
+
+ public KMRsa2048NoDigestSignature(byte alg) {
+ algorithm = alg;
+ inst = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);
+ }
+
+ @Override
+ public void init(Key key, byte b) throws CryptoException {
+ inst.init(key, b);
+ }
+
+ @Override
+ public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException {
+ inst.init(key, b, bytes, i, i1);
+ }
+
+ @Override
+ public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3)
+ throws CryptoException {}
+
+ @Override
+ public byte getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public byte getMessageDigestAlgorithm() {
+ return MessageDigest.ALG_NULL;
+ }
+
+ @Override
+ public byte getCipherAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public byte getPaddingAlgorithm() {
+ return Cipher.PAD_NULL;
+ }
+
+ @Override
+ public short getLength() throws CryptoException {
+ return 0;
+ }
+
+ @Override
+ public void update(byte[] bytes, short i, short i1) throws CryptoException {
+ // HAL accumulates the data and send it at finish operation.
+ }
+
+ @Override
+ public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2)
+ throws CryptoException {
+ padData(bytes, i, i1, KMAndroidSEProvider.getInstance().tmpArray, (short) 0);
+ return inst.doFinal(
+ KMAndroidSEProvider.getInstance().tmpArray, (short) 0, (short) 256, bytes1, i2);
+ }
+
+ @Override
+ public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2)
+ throws CryptoException {
+ return 0;
+ }
+
+ @Override
+ public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3)
+ throws CryptoException {
+ // Verification is handled inside HAL
+ return false;
+ }
+
+ @Override
+ public boolean verifyPreComputedHash(
+ byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException {
+ // Verification is handled inside HAL
+ return false;
+ }
+
+ private void padData(byte[] buf, short start, short len, byte[] outBuf, short outBufStart) {
+ if (!isValidData(buf, start, len)) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ Util.arrayFillNonAtomic(outBuf, (short) outBufStart, (short) 256, (byte) 0x00);
+ if (algorithm == ALG_RSA_SIGN_NOPAD) { // add zero to right
+ } else if (algorithm == ALG_RSA_PKCS1_NODIGEST) { // 0x00||0x01||PS||0x00
+ outBuf[0] = 0x00;
+ outBuf[1] = 0x01;
+ Util.arrayFillNonAtomic(outBuf, (short) 2, (short) (256 - len - 3), (byte) 0xFF);
+ outBuf[(short) (256 - len - 1)] = 0x00;
+ } else {
+ CryptoException.throwIt(CryptoException.ILLEGAL_USE);
+ }
+ Util.arrayCopyNonAtomic(buf, start, outBuf, (short) (256 - len), len);
+ }
+
+ private boolean isValidData(byte[] buf, short start, short len) {
+ if (algorithm == ALG_RSA_SIGN_NOPAD) {
+ if (len > 256) {
+ return false;
+ }
+ } else { // ALG_RSA_PKCS1_NODIGEST
+ if (len > 245) {
+ KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java
new file mode 100644
index 0000000..bf34ea1
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright(C) 2020 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import javacard.framework.JCSystem;
+import javacard.framework.Util;
+import javacard.security.CryptoException;
+import javacard.security.Key;
+import javacard.security.MessageDigest;
+import javacardx.crypto.Cipher;
+
+/** This class has the implementation for RSA_OAEP decoding algorithm. */
+public class KMRsaOAEPEncoding extends Cipher {
+
+ public static final byte ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1 = (byte) 0x1E;
+ public static final byte ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256 = (byte) 0x1F;
+
+ final short MGF1_BUF_SIZE = 256;
+ static byte[] mgf1Buf;
+ private Cipher cipher;
+ private byte hash;
+ private byte mgf1Hash;
+ private byte algorithm;
+
+ public KMRsaOAEPEncoding(byte alg) {
+ setDigests(alg);
+ cipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);
+ algorithm = alg;
+ if (null == mgf1Buf) {
+ mgf1Buf =
+ JCSystem.makeTransientByteArray(MGF1_BUF_SIZE, JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);
+ }
+ }
+
+ private void setDigests(byte alg) {
+ switch (alg) {
+ case ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1:
+ hash = MessageDigest.ALG_SHA_256;
+ mgf1Hash = MessageDigest.ALG_SHA;
+ break;
+ case ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256:
+ hash = MessageDigest.ALG_SHA_256;
+ mgf1Hash = MessageDigest.ALG_SHA_256;
+ break;
+ default:
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ }
+ }
+
+ private short getDigestLength() {
+ switch (hash) {
+ case MessageDigest.ALG_SHA:
+ return MessageDigest.LENGTH_SHA;
+ case MessageDigest.ALG_SHA_224:
+ return MessageDigest.LENGTH_SHA_224;
+ case MessageDigest.ALG_SHA_256:
+ return MessageDigest.LENGTH_SHA_256;
+ case MessageDigest.ALG_SHA_384:
+ return MessageDigest.LENGTH_SHA_384;
+ case MessageDigest.ALG_SHA_512:
+ return MessageDigest.LENGTH_SHA_512;
+ default:
+ CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
+ }
+ return 0;
+ }
+
+ @Override
+ public void init(Key theKey, byte theMode) throws CryptoException {
+ cipher.init(theKey, theMode);
+ }
+
+ @Override
+ public void init(Key theKey, byte theMode, byte[] bArray, short bOff, short bLen)
+ throws CryptoException {
+ cipher.init(theKey, theMode, bArray, bOff, bLen);
+ }
+
+ @Override
+ public byte getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public byte getCipherAlgorithm() {
+ return 0;
+ }
+
+ @Override
+ public byte getPaddingAlgorithm() {
+ return 0;
+ }
+
+ @Override
+ public short doFinal(
+ byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset)
+ throws CryptoException {
+ short len = cipher.doFinal(inBuff, inOffset, inLength, outBuff, outOffset);
+
+ // https://tools.ietf.org/html/rfc8017#section-7.1
+ // https://www.inf.pucrs.br/~calazans/graduate/TPVLSI_I/RSA-oaep_spec.pdf
+ // RSA OAEP Encoding and Decoding Mechanism for a 2048 bit RSA Key.
+ // Msg -> RSA-OAEP-ENCODE -> RSAEncryption -> RSADecryption ->
+ // RSA-OAEP-DECODE -> Msg
+ // RSA-OAEP-ENCODE generates an output length of 255, but RSAEncryption
+ // requires and input of length 256 so we pad 0 to the left of the input
+ // message and make the length equal to 256 and pass to RSAEncryption.
+ // RSADecryption takes input length equal to 256 and generates an
+ // output of length 256. After decryption the first byte of the output
+ // should be 0(left padding we did in encryption).
+ // RSA-OAEP-DECODE takes input of length 255 so remove the left padding of 1
+ // byte.
+ if (len != 256 || outBuff[0] != 0) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ Util.arrayCopyNonAtomic(
+ outBuff, (short) (outOffset + 1), outBuff, (short) 0, (short) (len - 1));
+ return rsaOAEPDecode(outBuff, (short) 0, (short) (len - 1));
+ }
+
+ @Override
+ public short update(
+ byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset)
+ throws CryptoException {
+ return cipher.update(inBuff, inOffset, inLength, outBuff, outOffset);
+ }
+
+ private void maskGenerationFunction1(
+ byte[] input,
+ short inputOffset,
+ short inputLen,
+ short expectedOutLen,
+ byte[] outBuf,
+ short outOffset) {
+ short counter = 0;
+ MessageDigest.OneShot md = null;
+ try {
+ md = MessageDigest.OneShot.open(mgf1Hash);
+ short digestLen = md.getLength();
+
+ Util.arrayCopyNonAtomic(input, inputOffset, mgf1Buf, (short) 0, inputLen);
+ while (counter < (short) (expectedOutLen / digestLen)) {
+ I2OS(counter, mgf1Buf, (short) inputLen);
+ md.doFinal(
+ mgf1Buf,
+ (short) 0,
+ (short) (4 + inputLen),
+ outBuf,
+ (short) (outOffset + (counter * digestLen)));
+ counter++;
+ }
+
+ if ((short) (counter * digestLen) < expectedOutLen) {
+ I2OS(counter, mgf1Buf, (short) inputLen);
+ md.doFinal(
+ mgf1Buf,
+ (short) 0,
+ (short) (4 + inputLen),
+ outBuf,
+ (short) (outOffset + (counter * digestLen)));
+ }
+
+ } finally {
+ if (md != null) {
+ md.close();
+ }
+ Util.arrayFillNonAtomic(mgf1Buf, (short) 0, (short) MGF1_BUF_SIZE, (byte) 0);
+ }
+ }
+
+ // Integer to Octet String conversion.
+ private void I2OS(short i, byte[] out, short offset) {
+ Util.arrayFillNonAtomic(out, (short) offset, (short) 4, (byte) 0);
+ out[(short) (offset + 3)] = (byte) (i >>> 0);
+ out[(short) (offset + 2)] = (byte) (i >>> 8);
+ }
+
+ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, short encodedMsgLen) {
+ MessageDigest.OneShot md = null;
+ byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray;
+
+ try {
+ short hLen = getDigestLength();
+
+ if (encodedMsgLen < (short) (2 * hLen + 1)) {
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ // encodedMsg will be in the format of maskedSeed||maskedDB.
+ // maskedSeed length is hLen and maskedDB length is (encodedMsgLen - hLen)
+ // Now retrieve the seedMask by calling MGF(maskedDB, hLen). The length
+ // of the seedMask is hLen.
+ // seedMask = MGF(maskedDB, hLen)
+ maskGenerationFunction1(
+ encodedMsg,
+ (short) (encodedMsgOff + hLen),
+ (short) (encodedMsgLen - hLen),
+ hLen,
+ tmpArray,
+ (short) 0);
+
+ // Get the seed by doing XOR of (maskedSeed ^ seedMask).
+ // seed = (maskedSeed ^ seedMask)
+ for (short i = 0; i < hLen; i++) {
+ // Store the seed in encodeMsg itself.
+ encodedMsg[(short) (encodedMsgOff + i)] ^= tmpArray[i];
+ }
+
+ // Now get the dbMask by calling MGF(seed , (emLen-hLen)).
+ // dbMask = MGF(seed , (emLen-hLen)).
+ maskGenerationFunction1(
+ encodedMsg,
+ (short) encodedMsgOff,
+ hLen,
+ (short) (encodedMsgLen - hLen),
+ tmpArray,
+ (short) 0);
+
+ // Get the DB value. DB = (maskedDB ^ dbMask)
+ // DB = Hash(P)||00||01||Msg, where P is encoding parameters. (P = NULL)
+ for (short i = 0; i < (short) (encodedMsgLen - hLen); i++) {
+ // Store the DB inside encodeMsg itself.
+ encodedMsg[(short) (encodedMsgOff + i + hLen)] ^= tmpArray[i];
+ }
+
+ // Verify Hash.
+ md = MessageDigest.OneShot.open(hash);
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0);
+ md.doFinal(tmpArray, (short) 0, (short) 0, tmpArray, (short) 0);
+ if (0
+ != Util.arrayCompare(
+ encodedMsg, (short) (encodedMsgOff + hLen), tmpArray, (short) 0, hLen)) {
+ // Verification failed.
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+
+ // Find the Message block in DB.
+ // DB = Hash(P)||00||01||Msg, where P is encoding parameters. (P = NULL)
+ // The message will be located at the end of the Data block (DB).
+ // The DB block is first constructed by keeping the message at the end and
+ // to the message 0x01 byte is prepended. The hash of the
+ // encoding parameters is calculated and then copied from the
+ // starting of the block and a variable length of 0's are
+ // appended to the end of the hash till the 0x01 byte.
+ short start = (short) (encodedMsgOff + encodedMsgLen);
+ for (short i = (short) (encodedMsgOff + 2 * hLen);
+ i < (short) (encodedMsgOff + encodedMsgLen);
+ i++) {
+ if ((encodedMsg[i] != 0)) {
+ start = i;
+ break;
+ }
+ }
+ if ((start >= (short) (encodedMsgOff + encodedMsgLen)) || (encodedMsg[start] != 0x01)) {
+ // Bad Padding.
+ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
+ }
+ start++; // Message starting pos.
+ if (start < (short) (encodedMsgOff + encodedMsgLen)) {
+ // Copy the message
+ Util.arrayCopyNonAtomic(
+ encodedMsg,
+ start,
+ encodedMsg,
+ encodedMsgOff,
+ (short) (encodedMsgLen - (start - encodedMsgOff)));
+ }
+ return (short) (encodedMsgLen - (start - encodedMsgOff));
+
+ } finally {
+ if (md != null) {
+ md.close();
+ }
+ Util.arrayFillNonAtomic(tmpArray, (short) 0, KMAndroidSEProvider.TMP_ARRAY_SIZE, (byte) 0);
+ }
+ }
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java
new file mode 100644
index 0000000..9313c04
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java
@@ -0,0 +1,782 @@
+/*
+ * Copyright(C) 2020 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import org.globalplatform.upgrade.Element;
+
+/**
+ * KMSEProvider is facade to use SE specific methods. The main intention of this interface is to
+ * abstract the cipher, signature and backup and restore related functions. The instance of this
+ * interface is created by the singleton KMSEProviderImpl class for each provider. At a time there
+ * can be only one provider in the applet package.
+ */
+public interface KMSEProvider {
+
+ /**
+ * This function tells if boot signal event is supported or not.
+ *
+ * @return true if supported, false otherwise.
+ */
+ boolean isBootSignalEventSupported();
+
+ /**
+ * This function tells if the device is booted or not.
+ *
+ * @return true if device booted, false otherwise.
+ */
+ boolean isDeviceRebooted();
+
+ /**
+ * This function is supposed to be used to reset the device booted stated after set boot param is
+ * handled
+ *
+ * @param resetBootFlag is false if event has been handled
+ */
+ void clearDeviceBooted(boolean resetBootFlag);
+
+ /**
+ * Create a symmetric key instance. If the algorithm and/or keysize are not supported then it
+ * should throw a CryptoException.
+ *
+ * @param alg will be KMType.AES, KMType.DES or KMType.HMAC.
+ * @param keysize will be 128 or 256 for AES or DES. It can be 64 to 512 (multiple of 8) for HMAC.
+ * @param buf is the buffer in which key has to be returned
+ * @param startOff is the start offset.
+ * @return length of the data in the buf. This should match the keysize (in bytes).
+ */
+ short createSymmetricKey(byte alg, short keysize, byte[] buf, short startOff);
+
+ /**
+ * Create a asymmetric key pair. If the algorithms are not supported then it should throw a
+ * CryptoException. For RSA the public key exponent must always be 0x010001. The key size of RSA
+ * key pair must be 2048 bits and key size of EC key pair must be for p256 curve.
+ *
+ * @param alg will be KMType.RSA or KMType.EC.
+ * @param privKeyBuf is the buffer to return the private key exponent in case of RSA or private
+ * key in case of EC.
+ * @param privKeyStart is the start offset.
+ * @param privKeyMaxLength is the maximum length of this private key buffer.
+ * @param pubModBuf is the buffer to return the modulus in case of RSA or public key in case of
+ * EC.
+ * @param pubModStart is the start of offset.
+ * @param pubModMaxLength is the maximum length of this public key buffer.
+ * @param lengths is the actual length of the key pair - lengths[0] should be private key and
+ * lengths[1] should be public key.
+ */
+ void createAsymmetricKey(
+ byte alg,
+ byte[] privKeyBuf,
+ short privKeyStart,
+ short privKeyMaxLength,
+ byte[] pubModBuf,
+ short pubModStart,
+ short pubModMaxLength,
+ short[] lengths);
+
+ /**
+ * Initializes the trusted confirmation operation.
+ *
+ * @param computedHmacKey Instance of the computed Hmac key.
+ * @return instance of KMOperation.
+ */
+ KMOperation initTrustedConfirmationSymmetricOperation(KMKey computedHmacKey);
+
+ /**
+ * Verify that the imported key is valid. If the algorithm and/or keysize are not supported then
+ * it should throw a CryptoException.
+ *
+ * @param alg will be KMType.AES, KMType.DES or KMType.HMAC.
+ * @param keysize will be 128 or 256 for AES or DES. It can be 64 to 512 (multiple of 8) for HMAC.
+ * @param buf is the buffer that contains the symmetric key.
+ * @param startOff is the start offset.
+ * @param length of the data in the buf. This should match the keysize (in bytes).
+ * @return true if the symmetric key is supported and valid.
+ */
+ boolean importSymmetricKey(byte alg, short keysize, byte[] buf, short startOff, short length);
+
+ /**
+ * Validate that the imported asymmetric key pair is valid. For RSA the public key exponent must
+ * always be 0x010001. The key size of RSA key pair must be 2048 bits and key size of EC key pair
+ * must be for p256 curve. If the algorithms are not supported then it should throw a
+ * CryptoException.
+ *
+ * @param alg will be KMType.RSA or KMType.EC.
+ * @param privKeyBuf is the buffer that contains the private key exponent in case of RSA or
+ * private key in case of EC.
+ * @param privKeyStart is the start offset.
+ * @param privKeyLength is the length of this private key buffer.
+ * @param pubModBuf is the buffer that contains the modulus in case of RSA or public key in case
+ * of EC.
+ * @param pubModStart is the start of offset.
+ * @param pubModLength is the length of this public key buffer.
+ * @return true if the key pair is supported and valid.
+ */
+ boolean importAsymmetricKey(
+ byte alg,
+ byte[] privKeyBuf,
+ short privKeyStart,
+ short privKeyLength,
+ byte[] pubModBuf,
+ short pubModStart,
+ short pubModLength);
+
+ /**
+ * This is a oneshot operation that generates random number of desired length.
+ *
+ * @param num is the buffer in which random number is returned to the applet.
+ * @param offset is start of the buffer.
+ * @param length indicates the size of buffer and desired length of random number in bytes.
+ */
+ void newRandomNumber(byte[] num, short offset, short length);
+
+ /**
+ * This is a oneshot operation that adds the entropy to the entropy pool. This operation
+ * corresponds to addRndEntropy command. This method may ignore the added entropy value if the SE
+ * provider does not support it.
+ *
+ * @param num is the buffer in which entropy value is given.
+ * @param offset is start of the buffer.
+ * @param length length of the buffer.
+ */
+ void addRngEntropy(byte[] num, short offset, short length);
+
+ /**
+ * This is a oneshot operation that generates and returns back a true random number.
+ *
+ * @param num is the buffer in which entropy value is returned.
+ * @param offset is start of the buffer.
+ * @param length length of the buffer.
+ */
+ void getTrueRandomNumber(byte[] num, short offset, short length);
+
+ /**
+ * This is a oneshot operation that performs encryption operation using AES GCM algorithm. It
+ * throws CryptoException if algorithm is not supported or if tag length is not equal to 16 or
+ * nonce length is not equal to 12.
+ *
+ * @param aesKey is the buffer that contains 128 bit or 256 bit aes key used to encrypt.
+ * @param aesKeyStart is the start in aes key buffer.
+ * @param aesKeyLen is the length of aes key buffer in bytes (16 or 32 bytes).
+ * @param data is the buffer that contains data to encrypt.
+ * @param dataStart is the start of the data buffer.
+ * @param dataLen is the length of the data buffer.
+ * @param encData is the buffer of the output encrypted data.
+ * @param encDataStart is the start of the encrypted data buffer.
+ * @param nonce is the buffer of nonce.
+ * @param nonceStart is the start of the nonce buffer.
+ * @param nonceLen is the length of the nonce buffer.
+ * @param authData is the authentication data buffer.
+ * @param authDataStart is the start of the authentication buffer.
+ * @param authDataLen is the length of the authentication buffer.
+ * @param authTag is the buffer to output authentication tag.
+ * @param authTagStart is the start of the buffer.
+ * @param authTagLen is the length of the buffer.
+ * @return length of the encrypted data.
+ */
+ short aesGCMEncrypt(
+ byte[] aesKey,
+ short aesKeyStart,
+ short aesKeyLen,
+ byte[] data,
+ short dataStart,
+ short dataLen,
+ byte[] encData,
+ short encDataStart,
+ byte[] nonce,
+ short nonceStart,
+ short nonceLen,
+ byte[] authData,
+ short authDataStart,
+ short authDataLen,
+ byte[] authTag,
+ short authTagStart,
+ short authTagLen);
+
+ /**
+ * This is a oneshot operation that performs decryption operation using AES GCM algorithm. It
+ * throws CryptoException if algorithm is not supported.
+ *
+ * @param aesKey is the buffer that contains 128 bit or 256 bit aes key used to encrypt.
+ * @param aesKeyStart is the start in aes key buffer.
+ * @param aesKeyLen is the length of aes key buffer in bytes (16 or 32 bytes).
+ * @param encData is the buffer of the input encrypted data.
+ * @param encDataStart is the start of the encrypted data buffer.
+ * @param encDataLen is the length of the data buffer.
+ * @param data is the buffer that contains output decrypted data.
+ * @param dataStart is the start of the data buffer.
+ * @param nonce is the buffer of nonce.
+ * @param nonceStart is the start of the nonce buffer.
+ * @param nonceLen is the length of the nonce buffer.
+ * @param authData is the authentication data buffer.
+ * @param authDataStart is the start of the authentication buffer.
+ * @param authDataLen is the length of the authentication buffer.
+ * @param authTag is the buffer to output authentication tag.
+ * @param authTagStart is the start of the buffer.
+ * @param authTagLen is the length of the buffer.
+ * @return true if the authentication is valid.
+ */
+ boolean aesGCMDecrypt(
+ byte[] aesKey,
+ short aesKeyStart,
+ short aesKeyLen,
+ byte[] encData,
+ short encDataStart,
+ short encDataLen,
+ byte[] data,
+ short dataStart,
+ byte[] nonce,
+ short nonceStart,
+ short nonceLen,
+ byte[] authData,
+ short authDataStart,
+ short authDataLen,
+ byte[] authTag,
+ short authTagStart,
+ short authTagLen);
+
+ /**
+ * This is a oneshot operation that performs key derivation function using cmac kdf (CKDF) as
+ * defined in android keymaster hal definition.
+ *
+ * @param hmacKey of pre-shared key.
+ * @param label is the label to be used for ckdf.
+ * @param labelStart is the start of label.
+ * @param labelLen is the length of the label.
+ * @param context is the context to be used for ckdf.
+ * @param contextStart is the start of the context
+ * @param contextLength is the length of the context
+ * @param key is the output buffer to return the derived key
+ * @param keyStart is the start of the output buffer.
+ * @return length of the derived key buffer in bytes.
+ */
+ short cmacKDF(
+ KMKey hmacKey,
+ byte[] label,
+ short labelStart,
+ short labelLen,
+ byte[] context,
+ short contextStart,
+ short contextLength,
+ byte[] key,
+ short keyStart);
+
+ /**
+ * This is a oneshot operation that signs the data using hmac algorithm.
+ *
+ * @param keyBuf is the buffer with hmac key.
+ * @param keyStart is the start of the buffer.
+ * @param keyLength is the length of the buffer which will be in bytes from 8 to 64.
+ * @param data is the buffer containing data to be signed.
+ * @param dataStart is the start of the data.
+ * @param dataLength is the length of the data.
+ * @param signature is the output signature buffer
+ * @param signatureStart is the start of the signature
+ * @return length of the signature buffer in bytes.
+ */
+ short hmacSign(
+ byte[] keyBuf,
+ short keyStart,
+ short keyLength,
+ byte[] data,
+ short dataStart,
+ short dataLength,
+ byte[] signature,
+ short signatureStart);
+
+ /**
+ * This is a oneshot operation that signs the data using hmac algorithm.
+ *
+ * @param hmacKey is the KMHmacKey.
+ * @param data is the buffer containing data to be signed.
+ * @param dataStart is the start of the data.
+ * @param dataLength is the length of the data.
+ * @param signature is the output signature buffer
+ * @param signatureStart is the start of the signature
+ * @return length of the signature buffer in bytes.
+ */
+ short hmacSign(
+ Object hmacKey,
+ byte[] data,
+ short dataStart,
+ short dataLength,
+ byte[] signature,
+ short signatureStart);
+
+ /**
+ * This is a oneshot operation that signs the data using hmac algorithm. This is used to derive
+ * the key, which is used to encrypt the keyblob.
+ *
+ * @param masterkey of masterkey.
+ * @param data is the buffer containing data to be signed.
+ * @param dataStart is the start of the data.
+ * @param dataLength is the length of the data.
+ * @param signature is the output signature buffer
+ * @param signatureStart is the start of the signature
+ * @return length of the signature buffer in bytes.
+ */
+ short hmacKDF(
+ KMKey masterkey,
+ byte[] data,
+ short dataStart,
+ short dataLength,
+ byte[] signature,
+ short signatureStart);
+
+ /**
+ * This is a oneshot operation that verifies the signature using hmac algorithm.
+ *
+ * @param keyBuf is the buffer with hmac key.
+ * @param keyStart is the start of the buffer.
+ * @param keyLength is the length of the buffer which will be in bytes from 8 to 64.
+ * @param data is the buffer containing data.
+ * @param dataStart is the start of the data.
+ * @param dataLength is the length of the data.
+ * @param signature is the signature buffer.
+ * @param signatureStart is the start of the signature buffer.
+ * @param signatureLen is the length of the signature buffer in bytes.
+ * @return true if the signature matches.
+ */
+ boolean hmacVerify(
+ KMKey hmacKey,
+ byte[] data,
+ short dataStart,
+ short dataLength,
+ byte[] signature,
+ short signatureStart,
+ short signatureLen);
+
+ /**
+ * This is a oneshot operation that decrypts the data using RSA algorithm with oaep256 padding.
+ * The public exponent is always 0x010001. It throws CryptoException if OAEP encoding validation
+ * fails.
+ *
+ * @param privExp is the private exponent (2048 bit) buffer.
+ * @param privExpStart is the start of the private exponent buffer.
+ * @param privExpLength is the length of the private exponent buffer in bytes.
+ * @param modBuffer is the modulus (2048 bit) buffer.
+ * @param modOff is the start of the modulus buffer.
+ * @param modLength is the length of the modulus buffer in bytes.
+ * @param inputDataBuf is the buffer of the input data.
+ * @param inputDataStart is the start of the input data buffer.
+ * @param inputDataLength is the length of the input data buffer in bytes.
+ * @param outputDataBuf is the output buffer that contains the decrypted data.
+ * @param outputDataStart is the start of the output data buffer.
+ * @return length of the decrypted data.
+ */
+ short rsaDecipherOAEP256(
+ byte[] privExp,
+ short privExpStart,
+ short privExpLength,
+ byte[] modBuffer,
+ short modOff,
+ short modLength,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart);
+
+ /**
+ * Implementation of HKDF as per RFC5869 https://datatracker.ietf.org/doc/html/rfc5869#section-2
+ *
+ * @param ikm is the buffer containing input key material.
+ * @param ikmOff is the start of the input key.
+ * @param ikmLen is the length of the input key.
+ * @param salt is the buffer containing the salt.
+ * @param saltOff is the start of the salt buffer.
+ * @param saltLen is the length of the salt buffer.
+ * @param info is the buffer containing the application specific information
+ * @param infoOff is the start of the info buffer.
+ * @param infoLen is the length of the info buffer.
+ * @param out is the output buffer.
+ * @param outOff is the start of the output buffer.
+ * @param outLen is the length of the expected out buffer.
+ * @return Length of the out buffer which is outLen.
+ */
+ short hkdf(
+ byte[] ikm,
+ short ikmOff,
+ short ikmLen,
+ byte[] salt,
+ short saltOff,
+ short saltLen,
+ byte[] info,
+ short infoOff,
+ short infoLen,
+ byte[] out,
+ short outOff,
+ short outLen);
+
+ /**
+ * This function performs ECDH key agreement and generates a secret.
+ *
+ * @param privKey is the buffer containing the private key from first party.
+ * @param privKeyOff is the offset of the private key buffer.
+ * @param privKeyLen is the length of the private key buffer.
+ * @param publicKey is the buffer containing the public key from second party.
+ * @param publicKeyOff is the offset of the public key buffer.
+ * @param publicKeyLen is the length of the public key buffer.
+ * @param secret is the output buffer.
+ * @param secretOff is the offset of the output buffer.
+ * @return The length of the secret.
+ */
+ short ecdhKeyAgreement(
+ byte[] privKey,
+ short privKeyOff,
+ short privKeyLen,
+ byte[] publicKey,
+ short publicKeyOff,
+ short publicKeyLen,
+ byte[] secret,
+ short secretOff);
+
+ /**
+ * This is a oneshort operation that verifies the data using EC public key
+ *
+ * @param pubKey is the public key buffer.
+ * @param pubKeyOffset is the start of the public key buffer.
+ * @param pubKeyLen is the length of the public key.
+ * @param inputDataBuf is the buffer of the input data.
+ * @param inputDataStart is the start of the input data buffer.
+ * @param inputDataLength is the length of the input data buffer in bytes.
+ * @param signatureDataBuf is the buffer the signature input data.
+ * @param signatureDataStart is the start of the signature input data.
+ * @param signatureDataLen is the length of the signature input data.
+ * @return true if verification is successful, otherwise false.
+ */
+ boolean ecVerify256(
+ byte[] pubKey,
+ short pubKeyOffset,
+ short pubKeyLen,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] signatureDataBuf,
+ short signatureDataStart,
+ short signatureDataLen);
+
+ /**
+ * This is a oneshot operation that signs the data using device unique key.
+ *
+ * @param ecPrivKey instance of KMECDeviceUniqueKey to sign the input data.
+ * @param inputDataBuf is the buffer of the input data.
+ * @param inputDataStart is the start of the input data buffer.
+ * @param inputDataLength is the length of the input data buffer in bytes.
+ * @param outputDataBuf is the output buffer that contains the signature.
+ * @param outputDataStart is the start of the output data buffer.
+ * @return length of the decrypted data.
+ */
+ short signWithDeviceUniqueKey(
+ KMKey deviceUniqueKey,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart);
+
+ short ecSign256(
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart);
+
+ short rsaSign256Pkcs1(
+ byte[] secret,
+ short secretStart,
+ short secretLength,
+ byte[] modBuf,
+ short modStart,
+ short modLength,
+ byte[] inputDataBuf,
+ short inputDataStart,
+ short inputDataLength,
+ byte[] outputDataBuf,
+ short outputDataStart);
+
+ /**
+ * This creates a persistent operation for signing, verify, encryption and decryption using HMAC,
+ * AES and DES algorithms when keymaster hal's beginOperation function is executed. The
+ * KMOperation instance can be reclaimed by the seProvider when KMOperation is finished or
+ * aborted. It throws CryptoException if algorithm is not supported.
+ *
+ * @param purpose is KMType.ENCRYPT or KMType.DECRYPT for AES and DES algorithm. It will be
+ * KMType.SIGN and KMType.VERIFY for HMAC algorithm
+ * @param alg is KMType.HMAC, KMType.AES or KMType.DES.
+ * @param digest is KMType.SHA2_256 in case of HMAC else it will be KMType.DIGEST_NONE.
+ * @param padding is KMType.PADDING_NONE or KMType.PKCS7 (in case of AES and DES).
+ * @param blockMode is KMType.CTR, KMType.GCM. KMType.CBC or KMType.ECB for AES or DES else it is
+ * 0.
+ * @param keyBuf is aes, des or hmac key buffer.
+ * @param keyStart is the start of the key buffer.
+ * @param keyLength is the length of the key buffer.
+ * @param ivBuf is the iv buffer (in case on AES and DES algorithm without ECB mode)
+ * @param ivStart is the start of the iv buffer.
+ * @param ivLength is the length of the iv buffer. It will be zero in case of HMAC and AES/DES
+ * with ECB mode.
+ * @param macLength is the mac length in case of signing operation for hmac algorithm.
+ * @return KMOperation instance.
+ */
+ KMOperation initSymmetricOperation(
+ byte purpose,
+ byte alg,
+ byte digest,
+ byte padding,
+ byte blockMode,
+ byte[] keyBuf,
+ short keyStart,
+ short keyLength,
+ byte[] ivBuf,
+ short ivStart,
+ short ivLength,
+ short macLength);
+
+ /**
+ * This creates a persistent operation for signing, verify, encryption and decryption using HMAC,
+ * AES and DES algorithms when keymaster hal's beginOperation function is executed. The
+ * KMOperation instance can be reclaimed by the seProvider when KMOperation is finished or
+ * aborted. It throws CryptoException if algorithm is not supported.
+ *
+ * @param purpose is KMType.ENCRYPT or KMType.DECRYPT for AES and DES algorithm. It will be
+ * KMType.SIGN and KMType.VERIFY for HMAC algorithm
+ * @param alg is KMType.HMAC, KMType.AES or KMType.DES.
+ * @param digest is KMType.SHA2_256 in case of HMAC else it will be KMType.DIGEST_NONE.
+ * @param padding is KMType.PADDING_NONE or KMType.PKCS7 (in case of AES and DES).
+ * @param blockMode is KMType.CTR, KMType.GCM. KMType.CBC or KMType.ECB for AES or DES else it is
+ * 0.
+ * @param key is a key object.
+ * @param interfaceType defines the type of key in the key object.
+ * @param ivBuf is the iv buffer (in case on AES and DES algorithm without ECB mode)
+ * @param ivStart is the start of the iv buffer.
+ * @param ivLength is the length of the iv buffer. It will be zero in case of HMAC and AES/DES
+ * with ECB mode.
+ * @param macLength is the mac length in case of signing operation for hmac algorithm.
+ * @param oneShot if true, creates oneshot operation.
+ * @return KMOperation instance.
+ */
+ KMOperation initSymmetricOperation(
+ byte purpose,
+ byte alg,
+ byte digest,
+ byte padding,
+ byte blockMode,
+ Object key,
+ byte interfaceType,
+ byte[] ivBuf,
+ short ivStart,
+ short ivLength,
+ short macLength,
+ boolean oneShot);
+
+ /**
+ * This function creates an Operation instance only for RKP module.
+ *
+ * @param purpose is KMType.ENCRYPT or KMType.DECRYPT for AES and DES algorithm. It will be
+ * KMType.SIGN and KMType.VERIFY for HMAC algorithm
+ * @param alg is KMType.HMAC, KMType.AES or KMType.DES.
+ * @param digest is KMType.SHA2_256 in case of HMAC else it will be KMType.DIGEST_NONE.
+ * @param padding is KMType.PADDING_NONE or KMType.PKCS7 (in case of AES and DES).
+ * @param blockMode is KMType.CTR, KMType.GCM. KMType.CBC or KMType.ECB for AES or DES else it is
+ * 0.
+ * @param keyBuf is aes, des or hmac key buffer.
+ * @param keyStart is the start of the key buffer.
+ * @param keyLength is the length of the key buffer.
+ * @param ivBuf is the iv buffer (in case on AES and DES algorithm without ECB mode)
+ * @param ivStart is the start of the iv buffer.
+ * @param ivLength is the length of the iv buffer. It will be zero in case of HMAC and AES/DES
+ * with ECB mode.
+ * @param macLength is the mac length in case of signing operation for hmac algorithm.
+ * @return KMOperation instance.
+ */
+ KMOperation getRkpOperation(
+ byte purpose,
+ byte alg,
+ byte digest,
+ byte padding,
+ byte blockMode,
+ byte[] keyBuf,
+ short keyStart,
+ short keyLength,
+ byte[] ivBuf,
+ short ivStart,
+ short ivLength,
+ short macLength);
+
+ /**
+ * This creates a persistent operation for signing, verify, encryption and decryption using RSA
+ * and EC algorithms when keymaster hal's beginOperation function is executed. For RSA the public
+ * exponent is always 0x0100101. For EC the curve is always p256. The KMOperation instance can be
+ * reclaimed by the seProvider when KMOperation is finished or aborted. It throws CryptoException
+ * if algorithm is not supported.
+ *
+ * @param purpose is KMType.ENCRYPT or KMType.DECRYPT for RSA. It will be * KMType.SIGN and
+ * KMType.VERIFY for RSA and EC algorithms.
+ * @param alg is KMType.RSA or KMType.EC algorithms.
+ * @param padding is KMType.PADDING_NONE or KMType.RSA_OAEP, KMType.RSA_PKCS1_1_5_ENCRYPT,
+ * KMType.RSA_PKCS1_1_5_SIGN or KMType.RSA_PSS.
+ * @param digest is KMType.DIGEST_NONE or KMType.SHA2_256.
+ * @param mgfDigest is the MGF digest.
+ * @param privKeyBuf is the private key in case of EC or private key exponent is case of RSA.
+ * @param privKeyStart is the start of the private key.
+ * @param privKeyLength is the length of the private key.
+ * @param pubModBuf is the modulus (in case of RSA) or public key (in case of EC).
+ * @param pubModStart is the start of the modulus.
+ * @param pubModLength is the length of the modulus.
+ * @return KMOperation instance that can be executed.
+ */
+ KMOperation initAsymmetricOperation(
+ byte purpose,
+ byte alg,
+ byte padding,
+ byte digest,
+ byte mgfDigest,
+ byte[] privKeyBuf,
+ short privKeyStart,
+ short privKeyLength,
+ byte[] pubModBuf,
+ short pubModStart,
+ short pubModLength);
+
+ /**
+ * This function tells if applet is upgrading or not.
+ *
+ * @return true if upgrading, otherwise false.
+ */
+ boolean isUpgrading();
+
+ /**
+ * This function generates an AES Key of keySizeBits, which is used as an master key. This
+ * generated key is maintained by the SEProvider. This function should be called only once at the
+ * time of installation.
+ *
+ * @param instance of the masterkey.
+ * @param keySizeBits key size in bits.
+ * @return An instance of KMMasterKey.
+ */
+ KMKey createMasterKey(KMKey masterKey, short keySizeBits);
+
+ /**
+ * This function creates an HMACKey and initializes the key with the provided input key data.
+ *
+ * @param keyData buffer containing the key data.
+ * @param offset start of the buffer.
+ * @param length length of the buffer.
+ * @return An instance of the KMComputedHmacKey.
+ */
+ KMKey createComputedHmacKey(KMKey computedHmacKey, byte[] keyData, short offset, short length);
+
+ /** Returns true if factory provisioned attestation key is supported. */
+ boolean isAttestationKeyProvisioned();
+
+ /**
+ * Returns algorithm type of the attestation key. It can be KMType.EC or KMType.RSA if the
+ * attestation key is provisioned in the factory.
+ */
+ short getAttestationKeyAlgorithm();
+
+ /**
+ * Creates an ECKey instance and sets the public and private keys to it.
+ *
+ * @param testMode to indicate if current execution is for test or production.
+ * @param pubKey buffer containing the public key.
+ * @param pubKeyOff public key buffer start offset.
+ * @param pubKeyLen public key buffer length.
+ * @param privKey buffer containing the private key.
+ * @param privKeyOff private key buffer start offset.
+ * @param privKeyLen private key buffer length.
+ * @return instance of KMDeviceUniqueKey.
+ */
+ KMKey createRkpDeviceUniqueKeyPair(
+ KMKey key,
+ byte[] pubKey,
+ short pubKeyOff,
+ short pubKeyLen,
+ byte[] privKey,
+ short privKeyOff,
+ short privKeyLen);
+
+ /**
+ * This is a one-shot operation the does digest of the input mesage.
+ *
+ * @param inBuff input buffer to be digested.
+ * @param inOffset start offset of the input buffer.
+ * @param inLength length of the input buffer.
+ * @param outBuff is the output buffer that contains the digested data.
+ * @param outOffset start offset of the digested output buffer.
+ * @return length of the digested data.
+ */
+ short messageDigest256(
+ byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset);
+
+ /**
+ * This function generates a HMAC key from the provided key buffers.
+ *
+ * @param presharedKey instance of the presharedkey.
+ * @param key buffer containing the key data.
+ * @param offset start offset of the buffer.
+ * @param length is the length of the key.
+ * @return instance of KMPresharedKey.
+ */
+ KMKey createPreSharedKey(KMKey presharedKey, byte[] key, short offset, short length);
+
+ /**
+ * This function saves the key objects while upgrade.
+ *
+ * @param element instance of the Element class where the objects to be stored.
+ * @param interfaceType the type interface of the parent object.
+ * @param object instance of the object to be saved.
+ */
+ void onSave(Element element, byte interfaceType, Object object);
+
+ /**
+ * This function restores the the object from element instance.
+ *
+ * @param element instance of the Element class.
+ * @return restored object.
+ */
+ Object onRestore(Element element);
+
+ /**
+ * This function returns the count of the primitive bytes required to be stored by the
+ * implementation of the interface type.
+ *
+ * @param interfaceType type interface of the parent object.
+ * @return count of the primitive bytes.
+ */
+ short getBackupPrimitiveByteCount(byte interfaceType);
+
+ /**
+ * This function returns the object count required to be stored by the implementation of the
+ * interface type.
+ *
+ * @param interfaceType type interface of the parent object.
+ * @return count of the objects.
+ */
+ short getBackupObjectCount(byte interfaceType);
+
+ /**
+ * This function creates an HMACKey and initializes the key with the provided input key data.
+ *
+ * @param keyData buffer containing the key data.
+ * @param offset start of the buffer.
+ * @param length length of the buffer.
+ * @return An instance of the KMRkpMacKey.
+ */
+ KMKey createRkpMacKey(KMKey createComputedHmacKey, byte[] keyData, short offset, short length);
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMType.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMType.java
new file mode 100644
index 0000000..82cbe26
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMType.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright(C) 2020 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 com.android.javacard.seprovider;
+
+/**
+ * This class declares all types, tag types, and tag keys. It also establishes basic structure of
+ * any KMType i.e. struct{byte type, short length, value} where value can any of the KMType. Also,
+ * KMType refers to transient memory heap in the repository. Finally KMType's subtypes are singleton
+ * prototype objects which just cast the structure over contiguous memory buffer.
+ */
+public abstract class KMType {
+
+ public static final short INVALID_VALUE = (short) 0x8000;
+
+ // Algorithm Enum Tag key and values
+ public static final short ALGORITHM = 0x0002;
+ public static final byte RSA = 0x01;
+ public static final byte DES = 0x21;
+ public static final byte EC = 0x03;
+ public static final byte AES = 0x20;
+ public static final byte HMAC = (byte) 0x80;
+
+ // EcCurve Enum Tag key and values.
+ public static final short ECCURVE = 0x000A;
+ public static final byte P_224 = 0x00;
+ public static final byte P_256 = 0x01;
+ public static final byte P_384 = 0x02;
+ public static final byte P_521 = 0x03;
+
+ // Purpose
+ public static final short PURPOSE = 0x0001;
+ public static final byte ENCRYPT = 0x00;
+ public static final byte DECRYPT = 0x01;
+ public static final byte SIGN = 0x02;
+ public static final byte VERIFY = 0x03;
+ public static final byte DERIVE_KEY = 0x04;
+ public static final byte WRAP_KEY = 0x05;
+ public static final byte AGREE_KEY = 0x06;
+ public static final byte ATTEST_KEY = (byte) 0x07;
+ // Block mode
+ public static final short BLOCK_MODE = 0x0004;
+ public static final byte ECB = 0x01;
+ public static final byte CBC = 0x02;
+ public static final byte CTR = 0x03;
+ public static final byte GCM = 0x20;
+
+ // Digest
+ public static final short DIGEST = 0x0005;
+ public static final byte DIGEST_NONE = 0x00;
+ public static final byte MD5 = 0x01;
+ public static final byte SHA1 = 0x02;
+ public static final byte SHA2_224 = 0x03;
+ public static final byte SHA2_256 = 0x04;
+ public static final byte SHA2_384 = 0x05;
+ public static final byte SHA2_512 = 0x06;
+
+ // Padding mode
+ public static final short PADDING = 0x0006;
+ public static final byte PADDING_NONE = 0x01;
+ public static final byte RSA_OAEP = 0x02;
+ public static final byte RSA_PSS = 0x03;
+ public static final byte RSA_PKCS1_1_5_ENCRYPT = 0x04;
+ public static final byte RSA_PKCS1_1_5_SIGN = 0x05;
+ public static final byte PKCS7 = 0x40;
+}
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java
new file mode 100644
index 0000000..420b2c7
--- /dev/null
+++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMUpgradable.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright(C) 2020 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" (short)0IS,
+ * 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 com.android.javacard.seprovider;
+
+import org.globalplatform.upgrade.Element;
+
+/** This interface helps in storing and restoring the applet data during the applet upgrades. */
+public interface KMUpgradable {
+
+ void onSave(Element ele);
+
+ void onRestore(Element ele, short oldVersion, short currentVersion);
+
+ short getBackupPrimitiveByteCount();
+
+ short getBackupObjectCount();
+}