Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5eeda37
Merge pull request #2 from cpathak/master
divegeek Mar 25, 2020
cc368c9
Update README to add HAL design doc link
divegeek Mar 26, 2020
6f9748f
Optimization of the code
cpathak Apr 7, 2020
39e34d5
Create COPYRIGHT
divegeek May 13, 2020
378331d
Delete COPYRIGHT
divegeek May 13, 2020
dc51f3f
ImportKey, GenerateKey and GetKeyCharacteristics
cpathak May 14, 2020
1c4ee23
Changes with crypto provider
cpathak Jun 9, 2020
e8a1546
Removed untested commands from KeymasterApplet
cpathak Jun 9, 2020
be4e303
Added Operations and commands
cpathak Jun 16, 2020
1d660ed
Added Import Wrapped Key
cpathak Jun 17, 2020
04c0880
Added getHmacSharingParams, ComputeSharedHmacKey
cpathak Jun 18, 2020
0925a18
Added AES GCM Cipher
cpathak Jun 22, 2020
32b716d
Added deviceLocked command
cpathak Jun 24, 2020
12ede7a
Bug fixes
cpathak Jun 26, 2020
244c6bc
Added RSA OAEP Encrypt Decrypt
cpathak Jun 29, 2020
5eff3bc
Added RSA signing with digest none
cpathak Jun 29, 2020
f47289a
Attest Key and Provision Command
cpathak Jul 23, 2020
e1fbc24
Added destroyAttestationIds command
cpathak Jul 23, 2020
93632be
Bug fix and support for EC Keys in AttestKey
cpathak Jul 24, 2020
8243c34
Update KMEnum.java
cpathak Jul 24, 2020
1e17516
Bug fixing and AES CTR support
cpathak Jul 28, 2020
9c6b1fc
Merge pull request #7 from cpathak/master
Jul 28, 2020
98e2792
Merge pull request #4 from BKSSMVenkateswarlu/master
Jul 28, 2020
171ba4c
Update KMKeymasterApplet.java
cpathak Jul 29, 2020
a13a56b
Update KMKeymasterApplet.java
cpathak Jul 29, 2020
8db678b
Changes due VTS related bug fixes
cpathak Aug 11, 2020
db536dc
Merge pull request #9 from BKSSMVenkateswarlu/master
Aug 19, 2020
ced06d9
Merge pull request #8 from cpathak/master
Aug 19, 2020
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 numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
package com.android.javacard.keymaster;

import javacard.framework.Util;
import javacard.security.CryptoException;
import javacardx.crypto.Cipher;
import javax.crypto.AEADBadTagException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.ShortBufferException;


public class KMCipherImpl extends KMCipher{
private Cipher cipher;
private javax.crypto.Cipher sunCipher;
private short cipherAlg;
private short paddingAlg;
private short mode;
private boolean verificationFlag;
public static short aes_gcm_decrypt_final_data = 0x00;

KMCipherImpl(Cipher c){
cipher = c;
}
KMCipherImpl(javax.crypto.Cipher c){
sunCipher = c;
}

@Override
public short doFinal(byte[] buffer, short startOff, short length, byte[] scratchPad, short i){
if(cipherAlg == KMCipher.CIPHER_RSA &&
(paddingAlg == KMCipher.PAD_PKCS1_OAEP_SHA256||paddingAlg == KMCipher.PAD_PKCS1_OAEP)){
try {
return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i);
} catch (ShortBufferException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
} catch (BadPaddingException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
}else if(cipherAlg == KMCipher.ALG_AES_GCM){
try {
/*
if (mode == javax.crypto.Cipher.DECRYPT_MODE) {
short acutalLen = (short)sunCipher.getOutputSize(length);
aes_gcm_decrypt_final_data = KMByteBlob.instance(acutalLen);
return (short)sunCipher.doFinal(buffer,startOff,length,
KMByteBlob.cast(aes_gcm_decrypt_final_data).getBuffer(),
KMByteBlob.cast(aes_gcm_decrypt_final_data).getStartOff());
}
*/
return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i);
} catch (AEADBadTagException e) {
e.printStackTrace();
verificationFlag = false;
KMException.throwIt(KMError.VERIFICATION_FAILED);
} catch (ShortBufferException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
} catch (IllegalBlockSizeException e) {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
} catch (BadPaddingException e) {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
} else if(cipherAlg == KMCipher.ALG_AES_CTR){
try {
return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i);
} catch (ShortBufferException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
} catch (BadPaddingException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
}
else{
short len = cipher.doFinal(buffer, startOff, length, scratchPad, i);
// JCard Sim removes leading zeros during decryption in case of no padding - we add that back.
if (cipherAlg == Cipher.ALG_RSA_NOPAD && mode == Cipher.MODE_DECRYPT && len < 256) {
byte[] tempBuf = new byte[256];
Util.arrayFillNonAtomic(tempBuf, (short) 0, (short) 256, (byte) 0);
Util.arrayCopyNonAtomic(scratchPad, (short) 0, tempBuf, (short) (i + 256 - len), len);
Util.arrayCopyNonAtomic(tempBuf, (short) 0, scratchPad, i, (short) 256);
len = 256;
}
return len;
}
return KMType.INVALID_VALUE;
}

@Override
public short getCipherAlgorithm() {
return cipherAlg;
}

@Override
public void setCipherAlgorithm(short alg) {
cipherAlg = alg;
}

@Override
public short update(byte[] buffer, short startOff, short length, byte[] scratchPad, short i) {
short len = 0;
if(cipherAlg == KMCipher.ALG_AES_GCM || cipherAlg == KMCipher.ALG_AES_CTR){
try {
return (short)sunCipher.update(buffer,startOff,length,scratchPad,i);
} catch (ShortBufferException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
} else{
return cipher.update(buffer, startOff, length, scratchPad, i);
}
return KMType.INVALID_VALUE;
}

@Override
public void updateAAD(byte[] buffer, short startOff, short length) {
try {
sunCipher.updateAAD(buffer,startOff,length);
} catch (IllegalArgumentException e) {
e.printStackTrace();
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
} catch (IllegalStateException e) {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
} catch (UnsupportedOperationException e) {
CryptoException.throwIt(CryptoException.ILLEGAL_USE);
}
}

@Override
public short getPaddingAlgorithm() {
return paddingAlg;
}

@Override
public void setPaddingAlgorithm(short alg) {
paddingAlg = alg;
}

public short getMode() {
return mode;
}

public void setMode(short mode) {
this.mode = mode;
}

@Override
public short getCipherProvider() {
return KMCipher.SUN_JCE;
}

@Override
public short getAesGcmOutputSize(short len, short macLength) {
if (sunCipher != null) {
return (short) sunCipher.getOutputSize(len);
} else {
if (mode == KMType.ENCRYPT) {
return (short) (len + macLength);
} else {
return (short) (len - macLength);
}
}
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
package com.android.javacard.keymaster;

import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import javacard.framework.Util;
import javacard.security.CryptoException;
import javacard.security.Key;
import javacard.security.Signature;


public class KMEcdsa256NoDigestSignature extends Signature {
private java.security.Signature sunSigner;

public KMEcdsa256NoDigestSignature(byte mode, byte[] key, short keyStart, short keyLength){
KeyFactory kf;
try {
sunSigner = java.security.Signature.getInstance("NONEwithECDSA", "SunEC");
kf = KeyFactory.getInstance("EC");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", "SunEC");
//Supported curve secp256r1
parameters.init(new ECGenParameterSpec("secp256r1"));
ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
if(mode == Signature.MODE_SIGN) {
byte[] privKey = new byte[keyLength];
for(short i =0; i< keyLength; i++) {
privKey[i] = key[keyStart+i];
}
BigInteger bI = new BigInteger(privKey);
ECPrivateKeySpec prikeyspec = new ECPrivateKeySpec(bI, ecParameters);
ECPrivateKey privkey = (ECPrivateKey) kf.generatePrivate(prikeyspec);
sunSigner.initSign(privkey);
} else {
//Check if the first byte is 04 and remove it.
if(key[keyStart] == 0x04) {
//uncompressed format.
keyStart++;
keyLength--;
}
short i = 0;
byte[] pubx = new byte[keyLength/2];
for(;i < keyLength/2; i++ ) {
pubx[i] = key[keyStart+i];
}
byte[] puby = new byte[keyLength/2];
for(i = 0;i < keyLength/2; i++ ) {
puby[i] = key[keyStart+keyLength/2+i];
}
BigInteger bIX = new BigInteger(pubx);
BigInteger bIY = new BigInteger(puby);
ECPoint point = new ECPoint(bIX, bIY);
ECPublicKeySpec pubkeyspec = new ECPublicKeySpec(point, ecParameters);
ECPublicKey pubkey = (ECPublicKey) kf.generatePublic(pubkeyspec);
sunSigner.initVerify(pubkey);
}
} catch (NoSuchAlgorithmException e) {
CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
} catch (NoSuchProviderException e) {
CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM);
} catch(InvalidParameterSpecException e) {
CryptoException.throwIt(CryptoException.INVALID_INIT);
} catch(InvalidKeySpecException e) {
CryptoException.throwIt(CryptoException.INVALID_INIT);
} catch(InvalidKeyException e) {
CryptoException.throwIt(CryptoException.INVALID_INIT);
}
}

@Override
public void init(Key key, byte b) throws CryptoException {

}

@Override
public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException {

}

@Override
public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException {

}

@Override
public byte getAlgorithm() {
return 0;
}

@Override
public byte getMessageDigestAlgorithm() {
return 0;
}

@Override
public byte getCipherAlgorithm() {
return 0;
}

@Override
public byte getPaddingAlgorithm() {
return 0;
}

@Override
public short getLength() throws CryptoException {
return 0;
}

@Override
public void update(byte[] message, short msgStart, short messageLength) throws CryptoException {
byte[] msgBytes = new byte[messageLength];
for(int i =0; i< messageLength; i++) {
msgBytes[i] = message[msgStart+i];
}
try {
if(messageLength > 0)
sunSigner.update(msgBytes);
} catch (SignatureException e) {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
}

@Override
public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException {
short len = 0;
try {
update(bytes, i , i1);
byte[] sig = sunSigner.sign();
Util.arrayCopyNonAtomic(sig, (short)0, bytes1, i2, (short)sig.length);
return (short)sig.length;
} catch (SignatureException e) {
// TODO Auto-generated catch block
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
return len;
}

@Override
public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException {
return 0;
}

@Override
public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException {
// Cannot support this method as javacard cipher api does not allow 256 byte for public key
// encryption without padding. It only allows 255 bytes data.
try {
update(bytes, i , i1);
return sunSigner.verify(bytes1, i2, i3);
} catch (SignatureException e) {
// TODO Auto-generated catch block
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
return false;
}

@Override
public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException {
return false;
}
}
Loading