blob: c74081ea1fcec5b14dc621b0bbe52acc9177e4c0 [file] [log] [blame]
/*
* 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,
KMKey keyPair,
byte[] ivBuf,
short ivStart,
short ivLength,
short macLength) {
KMOperation opr = null;
switch (alg) {
case KMType.EC:
// get EC private key buffer
ECPrivateKey ecPrivKey =
(ECPrivateKey) ((KMECDeviceUniqueKeyPair) keyPair).ecKeyPair.getPrivate();
short ecPrivKeyLen = ecPrivKey.getS(tmpArray, (short) 0);
opr = createEcSigner(digest, tmpArray, (short) 0, ecPrivKeyLen, 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, boolean isRkp) {
KMOperation operation = null;
byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest);
if (isRkp) {
operation =
poolMgr.getRKpOperation(
KMType.SIGN,
Signature.ALG_ECDSA_SHA_256,
KMType.EC,
KMType.INVALID_VALUE,
KMType.INVALID_VALUE,
KMType.INVALID_VALUE);
} else {
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, false);
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
}
}