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
@@ -0,0 +1,61 @@
/*
* Copyright(C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" (short)0IS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.javacard.keymaster;

import org.globalplatform.upgrade.Element;

import com.android.javacard.keymaster.KMMasterKey;

import javacard.security.AESKey;

public class KMAESKey implements KMMasterKey {
private AESKey aesKey;

public KMAESKey(AESKey key) {
aesKey = key;
}

public void setKey(byte[] keyData, short kOff) {
aesKey.setKey(keyData, kOff);
}

public AESKey getKey() {
return aesKey;
}

public short getKeySizeBits() {
return aesKey.getSize();
}

public static void onSave(Element element, KMAESKey kmKey) {
element.write(kmKey.aesKey);
}

public static KMAESKey onRestore(Element element) {
AESKey aesKey = (AESKey) element.readObject();
KMAESKey kmKey = new KMAESKey(aesKey);
return kmKey;
}

public static short getBackupPrimitiveByteCount() {
return (short) 0;
}

public static short getBackupObjectCount() {
return (short) 1;
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright(C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" (short)0IS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.javacard.keymaster;

import org.globalplatform.upgrade.Element;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
import javacardx.crypto.AEADCipher;
import javacardx.crypto.Cipher;

import com.android.javacard.keymaster.KMAESKey;
import com.android.javacard.keymaster.KMAttestationKey;
import com.android.javacard.keymaster.KMECPrivateKey;
import com.android.javacard.keymaster.KMHmacKey;
import com.android.javacard.keymaster.KMMasterKey;
import com.android.javacard.keymaster.KMPreSharedKey;

public class KMAndroidSEProvider implements KMSEProvider {
// static final variables
// --------------------------------------------------------------
Expand Down Expand Up @@ -158,6 +165,9 @@ public class KMAndroidSEProvider implements KMSEProvider {
private RandomData rng;
//For storing root certificate and intermediate certificates.
private byte[] certificateChain;
private KMAESKey masterKey;
private KMECPrivateKey attestationKey;
private KMHmacKey preSharedKey;

private static KMAndroidSEProvider androidSEProvider = null;

Expand All @@ -177,7 +187,8 @@ public KMAndroidSEProvider() {
hmacKey = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) 512,
false);
rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048);
initECKey();
ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
initECKey(ecKeyPair);

// Re-usable cipher and signature instances
cipherPool = new Object[(short) (CIPHER_ALGS.length * 4)];
Expand Down Expand Up @@ -210,8 +221,7 @@ public void clean() {
Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0);
}

private void initECKey() {
ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
private void initECKey(KeyPair ecKeyPair) {
ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate();
ECPublicKey pubkey = (ECPublicKey) ecKeyPair.getPublic();
pubkey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length);
Expand Down Expand Up @@ -600,13 +610,11 @@ public void addRngEntropy(byte[] num, short offset, short length) {
rng.setSeed(num, offset, length);
}

@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) {

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);
}
Expand All @@ -617,7 +625,6 @@ public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen,
aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM,
false);
}
AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen);
aesGcmCipher.init(key, Cipher.MODE_ENCRYPT, nonce, nonceStart, nonceLen);
aesGcmCipher.updateAAD(authData, authDataStart, authDataLen);
short ciphLen = aesGcmCipher.doFinal(secret, secretStart, secretLen,
Expand All @@ -626,6 +633,32 @@ public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen,
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,
Expand All @@ -648,8 +681,7 @@ public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart,
return verification;
}

public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart,
short keyMaterialLen, byte[] label, short labelStart, short labelLen,
public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelStart, short labelLen,
byte[] context, short contextStart, short contextLength) {
try {
// This is hardcoded to requirement - 32 byte output with two concatenated
Expand All @@ -667,10 +699,18 @@ public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart,
// [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.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);
aesKeys[KEYSIZE_256_OFFSET].setKey(keyMaterial, (short) keyMaterialStart);
kdf.init(aesKeys[KEYSIZE_256_OFFSET], Signature.MODE_SIGN);

byte i = 1;
short pos = 0;
while (i <= n) {
Expand Down Expand Up @@ -711,6 +751,21 @@ public short hmacSign(byte[] keyBuf, short keyStart, short keyLength,
return hmacSign(key, data, dataStart, dataLength, mac, macStart);
}

@Override
public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart,
short dataLength, byte[] signature, short signatureStart) {
try {
AESKey aesKey = ((KMAESKey) masterkey).getKey();
aesKey.getKey(tmpArray, (short) 0);
HMACKey key = createHMACKey(tmpArray, (short) 0,
(short) (aesKey.getSize() / 8));
return hmacSign(key, data, dataStart, dataLength, signature,
signatureStart);
} finally {
clean();
}
}

@Override
public boolean hmacVerify(byte[] keyBuf, short keyStart, short keyLength,
byte[] data, short dataStart, short dataLength, byte[] mac,
Expand All @@ -733,17 +788,15 @@ public short rsaDecipherOAEP256(byte[] secret, short secretStart,
outputDataBuf, (short) outputDataStart);
}

public short ecSign256(byte[] secret, short secretStart, short secretLength,
public short ecSign256(KMAttestationKey attestationKey,
byte[] inputDataBuf, short inputDataStart, short inputDataLength,
byte[] outputDataBuf, short outputDataStart) {
Signature.OneShot signer = null;
try {
ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate();
key.setS(secret, secretStart, secretLength);

signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256,
Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL);
signer.init(key, Signature.MODE_SIGN);
signer.init(((KMECPrivateKey)attestationKey).getPrivateKey(), Signature.MODE_SIGN);
return signer.sign(inputDataBuf, inputDataStart, inputDataLength,
outputDataBuf, outputDataStart);
} finally {
Expand Down Expand Up @@ -975,7 +1028,7 @@ public Cipher createRsaCipher(short padding, short digest, byte[] modBuffer,
short modOff, short modLength) {
try {
byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte)digest);
// TODO Java Card does not support MGF1-SHA1 and digest as SHA256.
// Java Card does not support MGF1-SHA1 and digest as SHA256.
// Both digest should be SHA256 as per Java Card, but as per Keymaster
// MGF should use SHA1 and message digest should be SHA256.
if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) {
Expand Down Expand Up @@ -1116,12 +1169,11 @@ public KMAttestationCert getAttestationCert(boolean rsaCert) {
}

@Override
public short cmacKdf(byte[] keyMaterial, short keyMaterialStart,
short keyMaterialLen, byte[] label, short labelStart, short labelLen,
byte[] context, short contextStart, short contextLength, byte[] keyBuf,
short keyStart) {
HMACKey key = cmacKdf(keyMaterial, keyMaterialStart, keyMaterialLen, label,
labelStart, labelLen, context, contextStart, contextLength);
public short cmacKDF(KMPreSharedKey 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);
}

Expand Down Expand Up @@ -1187,25 +1239,100 @@ public void clearDeviceBooted(boolean resetBootFlag) {
@Override
public void onSave(Element element) {
element.write(certificateChain);
KMAESKey.onSave(element, masterKey);
KMECPrivateKey.onSave(element, attestationKey);
KMHmacKey.onSave(element, preSharedKey);
}

@Override
public void onRestore(Element element) {
certificateChain = (byte[]) element.readObject();
masterKey = KMAESKey.onRestore(element);
attestationKey = KMECPrivateKey.onRestore(element);
preSharedKey = KMHmacKey.onRestore(element);
}

@Override
public short getBackupPrimitiveByteCount() {
return (short) 0;
short count =
(short) (KMAESKey.getBackupPrimitiveByteCount() +
KMECPrivateKey.getBackupPrimitiveByteCount() +
KMHmacKey.getBackupPrimitiveByteCount());
return count;
}

@Override
public short getBackupObjectCount() {
return (short) 1;
short count =
(short) (1 /*Certificate chain */ +
KMAESKey.getBackupObjectCount() +
KMECPrivateKey.getBackupObjectCount() +
KMHmacKey.getBackupObjectCount());
return count;
}

@Override
public boolean isUpgrading() {
return UpgradeManager.isUpgrading();
}

@Override
public KMMasterKey createMasterKey(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);
getTrueRandomNumber(tmpArray, (short) 0, keyLen);
masterKey.setKey(tmpArray, (short) 0);
}
return (KMMasterKey) masterKey;
} finally {
clean();
}
}

@Override
public KMAttestationKey createAttestationKey(byte[] keyData, short offset,
short length) {
if (attestationKey == null) {
// Strongbox supports only P-256 curve for EC key.
KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
initECKey(ecKeyPair);
attestationKey = new KMECPrivateKey(ecKeyPair);
}
attestationKey.setS(keyData, offset, length);
return (KMAttestationKey) attestationKey;
}

@Override
public KMPreSharedKey createPresharedKey(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);
}
preSharedKey.setKey(keyData, offset, length);
return (KMPreSharedKey) preSharedKey;
}

@Override
public KMMasterKey getMasterKey() {
return (KMMasterKey) masterKey;
}

@Override
public KMAttestationKey getAttestationKey() {
return (KMAttestationKey) attestationKey;
}

@Override
public KMPreSharedKey getPresharedKey() {
return (KMPreSharedKey) preSharedKey;
}
}
Loading