Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,23 @@ public class KMAndroidSEProvider implements KMSEProvider {
private static final short CERT_EXPIRY_OFFSET =
(short) (CERT_ISSUER_OFFSET + KMConfigurations.CERT_ISSUER_MAX_SIZE);

public static final short MAX_OPERATION_INSTANCES = 4;
private static final short 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;

final byte[] KEY_ALGS = {
AES_128,
AES_256,
KMType.DES,
KMType.RSA,
KMType.EC,
KMType.HMAC};

private static final byte[] CIPHER_ALGS = {
Cipher.ALG_AES_BLOCK_128_CBC_NOPAD,
Cipher.ALG_AES_BLOCK_128_ECB_NOPAD,
Expand Down Expand Up @@ -173,8 +190,11 @@ public class KMAndroidSEProvider implements KMSEProvider {
private Object[] sigPool;
// KMOperationImpl pool
private Object[] operationPool;
// Hmac signer pool which is used to support TRUSTED_CONFIRMATION_REQUIRED tag.
private Object[] hmacSignOperationPool;

//Hmac signer pool which is used to support TRUSTED_CONFIRMATION_REQUIRED tag.
private Object[] hmacSignOperationPool;

private Object[] keysPool;

private Signature kdf;

Expand Down Expand Up @@ -216,16 +236,19 @@ public KMAndroidSEProvider() {
cipherPool = new Object[(short) (CIPHER_ALGS.length * 4)];
// Extra 4 algorithms are used to support TRUSTED_CONFIRMATION_REQUIRED feature.
sigPool = new Object[(short) ((SIG_ALGS.length * 4) + 4)];
operationPool = new Object[4];

//maintain seperate operation pool for hmac signer used to support trusted confirmation
hmacSignOperationPool = new Object[4];
operationPool = new Object[MAX_OPERATION_INSTANCES];
hmacSignOperationPool = new Object[MAX_OPERATION_INSTANCES];
// Reserve (KEY_ALGS.length * 4) + 4) size of key pool
// Extra 4 keys for TRUSTED_CONFIRMATION_REQUIRED feature.
keysPool = new Object[(short) ((KEY_ALGS.length * 4) + 4)];

// Creates an instance of each cipher algorithm once.
initializeCipherPool();
// Creates an instance of each signature algorithm once.
initializeSigPool();
initializeOperationPool();
initializeHmacSignOperationPool();
initializeKeysPool();
//RsaOAEP Decipher
rsaOaepDecipher = new KMRsaOAEPEncoding(KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1);

Expand Down Expand Up @@ -301,15 +324,15 @@ private boolean isSignerAlgorithm(byte alg) {

private void initializeOperationPool() {
short index = 0;
while (index < 4) {
while (index < MAX_OPERATION_INSTANCES) {
operationPool[index] = new KMOperationImpl();
index++;
}
}

private void initializeHmacSignOperationPool() {
short index = 0;
while (index < 4) {
while (index < MAX_OPERATION_INSTANCES) {
hmacSignOperationPool[index] = new KMOperationImpl();
index++;
}
Expand All @@ -324,6 +347,14 @@ private void initializeSigPool() {
}
}

private void initializeKeysPool() {
short index = 0;
while (index < KEY_ALGS.length) {
keysPool[index] = createKeyObjectInstance(KEY_ALGS[index]);
index++;
}
}

private Signature getSignatureInstance(byte alg) {
if (KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD == alg
|| KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST == alg) {
Expand Down Expand Up @@ -388,11 +419,11 @@ private Cipher getCipherInstanceFromPool(byte alg) {
return (Cipher) getInstanceFromPool(cipherPool, alg);
}

private boolean isResourceBusy(Object obj) {
private boolean isResourceBusy(Object obj, byte resourceType) {
short index = 0;
while (index < MAX_OPERATIONS) {
if (((KMOperationImpl) operationPool[index]).isResourceMatches(obj)
|| ((KMOperationImpl) hmacSignOperationPool[index]).isResourceMatches(obj)) {
while (index < MAX_OPERATION_INSTANCES) {
if (((KMOperationImpl) operationPool[index]).isResourceMatches(obj, resourceType)
|| ((KMOperationImpl) hmacSignOperationPool[index]).isResourceMatches(obj, resourceType)) {
return true;
}
index++;
Expand Down Expand Up @@ -435,7 +466,7 @@ private Object getInstanceFromPool(Object[] pool, byte alg) {
}
if ((isCipher && (alg == ((Cipher) pool[index]).getAlgorithm()))
|| ((isSigner && (alg == ((Signature) pool[index]).getAlgorithm())))) {
if (!isResourceBusy(pool[index])) {
if (!isResourceBusy(pool[index], RESOURCE_TYPE_CRYPTO)) {
return pool[index];
}
instanceCount++;
Expand All @@ -444,6 +475,47 @@ private Object getInstanceFromPool(Object[] pool, byte alg) {
}
return null;
}

public KMKeyObject getKeyObjectFromPool(byte algo, short secretLength) {
KMKeyObject keyObject = null;
short maxOperations = MAX_OPERATION_INSTANCES;
if (KMType.HMAC == algo) {
maxOperations = HMAC_MAX_OPERATION_INSTANCES;
}
if(algo == KMType.AES) {
if (secretLength == 16) {
algo = AES_128;
} else if (secretLength == 32) {
algo = AES_256;
} else {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
}
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.getAlgorithm()) {
// Check if the Object instance is not busy and free to use.
if (!isResourceBusy(keyObject, RESOURCE_TYPE_KEY)) {
break;
}
usageCount++;
}
index++;
}
return keyObject;
}

public AESKey createAESKey(short keysize) {
try {
Expand Down Expand Up @@ -915,20 +987,15 @@ private byte mapCipherAlg(byte alg, byte padding, byte blockmode, byte digest) {

public Cipher createSymmetricCipher(short alg, short purpose,
short blockMode, short padding, byte[] secret, short secretStart,
short secretLength, byte[] ivBuffer, short ivStart, short ivLength) {
Key key = null;
short secretLength, byte[] ivBuffer, short ivStart, short ivLength, KMKeyObject keyObject) {
Key key = (Key) keyObject.getKeyObjectInstance();
Cipher symmCipher = null;
switch (secretLength) {
case 32:
key = aesKeys[KEYSIZE_256_OFFSET];
((AESKey) key).setKey(secret, secretStart);
break;
case 16:
key = aesKeys[KEYSIZE_128_OFFSET];
case 16:
case 32:
((AESKey) key).setKey(secret, secretStart);
break;
case 24:
key = triDesKey;
((DESKey) key).setKey(secret, secretStart);
break;
default:
Expand Down Expand Up @@ -963,8 +1030,9 @@ public Cipher createSymmetricCipher(short alg, short purpose,
}

private Signature createHmacSignerVerifier(short purpose, short digest,
byte[] secret, short secretStart, short secretLength) {
HMACKey key = createHMACKey(secret, secretStart, secretLength);
byte[] secret, short secretStart, short secretLength, KMKeyObject keyObject) {
HMACKey key = (HMACKey) keyObject.getKeyObjectInstance();
key.setKey(secret, secretStart, secretLength);
return createHmacSignerVerifier(purpose, digest, key);
}

Expand All @@ -984,14 +1052,17 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg,
short keyLength, byte[] ivBuf, short ivStart, short ivLength,
short macLength) {
KMOperationImpl opr = null;
KMKeyObject keyObject = null;
switch (alg) {
case KMType.AES:
case KMType.DES:
keyObject = getKeyObjectFromPool(alg, keyLength);
Cipher cipher = createSymmetricCipher(alg, purpose, blockMode, padding,
keyBuf, keyStart, keyLength, ivBuf, ivStart, ivLength);
keyBuf, keyStart, keyLength, ivBuf, ivStart, ivLength, keyObject);
opr = getOperationInstanceFromPool();
// Convert macLength to bytes
macLength = (short) (macLength / 8);
opr.setKeyObject(keyObject);
opr.setCipher(cipher);
opr.setCipherAlgorithm(alg);
opr.setBlockMode(blockMode);
Expand All @@ -1000,9 +1071,11 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg,
opr.setMacLength(macLength);
break;
case KMType.HMAC:
keyObject = getKeyObjectFromPool(alg, keyLength);
Signature signerVerifier = createHmacSignerVerifier(purpose, digest,
keyBuf, keyStart, keyLength);
keyBuf, keyStart, keyLength, keyObject);
opr = getOperationInstanceFromPool();
opr.setKeyObject(keyObject);
opr.setMode(purpose);
opr.setSignature(signerVerifier);
break;
Expand All @@ -1017,16 +1090,20 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg,
public KMOperation initTrustedConfirmationSymmetricOperation(KMComputedHmacKey computedHmacKey) {
KMOperationImpl opr = null;
KMHmacKey key = (KMHmacKey) computedHmacKey;
Signature signerVerifier = createHmacSignerVerifier(KMType.VERIFY, KMType.SHA2_256, key.getKey());
short len = key.getKey(tmpArray, (short) 0);
KMKeyObject keyObject = getKeyObjectFromPool(KMType.HMAC, len);
Signature signerVerifier = createHmacSignerVerifier(KMType.VERIFY, KMType.SHA2_256, tmpArray,
(short) 0, len, keyObject);
opr = getHmacSignOperationInstanceFromPool();
opr.setKeyObject(keyObject);
opr.setMode(KMType.VERIFY);
opr.setSignature(signerVerifier);
return opr;
}

public Signature createRsaSigner(short digest, short padding, byte[] secret,
short secretStart, short secretLength, byte[] modBuffer, short modOff,
short modLength) {
short modLength, KMKeyObject keyObject) {
byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest);
byte opMode;
if (padding == KMType.PADDING_NONE
Expand All @@ -1036,7 +1113,7 @@ public Signature createRsaSigner(short digest, short padding, byte[] secret,
opMode = Signature.MODE_SIGN;
}
Signature rsaSigner = getSignatureInstanceFromPool(alg);
RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate();
RSAPrivateKey key = (RSAPrivateKey) ((KeyPair)(keyObject.getKeyObjectInstance())).getPrivate();
key.setExponent(secret, secretStart, secretLength);
key.setModulus(modBuffer, modOff, modLength);
rsaSigner.init(key, opMode);
Expand All @@ -1045,21 +1122,21 @@ public Signature createRsaSigner(short digest, short padding, byte[] secret,

public Cipher createRsaDecipher(short padding, short digest, byte[] secret,
short secretStart, short secretLength, byte[] modBuffer, short modOff,
short modLength) {
short modLength, KMKeyObject keyObject) {
byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte) digest);
Cipher rsaCipher = getCipherInstanceFromPool(cipherAlg);
RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate();
RSAPrivateKey key = (RSAPrivateKey) ((KeyPair)(keyObject.getKeyObjectInstance())).getPrivate();
key.setExponent(secret, secretStart, secretLength);
key.setModulus(modBuffer, modOff, modLength);
rsaCipher.init(key, Cipher.MODE_DECRYPT);
return rsaCipher;
}

public Signature createEcSigner(short digest, byte[] secret,
short secretStart, short secretLength) {
short secretStart, short secretLength, KMKeyObject keyObject) {
byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest);
Signature ecSigner = null;
ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate();
ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObject.getKeyObjectInstance())).getPrivate();
key.setS(secret, secretStart, secretLength);
ecSigner = getSignatureInstanceFromPool(alg);
ecSigner.init(key, Signature.MODE_SIGN);
Expand All @@ -1072,21 +1149,26 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg,
short privKeyLength, byte[] pubModBuf, short pubModStart,
short pubModLength) {
KMOperationImpl opr = null;
KMKeyObject keyObject = null;
if (alg == KMType.RSA) {
switch (purpose) {
case KMType.SIGN:
keyObject = getKeyObjectFromPool(alg, privKeyLength);
Signature signer = createRsaSigner(digest, padding, privKeyBuf,
privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength);
privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength, keyObject);
opr = getOperationInstanceFromPool();
opr.setKeyObject(keyObject);
opr.setSignature(signer);
opr.setCipherAlgorithm(alg);
opr.setPaddingAlgorithm(padding);
opr.setMode(purpose);
break;
case KMType.DECRYPT:
keyObject = getKeyObjectFromPool(alg, privKeyLength);
Cipher decipher = createRsaDecipher(padding, digest, privKeyBuf,
privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength);
privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength, keyObject);
opr = getOperationInstanceFromPool();
opr.setKeyObject(keyObject);
opr.setCipher(decipher);
opr.setCipherAlgorithm(alg);
opr.setPaddingAlgorithm(padding);
Expand All @@ -1099,9 +1181,11 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg,
} else if (alg == KMType.EC) {
switch (purpose) {
case KMType.SIGN:
keyObject = getKeyObjectFromPool(alg, privKeyLength);
Signature signer = createEcSigner(digest, privKeyBuf, privKeyStart,
privKeyLength);
privKeyLength, keyObject);
opr = getOperationInstanceFromPool();
opr.setKeyObject(keyObject);
opr.setMode(purpose);
opr.setSignature(signer);
break;
Expand Down Expand Up @@ -1394,5 +1478,40 @@ public short messageDigest256(byte[] inBuff, short inOffset,
}
return len;
}


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.setKeyObjectData(alg, keyObject);
return ptr;
}


}
Loading