Commit fc423e41 authored by Josh Ji's avatar Josh Ji

clientPin_getPinRetries, clientPin_getKeyAgreement, clientPin_setPin

parent 8cfdaad1
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java/com/josh/vku2f/CTAP2.java" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
This diff is collapsed.
......@@ -275,6 +275,7 @@ public class AuthenticatorMakeCredential {
// Extensions
// We don't support any yet
// So check it's a map and skip
// TODO implement prlab extensions
if(decoder.getMajorType() != CBORBase.TYPE_MAP) {
UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
break;
......
......@@ -87,7 +87,7 @@ public abstract class CBORBase {
/**
* Initializes the encoder/decoder without buffer (use the APDU buffer instead).
*
* @param offset Offset in APDU buffer where content should be read
* @ param offset Offset in APDU buffer where content should be read
* @param length Length in the APDU buffer
*/
final public void init(short off, short length) {
......@@ -98,7 +98,7 @@ public abstract class CBORBase {
/**
* Initializes with a given array and the given offset.
* @param buffer Buffer with CBOR content
* @param offset Offset in buffer where content should be read/written
* @ param offset Offset in buffer where content should be read/written
*/
final public void init(byte[] buffer, short off, short length) {
if (buffer != APDU.getCurrentAPDUBuffer()) { // do not store the APDU buffer
......
This diff is collapsed.
package com.josh.vku2f;
import javacard.framework.JCSystem;
import javacard.framework.UserException;
import javacard.framework.Util;
public class ClientPINCommand {
public static final byte PARAMETER_PROTOCOL = 0x01;
......@@ -14,19 +16,22 @@ public class ClientPINCommand {
private byte protocol; // unsigned int
private byte subCommandCode; // unsigned int
private byte[] keyAgreement; // COSE object
private byte[] pinUvAuthParam; // byte string
private byte[] newPinEnc; // byte string
private byte[] pinHashEnc; // byte string
private byte[] keyAgreement = new byte[65]; // COSE object or 0x04||x||y
private byte[] x = new byte[32]; // x-coordinate
private byte[] y = new byte[32]; // y-coordinate
private byte[] pinUvAuthParam = new byte[64]; // byte string
private byte[] newPinEnc = new byte[64]; // byte string
private byte[] pinHashEnc = new byte[32]; // byte string
private byte permissions; // unsigned int
private byte[] rpId; // text string
private byte[] rpId = new byte[64]; // text string
byte[] scratch = JCSystem.makeTransientByteArray((short)64, JCSystem.CLEAR_ON_RESET);
public void decodeCommand(CBORDecoder cborDecoder) throws UserException {
short commandLength = cborDecoder.readMajorType(CBORBase.TYPE_MAP);
do {
byte commandKey = cborDecoder.readInt8();
while(commandLength > (short)0) {
short valueLength;
switch (commandKey) {
switch (cborDecoder.readInt8()) {
case PARAMETER_PROTOCOL:
protocol = cborDecoder.readInt8();
break;
......@@ -34,36 +39,50 @@ public class ClientPINCommand {
subCommandCode = cborDecoder.readInt8();
break;
case PARAMETER_KEY_AGREEMENT:
valueLength = cborDecoder.readLength();
keyAgreement = new byte[valueLength];
cborDecoder.readRawByteArray(keyAgreement, (short) 0, valueLength);
cborDecoder.readMajorType(CBORBase.TYPE_MAP);
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
// cborDecoder.skipEntry();
cborDecoder.readByteString(x, (short)0);
cborDecoder.skipEntry();
// cborDecoder.skipEntry();
cborDecoder.readByteString(y, (short)0);
break;
case PARAMETER_PIN_UV_AUTH_PARAM:
valueLength = cborDecoder.readLength();
pinUvAuthParam = new byte[valueLength];
cborDecoder.readRawByteArray(pinUvAuthParam, (short) 0, valueLength);
// cborDecoder.readByteString(pinUvAuthParam, (short) 0);
cborDecoder.skipEntry();
break;
case PARAMETER_NEW_PIN_ENC:
valueLength = cborDecoder.readLength();
newPinEnc = new byte[valueLength];
cborDecoder.readRawByteArray(newPinEnc, (short) 0, valueLength);
cborDecoder.readByteString(newPinEnc, (short) 0);
break;
case PARAMETER_PIN_HASH_ENC:
valueLength = cborDecoder.readLength();
pinHashEnc = new byte[valueLength];
cborDecoder.readRawByteArray(pinHashEnc, (short) 0, valueLength);
// cborDecoder.readByteString(pinHashEnc, (short) 0);
cborDecoder.skipEntry();
break;
case PARAMETER_PERMISSIONS:
permissions = cborDecoder.readInt8();
// permissions = cborDecoder.readInt8();
cborDecoder.skipEntry();
break;
case PARAMETER_RP_ID:
valueLength = cborDecoder.readLength();
rpId = new byte[valueLength];
cborDecoder.readRawByteArray(rpId, (short) 0, valueLength);
// cborDecoder.readByteString(rpId, (short) 0);
cborDecoder.skipEntry();
break;
}
commandLength--;
} while (commandLength >= 1);
}
}
public byte getProtocol() {
......@@ -75,6 +94,9 @@ public class ClientPINCommand {
}
public byte[] getKeyAgreement() {
keyAgreement[0] = 0x04;
Util.arrayCopy(x, (short)0, keyAgreement, (short)1, (short)x.length);
Util.arrayCopy(y, (short)0, keyAgreement, (short)33, (short)y.length);
return keyAgreement;
}
......
......@@ -30,6 +30,9 @@ public class IDSecret {
private MessageDigest sha256;
private byte[] scratch;
private final short SCRATCH_LENGTH = (short)128 ;
private CBOREncoder encoder = new CBOREncoder();
public final byte[] tempBuffer = new byte[100];
public short tempBufferLength = (short)0;
public IDSecret(){
IDx = new DomString(Utf8Strings.UTF8_NULL, (short)Utf8Strings.UTF8_NULL.length);
......@@ -45,6 +48,7 @@ public class IDSecret {
Random.getInstance().nextBytes(Cx, (short)0, (short)Cx.length);
Util.arrayFill(encryptedCx, (short)0, (byte)encryptedCx.length, (byte)0);
Util.arrayFill(hmac, (short)0, (byte)hmac.length, (byte)0);
Util.arrayFill(tempBuffer, (short)0, (byte)tempBuffer.length, (byte)0);
aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false);
......@@ -93,23 +97,81 @@ public class IDSecret {
Util.arrayCopy(outputBuffer, (short)0, hmac, (short)0, (short)32 );
}
private short generateExtensions(){
// 69byte <- EXTENSIONS:10 + PRLAB:5 + HMAC:4 + hmac:32 + CX:2 + cx:16
encoder.init(tempBuffer, (short)0, (short) tempBuffer.length);
encoder.startMap((short)1);
encoder.encodeTextString(Utf8Strings.UTF8_PRLab, (short)0, (short)Utf8Strings.UTF8_PRLab.length);
encoder.startMap((short)2);
encoder.encodeTextString(Utf8Strings.UTF8_HMAC, (short)0, (short)Utf8Strings.UTF8_HMAC.length);
encoder.encodeByteString(hmac, (short)0, (short)hmac.length );
encoder.encodeTextString(Utf8Strings.UTF8_Cx, (short)0, (short)Utf8Strings.UTF8_Cx.length);
encoder.encodeByteString(encryptedCx, (short)0, (short)encryptedCx.length);
return encoder.getCurrentOffset();
}
public short getExtensionsLength(){
tempBufferLength = generateExtensions();
return tempBufferLength;
}
public short getExtensionsByteString(byte[] outputBuffer, short outputOffset){
Util.arrayCopy(tempBuffer, (short)0, outputBuffer, outputOffset, tempBufferLength);
return tempBufferLength;
}
public void writeTempBuffer(byte[] inputBuffer){
if((short)inputBuffer.length > (short)tempBuffer.length){
tempBuffer[0] = 'T'; // too
tempBuffer[1] = 'L'; // long
Util.setShort(tempBuffer, (short)2, (short)inputBuffer.length); // input length
return;
}
Util.arrayCopy(inputBuffer, (short)0, tempBuffer, (short)0, (short)inputBuffer.length);
}
/**
* put IDSecret data with CBOR form in dataBuffer
* return data length
*/
public short dump(byte[] dataBuffer, CBOREncoder encoder){
encoder.init(dataBuffer, (short)0, (short)1200);
encoder.startArray((short)10);
encoder.encodeTextString(IDx.str, (short)0, IDx.len);
encoder.encodeByteString(Rx, (short)0, (short)Rx.length);
encoder.encodeByteString(Rp, (short)0, (short)Rp.length);
encoder.encodeByteString(getRxRp(), (short)0, (short)RxRp.length);
encoder.encodeByteString(PuKp, (short)0, (short)PuKp.length);
encoder.encodeByteString(sharedSecret, (short)0, (short)sharedSecret.length);
encoder.encodeByteString(hashedSharedSecret, (short)0 , (short) hashedSharedSecret.length);
encoder.encodeByteString(Cx, (short)0, (short)Cx.length);
encoder.encodeByteString(encryptedCx, (short)0, (short)encryptedCx.length);
encoder.encodeByteString(hmac, (short)0, (short)hmac.length );
encoder.startMap((short)1);
// encoder.encodeTextString(Utf8Strings.UTF8_IDx, (short)0, (short)Utf8Strings.UTF8_IDx.length);
// encoder.encodeTextString(IDx.str, (short)0, IDx.len);
//
// encoder.encodeTextString(Utf8Strings.UTF8_Rx, (short)0, (short)Utf8Strings.UTF8_Rx.length);
// encoder.encodeByteString(Rx, (short)0, (short)Rx.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_Rp, (short)0, (short)Utf8Strings.UTF8_Rp.length);
// encoder.encodeByteString(Rp, (short)0, (short)Rp.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_RxRp, (short)0, (short)Utf8Strings.UTF8_RxRp.length);
// encoder.encodeByteString(getRxRp(), (short)0, (short)RxRp.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_PuKp, (short)0, (short)Utf8Strings.UTF8_PuKp.length);
// encoder.encodeByteString(PuKp, (short)0, (short)PuKp.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_SHARED_SECRET, (short)0, (short)Utf8Strings.UTF8_SHARED_SECRET.length);
// encoder.encodeByteString(sharedSecret, (short)0, (short)sharedSecret.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_HASHED_SHARED_SECRET, (short)0, (short)Utf8Strings.UTF8_HASHED_SHARED_SECRET.length);
// encoder.encodeByteString(hashedSharedSecret, (short)0 , (short) hashedSharedSecret.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_Cx, (short)0, (short)Utf8Strings.UTF8_Cx.length);
// encoder.encodeByteString(Cx, (short)0, (short)Cx.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_ENCRYPTED_CX, (short)0, (short)Utf8Strings.UTF8_ENCRYPTED_CX.length);
// encoder.encodeByteString(encryptedCx, (short)0, (short)encryptedCx.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_HMAC, (short)0, (short)Utf8Strings.UTF8_HMAC.length);
// encoder.encodeByteString(hmac, (short)0, (short)hmac.length );
// tempBufferLength = generateExtensions();
encoder.encodeTextString(Utf8Strings.UTF8_TEMP, (short)0, (short)Utf8Strings.UTF8_TEMP.length);
encoder.encodeByteString(tempBuffer, (short)0, (short)tempBuffer.length);
return encoder.getCurrentOffset();
}
......
......@@ -9,6 +9,6 @@ public abstract class PinUvAuthProtocol {
public abstract void resetPinUvAuthToken();
public abstract byte[] getPublicKey();
public abstract byte[] decapsulate(COSEKey peerCoseKey);
public abstract void decrypt(byte[] sharedSecret, byte[] cipherText);
public abstract byte[] decrypt(byte[] sharedSecret, byte[] cipherText);
public abstract void verify(byte[] key, byte[] message, byte[] signature);
}
......@@ -2,11 +2,17 @@ package com.josh.vku2f;
import javacard.framework.JCSystem;
import javacard.security.*;
import javacardx.crypto.Cipher;
public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
private KeyPair ecDhKeyPair;
private boolean[] ecDhSet;
private AESKey aesKey;
private Cipher aesEncrypt;
private Cipher aesDecrypt;
private MessageDigest sha256;
private final byte[] IV_ZERO_AES = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@Override
public void initialize() {
......@@ -16,6 +22,13 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
JCSystem.MEMORY_TYPE_TRANSIENT_RESET, KeyBuilder.LENGTH_EC_FP_256, false);
ecDhKeyPair = new KeyPair(ecDhPub, ecDhPriv);
ecDhSet = JCSystem.makeTransientBooleanArray((short) 1, JCSystem.CLEAR_ON_RESET);
aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false);
aesEncrypt = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
aesDecrypt = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
sha256 = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
}
@Override
......@@ -65,8 +78,13 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
}
@Override
public void decrypt(byte[] sharedSecret, byte[] cipherText) {
public byte[] decrypt(byte[] key, byte[] cipherText) {
byte[] plainText = new byte[64];
aesKey.setKey(key, (short)0);
aesDecrypt.init(aesKey, Cipher.MODE_DECRYPT, IV_ZERO_AES, (short)0, (short)IV_ZERO_AES.length);
aesDecrypt.update(cipherText, (short)0, (short)32, plainText, (short)0);
aesDecrypt.doFinal(cipherText, (short)32, (short)32, plainText, (short)32);
return plainText;
}
public byte[] authenticate(byte[] key, byte[] message){
......@@ -77,10 +95,17 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
public void verify(byte[] key, byte[] message, byte[] signature) {
}
private byte[] ecdh(COSEKey peerCoseKey){
return null;
public byte[] ecdh(byte[] peerKey){
byte[] sharedKey = new byte[65];
KeyAgreement keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN_XY, false);
keyAgreement.init(ecDhKeyPair.getPrivate());
keyAgreement.generateSecret(peerKey, (short)0, (short)65, sharedKey, (short)0);
return kdf(sharedKey, (short)1);
}
private byte[] kdf(byte[] Z){
return null;
public byte[] kdf(byte[] Z, short offset){
byte[] hashed = new byte[32];
sha256.doFinal(Z, offset, (short)32, hashed, (short)0);
return hashed;
}
}
......@@ -66,8 +66,9 @@ public class StoredES256Credential extends StoredCredential {
}
((ECPublicKey) keyPair.getPublic()).getW(w, (short) 0);
// Form the common params
// Form the common params (AAGUID||key handle Length||key handle)
doAttestationCommon(buf, off);
enc.init(buf, (short) (off + 34), (short) 1000);
enc.startMap((short) 5);
// We had to kinda hack the map labels - this is kty
......
......@@ -28,6 +28,7 @@ public class Utf8Strings {
public static final byte[] UTF8_ALG = {'a', 'l', 'g'};
public static final byte[] UTF8_UV = {'u', 'v'};
public static final byte[] UTF8_RK = {'r', 'k'};
public static final byte[] UTF8_CLIENT_PIN = {'c', 'l', 'i', 'e', 'n', 't', 'P', 'i', 'n'};
public static final byte[] UTF8_TYPE = {'t', 'y', 'p', 'e'};
public static final byte[] UTF8_PACKED = {'p', 'a', 'c', 'k', 'e', 'd'};
public static final byte[] UTF8_SIG = {'s', 'i', 'g'};
......@@ -37,7 +38,18 @@ public class Utf8Strings {
public static final byte[] UTF8_ICON = {'i', 'c', 'o', 'n'};
public static final byte[] UTF8_NULL = {'n', 'u', 'l', 'l'};
public static final byte[] UTF8_EXTENSIONS = {'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's'};
public static final byte[] UTF8_PRLab = {'P', 'R', 'L', 'a', 'b'};
public static final byte[] UTF8_credProtect = {'c','r','e','d','P','r','o','t','e','c','t'};
public static final byte[] UTF8_HMAC = {'H', 'M', 'A', 'C'};
public static final byte[] UTF8_Cx = {'C', 'x'};
public static final byte[] UTF8_IDx = {'I', 'D', 'x'};
public static final byte[] UTF8_Rx = {'R', 'x'};
public static final byte[] UTF8_Rp = {'R', 'p'};
public static final byte[] UTF8_RxRp = {'R', 'x', 'R', 'p'};
public static final byte[] UTF8_PuKp = {'P', 'u', 'K', 'p'};
public static final byte[] UTF8_SHARED_SECRET = {'S', 'h', 'a', 'r', 'e', 'd', 'S', 'e', 'c', 'r', 'e', 't'};
public static final byte[] UTF8_HASHED_SHARED_SECRET = {'H', 'a', 's', 'h', 'e', 'd', 'S', 'h', 'a', 'r', 'e', 'd', 'S', 'e', 'c', 'r', 'e', 't'};
public static final byte[] UTF8_ENCRYPTED_CX = {'E', 'n', 'c', 'r', 'y', 'p', 't', 'e', 'd', 'C', 'x', };
public static final byte[] UTF8_TEMP = {'T', 'E', 'M', 'P'};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment