Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,12 @@ public KMAndroidSEProvider() {
//Allocate buffer for certificate chain.
if (!isUpgrading()) {
certificateChain = new byte[CERT_CHAIN_MAX_SIZE];
// Initialize attestationKey and preShared key with zeros.
Util.arrayFillNonAtomic(tmpArray, (short) 0, TMP_ARRAY_SIZE, (byte) 0);
// Create attestation key of P-256 curve.
createAttestationKey(tmpArray, (short)0, (short) 32);
// Pre-shared secret key length is 32 bytes.
createPresharedKey(tmpArray, (short)0, (short) KMRepository.SHARED_SECRET_KEY_SIZE);
}
androidSEProvider = this;
}
Expand Down Expand Up @@ -987,22 +993,18 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg,
opr = getOperationInstanceFromPool();
// Convert macLength to bytes
macLength = (short) (macLength / 8);
JCSystem.beginTransaction();
opr.setCipher(cipher);
opr.setCipherAlgorithm(alg);
opr.setBlockMode(blockMode);
opr.setPaddingAlgorithm(padding);
opr.setMode(purpose);
opr.setMacLength(macLength);
JCSystem.commitTransaction();
break;
case KMType.HMAC:
Signature signerVerifier = createHmacSignerVerifier(purpose, digest,
keyBuf, keyStart, keyLength);
opr = getOperationInstanceFromPool();
JCSystem.beginTransaction();
opr.setSignature(signerVerifier);
JCSystem.commitTransaction();
break;
default:
CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
Expand Down Expand Up @@ -1065,23 +1067,19 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg,
Signature signer = createRsaSigner(digest, padding, privKeyBuf,
privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength);
opr = getOperationInstanceFromPool();
JCSystem.beginTransaction();
opr.setSignature(signer);
opr.setCipherAlgorithm(alg);
opr.setPaddingAlgorithm(padding);
opr.setMode(purpose);
JCSystem.commitTransaction();
break;
case KMType.DECRYPT:
Cipher decipher = createRsaDecipher(padding, digest, privKeyBuf,
privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength);
opr = getOperationInstanceFromPool();
JCSystem.beginTransaction();
opr.setCipher(decipher);
opr.setCipherAlgorithm(alg);
opr.setPaddingAlgorithm(padding);
opr.setMode(purpose);
JCSystem.commitTransaction();
break;
default:
KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
Expand All @@ -1093,9 +1091,7 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg,
Signature signer = createEcSigner(digest, privKeyBuf, privKeyStart,
privKeyLength);
opr = getOperationInstanceFromPool();
JCSystem.beginTransaction();
opr.setSignature(signer);
JCSystem.commitTransaction();
break;
default:
KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
Expand Down Expand Up @@ -1133,13 +1129,12 @@ public void clearCertificateChain() {
@Override
public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) {
// _____________________________________________________
// | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|...
// |_________|________|_________|_______|_________|______|
// | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | Cert2 |...
// |_________|________|_________|_______|________|_______
// First two bytes holds the length of the total buffer.
// CBOR format:
// Next single byte holds the array header.
// Next 3 bytes holds the Byte array header with the cert1 length.
// Next 3 bytes holds the Byte array header with the cert2 length.
// Next single byte holds the byte string header.
// Next 3 bytes holds the total length of the certificate chain.
if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) {
KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,110 +23,118 @@

public class KMOperationImpl implements KMOperation {

private Cipher cipher;
private Signature signature;
private short cipherAlg;
private short padding;
private short mode;
private short blockMode;
private short macLength;
private static final short CIPHER_ALG_OFFSET = 0x00;
private static final short PADDING_OFFSET = 0x01;
private static final short OPER_MODE_OFFSET = 0x02;
private static final short BLOCK_MODE_OFFSET = 0x03;
private static final short MAC_LENGTH_OFFSET = 0x04;
//This will hold the length of the buffer stored inside the
//Java Card after the GCM update operation.
private short aesGcmUpdatedLen;
private static final short AES_GCM_UPDATE_LEN_OFFSET = 0x05;
private short[] parameters;
// Either one of Cipher/Signature instance is stored.
private Object[] operationInst;

public KMOperationImpl() {
parameters = JCSystem.makeTransientShortArray((short) 6, JCSystem.CLEAR_ON_RESET);
operationInst = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET);
}

public short getMode() {
return mode;
return parameters[OPER_MODE_OFFSET];
}

public void setMode(short mode) {
this.mode = mode;
parameters[OPER_MODE_OFFSET] = mode;
}

public short getMacLength() {
return macLength;
return parameters[MAC_LENGTH_OFFSET];
}

public void setMacLength(short macLength) {
this.macLength = macLength;
parameters[MAC_LENGTH_OFFSET] = macLength;
}

public short getPaddingAlgorithm() {
return padding;
return parameters[PADDING_OFFSET];
}

public void setPaddingAlgorithm(short alg) {
padding = alg;
parameters[PADDING_OFFSET] = alg;
}

public void setBlockMode(short mode) {
blockMode = mode;
parameters[BLOCK_MODE_OFFSET] = mode;
}

public short getBlockMode() {
return blockMode;
return parameters[BLOCK_MODE_OFFSET];
}

public short getCipherAlgorithm() {
return cipherAlg;
return parameters[CIPHER_ALG_OFFSET];
}

public void setCipherAlgorithm(short cipherAlg) {
this.cipherAlg = cipherAlg;
parameters[CIPHER_ALG_OFFSET] = cipherAlg;
}

public void setCipher(Cipher cipher) {
this.cipher = cipher;
operationInst[0] = cipher;
}

public void setSignature(Signature signer) {
this.signature = signer;
operationInst[0] = signer;
}

private void resetCipher() {
JCSystem.beginTransaction();
cipher = null;
macLength = 0;
aesGcmUpdatedLen = 0;
blockMode = 0;
mode = 0;
cipherAlg = 0;
JCSystem.commitTransaction();
operationInst[0] = null;
parameters[MAC_LENGTH_OFFSET] = 0;
parameters[AES_GCM_UPDATE_LEN_OFFSET] = 0;
parameters[BLOCK_MODE_OFFSET] = 0;
parameters[OPER_MODE_OFFSET] = 0;
parameters[CIPHER_ALG_OFFSET] = 0;
parameters[PADDING_OFFSET] = 0;
}

@Override
public short update(byte[] inputDataBuf, short inputDataStart,
short inputDataLength, byte[] outputDataBuf, short outputDataStart) {
short len = cipher.update(inputDataBuf, inputDataStart, inputDataLength,
outputDataBuf, outputDataStart);
if (cipherAlg == KMType.AES && blockMode == KMType.GCM) {
short inputDataLength, byte[] outputDataBuf, short outputDataStart) {
short len = ((Cipher) operationInst[0]).update(inputDataBuf, inputDataStart, inputDataLength,
outputDataBuf, outputDataStart);
if (parameters[CIPHER_ALG_OFFSET] == KMType.AES && parameters[BLOCK_MODE_OFFSET] == KMType.GCM) {
// Every time Block size data is stored as intermediate result.
aesGcmUpdatedLen += (short) (inputDataLength - len);
parameters[AES_GCM_UPDATE_LEN_OFFSET] += (short) (inputDataLength - len);
}
return len;
}

@Override
public short update(byte[] inputDataBuf, short inputDataStart,
short inputDataLength) {
signature.update(inputDataBuf, inputDataStart, inputDataLength);
short inputDataLength) {
((Signature) operationInst[0]).update(inputDataBuf, inputDataStart, inputDataLength);
return 0;
}

@Override
public short finish(byte[] inputDataBuf, short inputDataStart,
short inputDataLen, byte[] outputDataBuf, short outputDataStart) {
short inputDataLen, byte[] outputDataBuf, short outputDataStart) {
byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray;
Cipher cipher = (Cipher) operationInst[0];
short cipherAlg = parameters[CIPHER_ALG_OFFSET];
short blockMode = parameters[BLOCK_MODE_OFFSET];
short mode = parameters[OPER_MODE_OFFSET];
short macLength = parameters[MAC_LENGTH_OFFSET];
short padding = parameters[PADDING_OFFSET];
short len = 0;
try {
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) {
padding == KMType.PKCS7 && mode == KMType.ENCRYPT) {
byte blkSize = 16;
byte paddingBytes;
short inputlen = inputDataLen;
Expand All @@ -146,15 +154,15 @@ public short finish(byte[] inputDataBuf, short inputDataStart,
Util.arrayFillNonAtomic(tmpArray, (short) 0, inputlen, paddingBytes);
// copy the input data
Util.arrayCopyNonAtomic(inputDataBuf, inputDataStart, tmpArray,
(short) 0, inputDataLen);
(short) 0, inputDataLen);
inputDataBuf = tmpArray;
inputDataLen = inputlen;
inputDataStart = 0;
}
len = cipher.doFinal(inputDataBuf, inputDataStart, inputDataLen,
outputDataBuf, outputDataStart);
outputDataBuf, outputDataStart);
if ((cipherAlg == KMType.AES || cipherAlg == KMType.DES) &&
padding == KMType.PKCS7 && mode == KMType.DECRYPT) {
padding == KMType.PKCS7 && mode == KMType.DECRYPT) {
byte blkSize = 16;
if (cipherAlg == KMType.DES) {
blkSize = 8;
Expand All @@ -177,10 +185,10 @@ public short finish(byte[] inputDataBuf, short inputDataStart,
} else if (cipherAlg == KMType.AES && blockMode == KMType.GCM) {
if (mode == KMType.ENCRYPT) {
len += ((AEADCipher) cipher).retrieveTag(outputDataBuf,
(short) (outputDataStart + len), macLength);
(short) (outputDataStart + len), macLength);
} else {
boolean verified = ((AEADCipher) cipher).verifyTag(inputDataBuf,
(short) (inputDataStart + inputDataLen), macLength, macLength);
(short) (inputDataStart + inputDataLen), macLength, macLength);
if (!verified) {
KMException.throwIt(KMError.VERIFICATION_FAILED);
}
Expand All @@ -196,57 +204,58 @@ public short finish(byte[] inputDataBuf, short inputDataStart,

@Override
public short sign(byte[] inputDataBuf, short inputDataStart,
short inputDataLength, byte[] signBuf, short signStart) {
short inputDataLength, byte[] signBuf, short signStart) {
short len = 0;
try {
len = signature.sign(inputDataBuf, inputDataStart, inputDataLength,
signBuf, signStart);
len = ((Signature) operationInst[0]).sign(inputDataBuf, inputDataStart, inputDataLength,
signBuf, signStart);
} finally {
KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature);
signature = null;
KMAndroidSEProvider.getInstance().releaseSignatureInstance((Signature) operationInst[0]);
operationInst[0] = null;
}
return len;
}

@Override
public boolean verify(byte[] inputDataBuf, short inputDataStart,
short inputDataLength, byte[] signBuf, short signStart, short signLength) {
short inputDataLength, byte[] signBuf, short signStart, short signLength) {
boolean ret = false;
try {
ret = signature.verify(inputDataBuf, inputDataStart, inputDataLength,
signBuf, signStart, signLength);
ret = ((Signature) operationInst[0]).verify(inputDataBuf, inputDataStart, inputDataLength,
signBuf, signStart, signLength);
} finally {
KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature);
signature = null;
KMAndroidSEProvider.getInstance().releaseSignatureInstance((Signature) operationInst[0]);
operationInst[0] = null;
}
return ret;
}

@Override
public void abort() {
// do nothing
if (cipher != null) {
KMAndroidSEProvider.getInstance().releaseCipherInstance(cipher);
resetCipher();
}
if (signature != null) {
KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature);
signature = null;
if (operationInst[0] != null) {
if (parameters[OPER_MODE_OFFSET] == KMType.ENCRYPT ||
parameters[OPER_MODE_OFFSET] == KMType.DECRYPT) {
KMAndroidSEProvider.getInstance().releaseCipherInstance((Cipher) operationInst[0]);
resetCipher();
} else {
KMAndroidSEProvider.getInstance().releaseSignatureInstance((Signature) operationInst[0]);
}
operationInst[0] = null;
}
KMAndroidSEProvider.getInstance().releaseOperationInstance(this);
}

@Override
public void updateAAD(byte[] dataBuf, short dataStart, short dataLength) {
((AEADCipher) cipher).updateAAD(dataBuf, dataStart, dataLength);
((AEADCipher) operationInst[0]).updateAAD(dataBuf, dataStart, dataLength);
}

@Override
public short getAESGCMOutputSize(short dataSize, short macLength) {
if (mode == KMType.ENCRYPT) {
return (short) (aesGcmUpdatedLen + dataSize + macLength);
if (parameters[OPER_MODE_OFFSET] == KMType.ENCRYPT) {
return (short) (parameters[AES_GCM_UPDATE_LEN_OFFSET] + dataSize + macLength);
} else {
return (short) (aesGcmUpdatedLen + dataSize - macLength);
return (short) (parameters[AES_GCM_UPDATE_LEN_OFFSET] + dataSize - macLength);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1203,13 +1203,12 @@ public void clearCertificateChain() {
public void persistPartialCertificateChain(byte[] buf, short offset,
short len, short totalLen) {
// _____________________________________________________
// | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|...
// |_________|________|_________|_______|_________|______|
// | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | Cert2 |...
// |_________|________|_________|_______|________|_______
// First two bytes holds the length of the total buffer.
// CBOR format:
// Next single byte holds the array header.
// Next 3 bytes holds the Byte array header with the cert1 length.
// Next 3 bytes holds the Byte array header with the cert2 length.
// Next single byte holds the byte string header.
// Next 3 bytes holds the total length of the certificate chain.
if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) {
KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
}
Expand Down
Loading