diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java index b706d5ed..3fb36539 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java @@ -23,4 +23,5 @@ public class KMConfigurations { // If the size of the attestation ids is known and lesser than 64 // then reduce the size here. It reduces the heap memory usage. public static final byte MAX_ATTESTATION_IDS_SIZE = 64; + public static final short MAX_SUBJECT_DER_LEN = 1095; } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index e5ede6e9..67b02708 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -80,6 +80,7 @@ public class KMAndroidSEProvider implements KMSEProvider { private KMRsaOAEPEncoding rsaOaepDecipher; private KMPoolManager poolMgr; + private KMOperationImpl globalOperation; // Entropy private RandomData rng; @@ -112,6 +113,8 @@ public KMAndroidSEProvider() { 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); @@ -131,7 +134,7 @@ void initStatics() { } public void clean() { - Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); + Util.arrayFillNonAtomic(tmpArray, (short) 0, TMP_ARRAY_SIZE, (byte) 0); } public AESKey createAESKey(short keysize) { @@ -352,7 +355,9 @@ public short aesGCMEncrypt(AESKey key, false); } aesGcmCipher.init(key, Cipher.MODE_ENCRYPT, nonce, nonceStart, nonceLen); - aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); + if (authDataLen != 0) { + aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); + } short ciphLen = aesGcmCipher.doFinal(secret, secretStart, secretLen, encSecret, encSecretStart); aesGcmCipher.retrieveTag(authTag, authTagStart, authTagLen); @@ -398,7 +403,9 @@ public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart, boolean verification = false; AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen); aesGcmCipher.init(key, Cipher.MODE_DECRYPT, nonce, nonceStart, nonceLen); - aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); + if (authDataLen != 0) { + aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); + } // encrypt the secret aesGcmCipher.doFinal(encSecret, encSecretStart, encSecretLen, secret, secretStart); @@ -479,9 +486,8 @@ public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, try { KMAESKey aesKey = (KMAESKey) masterkey; short keyLen = (short) (aesKey.getKeySizeBits() / 8); - byte[] keyData = new byte[keyLen]; - aesKey.getKey(keyData, (short) 0); - return hmacSign(keyData, (short) 0, keyLen, data, dataStart, dataLength, + aesKey.getKey(tmpArray, (short) 0); + return hmacSign(tmpArray, (short) 0, keyLen, data, dataStart, dataLength, signature, signatureStart); } finally { clean(); @@ -697,6 +703,43 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, 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.getKeySizeBits() / 8); + 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(KMComputedHmacKey computedHmacKey) { KMHmacKey key = (KMHmacKey) computedHmacKey; diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java index d77f2167..2a99f81b 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java @@ -562,6 +562,43 @@ KMOperation initSymmetricOperation( 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. * diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java index 35c458bb..7f423f00 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java @@ -359,10 +359,12 @@ public short aesGCMEncrypt( e.printStackTrace(); CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); } - // Create auth data - byte[] aad = new byte[authDataLen]; - Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, authDataLen); - cipher.updateAAD(aad); + if (authDataLen != 0) { + // Create auth data + byte[] aad = new byte[authDataLen]; + Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, authDataLen); + cipher.updateAAD(aad); + } // Encrypt secret short len = 0; byte[] outputBuf = new byte[cipher.getOutputSize(secretLen)]; @@ -444,11 +446,13 @@ public boolean aesGCMDecrypt( e.printStackTrace(); CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); } - // Create auth data - byte[] aad = new byte[authDataLen]; - Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, + if (authDataLen != 0) { + // Create auth data + byte[] aad = new byte[authDataLen]; + Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, authDataLen); - cipher.updateAAD(aad); + cipher.updateAAD(aad); + } // Append the auth tag at the end of data byte[] inputBuf = new byte[(short) (encSecretLen + authTagLen)]; Util.arrayCopyNonAtomic(encSecret, encSecretStart, inputBuf, (short) 0, @@ -666,6 +670,39 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, byte digest, b return null; } + @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) { + KMOperationImpl operation = null; + short keyLen = 0; + byte[] keyData = null; + + switch (interfaceType) { + case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY: + KMAESKey aesKey = (KMAESKey) key; + keyLen = (short) (aesKey.getKeySizeBits() / 8); + keyData = new byte[keyLen]; + aesKey.getKey(keyData, (short) 0); + break; + + default: + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + + switch (alg){ + case KMType.HMAC: + Signature signerVerifier = createHmacSignerVerifier(purpose, digest, keyData, (short)0, + keyLen); + operation = new KMOperationImpl(signerVerifier); + break; + + default: + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + return operation; + } + @Override public KMOperation initTrustedConfirmationSymmetricOperation(KMComputedHmacKey computedHmacKey) { KMOperationImpl opr = null; diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java index d77f2167..c758889f 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java @@ -562,6 +562,43 @@ KMOperation initSymmetricOperation( 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. * diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index 40bcbc2c..0b6038cd 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -77,8 +77,8 @@ public class KMKeyParameters extends KMType { KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID, KMType.UINT_TAG, KMType.AUTH_TIMEOUT, KMType.ENUM_TAG, KMType.USER_AUTH_TYPE, - KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, - KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, + KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, + KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, }; private static final short[] invalidTagsArr = { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 79708430..c9347864 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -17,8 +17,10 @@ package com.android.javacard.keymaster; import com.android.javacard.seprovider.KMAttestationCert; +import com.android.javacard.seprovider.KMDataStoreConstants; import com.android.javacard.seprovider.KMDeviceUniqueKeyPair; import com.android.javacard.seprovider.KMException; +import com.android.javacard.seprovider.KMOperation; import com.android.javacard.seprovider.KMSEProvider; import javacard.framework.APDU; import javacard.framework.Applet; @@ -28,6 +30,7 @@ import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.CryptoException; +import javacard.security.Signature; import javacardx.apdu.ExtendedLength; /** @@ -247,12 +250,12 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // the KeyBlobs if it is changed. please increment this // version number whenever you change anything related to // KeyBlob (structure, encryption algorithm etc). - public static final short KEYBLOB_CURRENT_VERSION = 2; + public static final short KEYBLOB_CURRENT_VERSION = 3; // KeyBlob Verion 1 constant. public static final short KEYBLOB_VERSION_1 = 1; // KeyBlob array size constants. - public static final byte SYM_KEY_BLOB_SIZE_V2 = 6; - public static final byte ASYM_KEY_BLOB_SIZE_V2 = 7; + public static final byte SYM_KEY_BLOB_SIZE_V2_V3 = 6; + public static final byte ASYM_KEY_BLOB_SIZE_V2_V3 = 7; public static final byte SYM_KEY_BLOB_SIZE_V1 = 5; public static final byte ASYM_KEY_BLOB_SIZE_V1 = 6; public static final byte SYM_KEY_BLOB_SIZE_V0 = 4; @@ -895,7 +898,8 @@ private short createKeyBlobExp(short version) { KMArray.cast(keyBlob).add((short) 5, byteBlobExp);// PubKey break; case (short) 2: - keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2); + case (short) 3: + keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2_V3); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_VERSION_OFFSET, KMInteger.exp()); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_SECRET, byteBlobExp); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, byteBlobExp); @@ -914,10 +918,10 @@ private static short createKeyBlobInstance(byte keyType) { short arrayLen = 0; switch (keyType) { case ASYM_KEY_TYPE: - arrayLen = ASYM_KEY_BLOB_SIZE_V2; + arrayLen = ASYM_KEY_BLOB_SIZE_V2_V3; break; case SYM_KEY_TYPE: - arrayLen = SYM_KEY_BLOB_SIZE_V2; + arrayLen = SYM_KEY_BLOB_SIZE_V2_V3; break; default: KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); @@ -1140,11 +1144,11 @@ private void processUpgradeKeyCmd(APDU apdu) { byte keyType = getKeyType(data[HW_PARAMETERS]); switch (keyType) { case ASYM_KEY_TYPE: - data[KEY_BLOB] = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2); + data[KEY_BLOB] = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2_V3); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]); break; case SYM_KEY_TYPE: - data[KEY_BLOB] = KMArray.instance(SYM_KEY_BLOB_SIZE_V2); + data[KEY_BLOB] = KMArray.instance(SYM_KEY_BLOB_SIZE_V2_V3); break; default: KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); @@ -2630,7 +2634,7 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) KMError.INVALID_KEY_BLOB); //Validate early boot - //VTS expects error code EARLY_BOOT_ONLY during begin operation if eary boot ended tag is present + //VTS expects error code EARLY_BOOT_ONLY during begin operation if early boot ended tag is present if (kmDataStore.getEarlyBootEndedStatus()) { KMTag.assertAbsence(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, KMError.EARLY_BOOT_ENDED); @@ -3889,8 +3893,6 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { data[KEY_BLOB_VERSION_DATA_OFFSET] = KMInteger.uint_16(KEYBLOB_CURRENT_VERSION); // create custom tags data[CUSTOM_TAGS] = KMKeyParameters.makeCustomTags(data[HW_PARAMETERS], scratchPad); - // make authorization data - makeAuthData(KEYBLOB_CURRENT_VERSION, scratchPad); // encrypt the secret and cryptographically attach that to authorization data encryptSecret(scratchPad); // create key blob array @@ -3993,6 +3995,7 @@ private void readKeyBlobParams(short version, short parsedKeyBlob) { } break; case (short) 2: + case (short) 3: data[SECRET] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_SECRET); data[NONCE]= KMArray.cast(parsedKeyBlob).get(KEY_BLOB_NONCE); data[AUTH_TAG] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_AUTH_TAG); @@ -4002,7 +4005,7 @@ private void readKeyBlobParams(short version, short parsedKeyBlob) { data[CUSTOM_TAGS] = KMArray.cast(parsedKeyBlob).get( KEY_BLOB_CUSTOM_TAGS); data[PUB_KEY] = KMType.INVALID_VALUE; - if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V2) { + if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V2_V3) { data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_PUB_KEY); } break; @@ -4026,7 +4029,8 @@ private void decodeKeyBlob(short version, short keyBlob) { minArraySize = SYM_KEY_BLOB_SIZE_V1; break; case 2: - minArraySize = SYM_KEY_BLOB_SIZE_V2; + case 3: + minArraySize = SYM_KEY_BLOB_SIZE_V2_V3; break; default: KMException.throwIt(KMError.INVALID_KEY_BLOB); @@ -4045,10 +4049,8 @@ private void processDecryptSecret(short version, short appId, short appData, byt data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced(data[SB_PARAMETERS], data[TEE_PARAMETERS]); data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(appId, appData, data[ROT], scratchPad); - // make auth data - makeAuthData(version, scratchPad); // Decrypt Secret and verify auth tag - decryptSecret(scratchPad); + decryptSecret(scratchPad, version); short keyBlobSecretOff = 0; switch(version) { case 0: @@ -4075,6 +4077,7 @@ private void processDecryptSecret(short version, short appId, short appData, byt keyBlobSecretOff = (short) 1; break; case 2: + case 3: // V2 KeyBlob // KEY_BLOB = [ // VERSION, @@ -4130,10 +4133,31 @@ public static short readROT(byte[] scratchPad, short version) { return KMByteBlob.instance(scratchPad, (short) 0, len); } - private void decryptSecret(byte[] scratchPad) { + private void decryptSecret(byte[] scratchPad, short version) { // derive master key - stored in derivedKey - short len = deriveKey(scratchPad); - if (!seProvider.aesGCMDecrypt( + short len; + short authDataOff = 0; + short authDataLen = 0; + byte[] authDataBuff = null; + switch (version) { + case 3: + len = deriveKey(scratchPad); + break; + + case 2: + case 1: + case 0: + makeAuthData(version, scratchPad); + len = deriveKeyForOldKeyBlobs(scratchPad); + authDataBuff = repository.getHeap(); + authDataOff = data[AUTH_DATA]; + authDataLen = data[AUTH_DATA_LENGTH]; + break; + default: + KMException.throwIt(KMError.INVALID_KEY_BLOB); + + } + if (!seProvider.aesGCMDecrypt( KMByteBlob.cast(data[DERIVED_KEY]).getBuffer(), KMByteBlob.cast(data[DERIVED_KEY]).getStartOff(), KMByteBlob.cast(data[DERIVED_KEY]).length(), @@ -4144,7 +4168,7 @@ private void decryptSecret(byte[] scratchPad) { KMByteBlob.cast(data[NONCE]).getBuffer(), KMByteBlob.cast(data[NONCE]).getStartOff(), KMByteBlob.cast(data[NONCE]).length(), - repository.getHeap(), data[AUTH_DATA], data[AUTH_DATA_LENGTH], + authDataBuff, authDataOff, authDataLen, KMByteBlob.cast(data[AUTH_TAG]).getBuffer(), KMByteBlob.cast(data[AUTH_TAG]).getStartOff(), KMByteBlob.cast(data[AUTH_TAG]).length())) { @@ -4165,7 +4189,7 @@ private static void encryptSecret(byte[] scratchPad) { KMByteBlob.cast(data[NONCE]).length()); // derive master key - stored in derivedKey short len = deriveKey(scratchPad); - len = seProvider.aesGCMEncrypt( + len = seProvider.aesGCMEncrypt( KMByteBlob.cast(data[DERIVED_KEY]).getBuffer(), KMByteBlob.cast(data[DERIVED_KEY]).getStartOff(), KMByteBlob.cast(data[DERIVED_KEY]).length(), @@ -4177,9 +4201,9 @@ private static void encryptSecret(byte[] scratchPad) { KMByteBlob.cast(data[NONCE]).getBuffer(), KMByteBlob.cast(data[NONCE]).getStartOff(), KMByteBlob.cast(data[NONCE]).length(), - repository.getHeap(), - data[AUTH_DATA], - data[AUTH_DATA_LENGTH], + null, + (short)0, + (short)0, KMByteBlob.cast(data[AUTH_TAG]).getBuffer(), KMByteBlob.cast(data[AUTH_TAG]).getStartOff(), KMByteBlob.cast(data[AUTH_TAG]).length()); @@ -4275,7 +4299,7 @@ private static void makeAuthData(short version, byte[] scratchPad) { data[AUTH_DATA_LENGTH] = len; } - private static short deriveKey(byte[] scratchPad) { + private static short deriveKeyForOldKeyBlobs(byte[] scratchPad) { // KeyDerivation: // 1. Do HMAC Sign, Auth data. // 2. HMAC Sign generates an output of 32 bytes length. @@ -4296,6 +4320,77 @@ private static short deriveKey(byte[] scratchPad) { return len; } + private static short deriveKey(byte[] scratchPad) { + // For KeyBlob V3: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, CUSTOM_TAGS, VERSION and PUB_KEY. + short index = 0; + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 10, (byte) 0); + byte keyType = getKeyType(data[HW_PARAMETERS]); + // Copy the relevant parameters in the scratchPad in the order + // 1. HW_PARAMETERS + // 2. HIDDEN_PARAMETERS + // 3. CUSTOM_TAGS + // 3. VERSION ( Only Version >= 1) + // 4. PUB_KEY ( Only for Asymmetric Keys) + short numParams = 4; + Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals()); + Util.setShort(scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals()); + Util.setShort(scratchPad, (short) 4, KMKeyParameters.cast(data[CUSTOM_TAGS]).getVals()); + Util.setShort(scratchPad, (short) 6, data[KEY_BLOB_VERSION_DATA_OFFSET]); + // For Asymmetric Keys include the PUB_KEY. + if (keyType == ASYM_KEY_TYPE) { + numParams = 5; + Util.setShort(scratchPad, (short) 8, data[PUB_KEY]); + } + short prevReclaimIndex = repository.getHeapReclaimIndex(); + short authIndex = repository.allocReclaimableMemory(MAX_AUTH_DATA_SIZE); + Util.arrayFillNonAtomic(repository.getHeap(), authIndex, MAX_AUTH_DATA_SIZE, (byte) 0); + short len = 0; + KMOperation operation = null; + try { + operation = seProvider.initSymmetricOperation( + KMType.SIGN, + KMType.HMAC, + KMType.SHA2_256, + KMType.PADDING_NONE, + (byte)KMType.INVALID_VALUE, + (Object)kmDataStore.getMasterKey(), + KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY, + (byte[])null, + (short)0, + (short)0, + (short)0, false); + + byte arrayHeader = (byte) 0x80; + arrayHeader |= (byte) numParams; + ((byte[])repository.getHeap())[authIndex] = arrayHeader; + operation.update(repository.getHeap(), authIndex, (short) 1); + + while (index < numParams) { + short tag = Util.getShort(scratchPad, (short) (index * 2)); + len = encoder.encode(tag, repository.getHeap(), (short) authIndex, prevReclaimIndex); + operation.update(repository.getHeap(), authIndex, len); + index++; + } + repository.reclaimMemory(MAX_AUTH_DATA_SIZE); + // KeyDerivation: + // 1. Do HMAC Sign, Auth data. + // 2. HMAC Sign generates an output of 32 bytes length. + // Consume only first 16 bytes as derived key. + // Hmac sign. + len = operation.sign(scratchPad, (short)0, (short)0, scratchPad, (short)0); + } finally { + if (operation != null) { + operation.abort(); + } + } + if (len < 16) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + len = 16; + data[DERIVED_KEY] = KMByteBlob.instance(scratchPad, (short)0, len); + return len; + } + public static void sendResponse(APDU apdu, short err) { short resp = KMArray.instance((short)1); err = KMError.translate(err);