Commit c9d0b00a authored by Josh Ji's avatar Josh Ji

setPin, getPinToken, usePinToken and some dummy or unnecessary stuff while testing and debugging

parent fc423e41
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -26,6 +26,7 @@ public class AuthenticatorGetAssertion { ...@@ -26,6 +26,7 @@ public class AuthenticatorGetAssertion {
byte[] clientDataHash; byte[] clientDataHash;
boolean[] options; boolean[] options;
PublicKeyCredentialDescriptor[] allow; PublicKeyCredentialDescriptor[] allow;
private byte[] pinUvAuthParam;
public AuthenticatorGetAssertion(CBORDecoder decoder) throws UserException { public AuthenticatorGetAssertion(CBORDecoder decoder) throws UserException {
...@@ -117,8 +118,10 @@ public class AuthenticatorGetAssertion { ...@@ -117,8 +118,10 @@ public class AuthenticatorGetAssertion {
decoder.skipEntry(); decoder.skipEntry();
break; break;
case 0x06: case 0x06:
// Pin stuff // Pin UV Auth Param // 0x06
decoder.skipEntry(); pinUvAuthParam = new byte[16];
if(decoder.readByteString(pinUvAuthParam, (short)0 ) < (short)16)
UserException.throwIt(CTAP2_ERR_PIN_INVALID);
break; break;
case 0x07: case 0x07:
// Pin protocol // Pin protocol
......
...@@ -27,6 +27,7 @@ public class AuthenticatorMakeCredential { ...@@ -27,6 +27,7 @@ public class AuthenticatorMakeCredential {
private PublicKeyCredentialUserEntity user; private PublicKeyCredentialUserEntity user;
private PublicKeyCredentialParams params; private PublicKeyCredentialParams params;
private boolean[] options = new boolean[2]; private boolean[] options = new boolean[2];
private byte[] pinUvAuthParam;
public PublicKeyCredentialDescriptor[] exclude; public PublicKeyCredentialDescriptor[] exclude;
...@@ -282,6 +283,14 @@ public class AuthenticatorMakeCredential { ...@@ -282,6 +283,14 @@ public class AuthenticatorMakeCredential {
} }
decoder.skipEntry(); decoder.skipEntry();
break; break;
case (short)8: // pinUvAuthToken
pinUvAuthParam = new byte[16];
if(decoder.readByteString(pinUvAuthParam, (short)0 ) < (short)16)
UserException.throwIt(CTAP2_ERR_PIN_INVALID);
break;
case (short)9: // pinProtocol
short pinProtocol = decoder.readInt8();
break;
default: default:
// Skip it transparently // Skip it transparently
decoder.skipEntry(); decoder.skipEntry();
...@@ -290,12 +299,16 @@ public class AuthenticatorMakeCredential { ...@@ -290,12 +299,16 @@ public class AuthenticatorMakeCredential {
} }
}
if(pinUvAuthParam == null){
UserException.throwIt(CTAP2_ERR_PIN_INVALID);
} }
// Check we've got stuff like the clientDataHash // Check we've got stuff like the clientDataHash
if(dataHash == null || rp == null || user == null || params == null) { if(dataHash == null || rp == null || user == null || params == null) {
UserException.throwIt(CTAP2_ERR_MISSING_PARAMETER); UserException.throwIt(CTAP2_ERR_MISSING_PARAMETER);
} }
// We're done, I guess // We're done, I guess
} }
...@@ -319,6 +332,14 @@ public class AuthenticatorMakeCredential { ...@@ -319,6 +332,14 @@ public class AuthenticatorMakeCredential {
return (exclude != null && exclude.length > 0); return (exclude != null && exclude.length > 0);
} }
/**
*
* @return pinUvAuthToken
*/
public byte[] getPinUvAuthParam(){
return pinUvAuthParam;
}
/** /**
* Reads the clientDataHash into a buffer. * Reads the clientDataHash into a buffer.
* *
...@@ -326,9 +347,8 @@ public class AuthenticatorMakeCredential { ...@@ -326,9 +347,8 @@ public class AuthenticatorMakeCredential {
* @param outOff the offset to begin at. * @param outOff the offset to begin at.
* @return the length of the data read out. * @return the length of the data read out.
*/ */
public short getDataHash(byte[] outBuf, short outOff) { public byte[] getDataHash() {
Util.arrayCopy(dataHash, (short) 0, outBuf, outOff, (short) dataHash.length); return dataHash;
return (short) dataHash.length;
} }
} }
...@@ -66,6 +66,10 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -66,6 +66,10 @@ public class CTAP2 extends Applet implements ExtendedLength {
// private final KeyPair ecDhKeyPair; // private final KeyPair ecDhKeyPair;
// private final boolean[] ecDhSet; // private final boolean[] ecDhSet;
private PinUvAuthProtocolOne pinUvAuthProtocolOne; private PinUvAuthProtocolOne pinUvAuthProtocolOne;
private short pinLength = 0;
private byte[] pin;
private final byte[] currentStoredPIN = new byte[16]; // LEFT(SHA-256(pin), 16)
private final byte[] pinToken = new byte[32];
// INS // INS
...@@ -101,9 +105,9 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -101,9 +105,9 @@ public class CTAP2 extends Applet implements ExtendedLength {
// this uniquely identifies the type of authenticator we have built. // this uniquely identifies the type of authenticator we have built.
// If you're reusing this code, please generate your own GUID and put it here - // If you're reusing this code, please generate your own GUID and put it here -
// this is unique to manufacturer and device model. // this is unique to manufacturer and device model.
public static final byte[] aaguid = { public static final byte[] aaguid = {//yubikey 5c nfc aaguid
(byte) 't', (byte) 'e', (byte) 's', (byte) 't', (byte) 'g', (byte) 'u', (byte) 'i', (byte) 'd', (byte) 0x2f, (byte) 0xc0, (byte) 0x57, (byte) 0x9f, (byte) 0x81, (byte) 0x13, (byte) 0x47, (byte) 0xea,
(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; (byte) 0xb1, (byte) 0x16, (byte) 0xbb, (byte) 0x5a, (byte) 0x8d, (byte) 0xb9, (byte) 0x20, (byte) 0x2a, };
private CTAP2() { private CTAP2() {
...@@ -162,11 +166,11 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -162,11 +166,11 @@ public class CTAP2 extends Applet implements ExtendedLength {
public void process(APDU apdu) throws ISOException { public void process(APDU apdu) throws ISOException {
byte[] buffer = apdu.getBuffer(); byte[] buffer = apdu.getBuffer();
// return FIDO2 String when selecting // return version String when selecting
if (selectingApplet()) { if (selectingApplet()) {
Util.arrayCopyNonAtomic(Utf8Strings.UTF8_FIDO2, (short) 0, buffer, (short) 0, Util.arrayCopyNonAtomic(Utf8Strings.UTF8_U2F_V2, (short) 0, buffer, (short) 0,
(short) Utf8Strings.UTF8_FIDO2.length); (short) Utf8Strings.UTF8_U2F_V2.length);
apdu.setOutgoingAndSend((short) 0, (short) Utf8Strings.UTF8_FIDO2.length); apdu.setOutgoingAndSend((short) 0, (short) Utf8Strings.UTF8_U2F_V2.length);
return; return;
} }
...@@ -486,6 +490,11 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -486,6 +490,11 @@ public class CTAP2 extends Applet implements ExtendedLength {
} }
public void authMakeCredential(APDU apdu, short bufLen) { public void authMakeCredential(APDU apdu, short bufLen) {
if(pinRetries < (short)1){
returnError(apdu, CTAP2_ERR_PIN_AUTH_BLOCKED);
return;
}
// Init the decoder // Init the decoder
cborDecoder.init(dataBuffer, (short) 1, bufLen); cborDecoder.init(dataBuffer, (short) 1, bufLen);
// create a credential object // create a credential object
...@@ -512,8 +521,25 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -512,8 +521,25 @@ public class CTAP2 extends Applet implements ExtendedLength {
return; return;
} }
if (authenticatorMakeCredential.isResident()) { if (authenticatorMakeCredential.isResident()) {
// Check if a credential exists on the excluded list idSecret.writeTempBuffer(pinUvAuthProtocolOne.authenticate(pinToken, authenticatorMakeCredential.getDataHash()), (short)0);
idSecret.writeTempBuffer(authenticatorMakeCredential.getPinUvAuthParam(), (short)64);
// verify the pin UV Auth token
if(pinUvAuthProtocolOne.verify(
pinToken,
authenticatorMakeCredential.getDataHash(),
authenticatorMakeCredential.getPinUvAuthParam()
)
){
pinRetries = MAX_PIN_RETRIES;
}else{
pinRetries--;
returnError(apdu, CTAP2_ERR_PIN_AUTH_INVALID);
return;
}
// Check if a credential exists on the excluded list
if (authenticatorMakeCredential.isExclude() && isPresent(authenticatorMakeCredential.exclude)) { if (authenticatorMakeCredential.isExclude() && isPresent(authenticatorMakeCredential.exclude)) {
// Throw the error // Throw the error
returnError(apdu, CTAP2_ERR_CREDENTIAL_EXCLUDED); returnError(apdu, CTAP2_ERR_CREDENTIAL_EXCLUDED);
...@@ -731,14 +757,15 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -731,14 +757,15 @@ public class CTAP2 extends Applet implements ExtendedLength {
switch(clientPINCommand.getSubCommandCode()){ switch(clientPINCommand.getSubCommandCode()){
case SUBCOMMAND_GET_PIN_RETRIES: case SUBCOMMAND_GET_PIN_RETRIES:
dataBuffer[0] = 0x00; // 0x00 : response success code dataBuffer[0] = CTAP1_ERR_SUCCESS; // 0x00 : response success code
cborEncoder.init(dataBuffer, (short)1, (short)(1199)); cborEncoder.init(dataBuffer, (short)1, (short)(1199));
cborEncoder.startMap((short)1); cborEncoder.startMap((short)1);
cborEncoder.encodeUInt8(ClientPINResponse.PIN_RETRIES); cborEncoder.encodeUInt8(ClientPINResponse.PIN_RETRIES);
cborEncoder.encodeUInt8(pinRetries); cborEncoder.encodeUInt8(pinRetries);
sendLongChaining(apdu, cborEncoder.getCurrentOffset());
break; break;
case SUBCOMMAND_GET_KEY_AGREEMENT: case SUBCOMMAND_GET_KEY_AGREEMENT:
dataBuffer[0] = 0x00; // 0x00 : response success code dataBuffer[0] = CTAP1_ERR_SUCCESS; // 0x00 : response success code
cborEncoder.init(dataBuffer, (short) 1, (short) 1199); cborEncoder.init(dataBuffer, (short) 1, (short) 1199);
// Start a map // Start a map
cborEncoder.startMap((short) 1); cborEncoder.startMap((short) 1);
...@@ -771,21 +798,66 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -771,21 +798,66 @@ public class CTAP2 extends Applet implements ExtendedLength {
sendLongChaining(apdu, cborEncoder.getCurrentOffset()); sendLongChaining(apdu, cborEncoder.getCurrentOffset());
break; break;
case SUBCOMMAND_SET_PIN: case SUBCOMMAND_SET_PIN:
// idSecret.writeTempBuffer(pinUvAuthProtocolOne.ecdh(clientPINCommand.getKeyAgreement())); byte[] paddedPin = pinUvAuthProtocolOne.decrypt(
idSecret.writeTempBuffer( pinUvAuthProtocolOne.ecdh(clientPINCommand.getKeyAgreement()),
pinUvAuthProtocolOne.decrypt(
pinUvAuthProtocolOne.ecdh(
clientPINCommand.getKeyAgreement()),
clientPINCommand.getNewPinEnc() clientPINCommand.getNewPinEnc()
) );
);
for(short i = 0 ; i < (short)paddedPin.length ; i ++){
if(paddedPin[i] == 0x00) {
pinLength = i;
break;
}
}
pin = new byte[pinLength];
Util.arrayCopy(paddedPin, (short)0, pin, (short)0, (short)pin.length);
// idSecret.writeTempBuffer(pin, (short)0);
byte[] hashedPin = pinUvAuthProtocolOne.hashPin(pin);
Util.arrayCopy(hashedPin, (short)0, currentStoredPIN, (short)0, (short)16);
// idSecret.writeTempBuffer(currentStoredPIN, (short)10);
isClientPinSet = true; isClientPinSet = true;
fidoInfo = null; fidoInfo = null;
pinRetries = MAX_PIN_RETRIES;
JCSystem.requestObjectDeletion(); JCSystem.requestObjectDeletion();
break; break;
case SUBCOMMAND_CHANGE_PIN: case SUBCOMMAND_CHANGE_PIN:
break; break;
case SUBCOMMAND_GET_PIN_TOKEN: case SUBCOMMAND_GET_PIN_TOKEN:
byte[] hashedPin_leftHalf;
byte[] sharedSecret = pinUvAuthProtocolOne.ecdh(clientPINCommand.getKeyAgreement());
hashedPin_leftHalf = pinUvAuthProtocolOne.decryptHashedPin(
sharedSecret, clientPINCommand.getPinHashEnc()
);
// idSecret.writeTempBuffer(hashedPin_leftHalf, (short)36);
for(short i = 0; i < (short)hashedPin_leftHalf.length ; i++){
if(hashedPin_leftHalf[i] != currentStoredPIN[i]){
pinRetries--;
UserException.throwIt(CTAP2_ERR_PIN_INVALID);
break;
}
}
RandomData r = Random.getInstance();
r.nextBytes(pinToken, (short)0, (short)pinToken.length);
// idSecret.writeTempBuffer(pinToken, (short) 0);
byte[] pinTokenEnc = pinUvAuthProtocolOne.encrypt(sharedSecret, pinToken);
dataBuffer[0] = CTAP1_ERR_SUCCESS;
cborEncoder.init(dataBuffer, (short)1, (short)1199);
cborEncoder.startMap((short)1);
cborEncoder.encodeUInt8((byte)0x02);
cborEncoder.encodeByteString(pinTokenEnc, (short)0, (short)32);
sendLongChaining(apdu, cborEncoder.getCurrentOffset());
break; break;
case SUBCOMMAND_GET_PIN_UV_AUTH_TOKEN_UV: case SUBCOMMAND_GET_PIN_UV_AUTH_TOKEN_UV:
break; break;
...@@ -944,40 +1016,57 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -944,40 +1016,57 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Create the authGetInfo - 0x00 is success // Create the authGetInfo - 0x00 is success
dataBuffer[0] = 0x00; dataBuffer[0] = 0x00;
cborEncoder.init(dataBuffer, (short) 1, (short) 1199); cborEncoder.init(dataBuffer, (short) 1, (short) 1199);
cborEncoder.startMap((short) 6); cborEncoder.startMap((short) 8);
// 0x01, versions // 0x01, versions
cborEncoder.encodeUInt8((byte) 0x01); cborEncoder.encodeUInt8((byte) 0x01);
// Value is an array of strings // Value is an array of strings
cborEncoder.startArray((short) 1); cborEncoder.startArray((short) 2);
// Type 1, FIDO2 // Type 1, FIDO2
cborEncoder.encodeTextString(Utf8Strings.UTF8_FIDO2, (short) 0, (short) 8); cborEncoder.encodeTextString(Utf8Strings.UTF8_FIDO2, (short) 0, (short) Utf8Strings.UTF8_FIDO2.length);
cborEncoder.encodeTextString(Utf8Strings.UTF8_FIDO_2_1_PRE, (short) 0, (short) Utf8Strings.UTF8_FIDO_2_1_PRE.length);
// 0x02, Extensions // 0x02, Extensions
cborEncoder.encodeUInt8((byte) 0x02); cborEncoder.encodeUInt8((byte) 0x02);
cborEncoder.startArray((short) 2); cborEncoder.startArray((short) 2);
cborEncoder.encodeTextString(Utf8Strings.UTF8_PRLab, (short)0, (short)Utf8Strings.UTF8_PRLab.length);
cborEncoder.encodeTextString(Utf8Strings.UTF8_credProtect, (short)0, (short)Utf8Strings.UTF8_credProtect.length); cborEncoder.encodeTextString(Utf8Strings.UTF8_credProtect, (short)0, (short)Utf8Strings.UTF8_credProtect.length);
cborEncoder.encodeTextString(Utf8Strings.UTF8_hmac_secret, (short)0, (short)Utf8Strings.UTF8_hmac_secret.length);
// cborEncoder.encodeTextString(Utf8Strings.UTF8_PRLab, (short)0, (short)Utf8Strings.UTF8_PRLab.length);
// 0x03, AAGUID, // 0x03, AAGUID,
cborEncoder.encodeUInt8((byte) 0x03); cborEncoder.encodeUInt8((byte) 0x03);
cborEncoder.encodeByteString(aaguid, (short) 0, (short) 16); cborEncoder.encodeByteString(aaguid, (short) 0, (short) 16);
// 0x04, Options, // 0x04, Options,
cborEncoder.encodeUInt8((byte) 0x04); cborEncoder.encodeUInt8((byte) 0x04);
// Map of 3 // Map of 3
cborEncoder.startMap((short) 4); cborEncoder.startMap((short) 5);
// Rk // Rk
cborEncoder.encodeTextString(Utf8Strings.UTF8_RK, (short) 0, (short)Utf8Strings.UTF8_RK.length); cborEncoder.encodeTextString(Utf8Strings.UTF8_RK, (short) 0, (short)Utf8Strings.UTF8_RK.length);
cborEncoder.encodeBoolean(true); cborEncoder.encodeBoolean(true);
// UP // UP
cborEncoder.encodeTextString(Utf8Strings.UTF8_UP, (short) 0, (short)Utf8Strings.UTF8_UP.length); cborEncoder.encodeTextString(Utf8Strings.UTF8_UP, (short) 0, (short)Utf8Strings.UTF8_UP.length);
cborEncoder.encodeBoolean(true); cborEncoder.encodeBoolean(true);
// // UV
// cborEncoder.encodeTextString(Utf8Strings.UTF8_UV, (short) 0, (short)Utf8Strings.UTF8_UV.length);
// cborEncoder.encodeBoolean(true);
// plat
cborEncoder.encodeTextString(Utf8Strings.UTF8_plat, (short) 0, (short)Utf8Strings.UTF8_plat.length);
cborEncoder.encodeBoolean(false);
// clientPin // clientPin
cborEncoder.encodeTextString(Utf8Strings.UTF8_CLIENT_PIN, (short) 0, (short)Utf8Strings.UTF8_CLIENT_PIN.length); cborEncoder.encodeTextString(Utf8Strings.UTF8_CLIENT_PIN, (short) 0, (short)Utf8Strings.UTF8_CLIENT_PIN.length);
cborEncoder.encodeBoolean(isClientPinSet); cborEncoder.encodeBoolean(isClientPinSet);
// UV // credentialMgmtPreview
cborEncoder.encodeTextString(Utf8Strings.UTF8_UV, (short) 0, (short)Utf8Strings.UTF8_UV.length); cborEncoder.encodeTextString(Utf8Strings.UTF8_CREDENTIAL_MGMT_PREVIEW, (short) 0, (short)Utf8Strings.UTF8_CREDENTIAL_MGMT_PREVIEW.length);
cborEncoder.encodeBoolean(true); cborEncoder.encodeBoolean(true);
// Max msg size, 0x05 // Max msg size, 0x05
cborEncoder.encodeUInt8((byte) 0x05); cborEncoder.encodeUInt8((byte) 0x05);
cborEncoder.encodeUInt16((short) 1200); cborEncoder.encodeUInt16((short) 1200);
// pin Protocols, 0x06
cborEncoder.encodeUInt8((byte) 0x06);
cborEncoder.startArray((short)0x01);
cborEncoder.encodeUInt8((byte) 0x01);
// transports, 0x09
cborEncoder.encodeUInt8((byte) 0x09);
cborEncoder.startArray((short)0x02);
cborEncoder.encodeTextString(Utf8Strings.UTF8_nfc, (short) 0, (short)Utf8Strings.UTF8_nfc.length);
cborEncoder.encodeTextString(Utf8Strings.UTF8_usb, (short) 0, (short)Utf8Strings.UTF8_usb.length);
// minPINLength, 0x0D // minPINLength, 0x0D
cborEncoder.encodeUInt8((byte) 0x0D); cborEncoder.encodeUInt8((byte) 0x0D);
cborEncoder.encodeUInt8((byte) 0x04); cborEncoder.encodeUInt8((byte) 0x04);
......
...@@ -21,7 +21,7 @@ public class ClientPINCommand { ...@@ -21,7 +21,7 @@ public class ClientPINCommand {
private byte[] y = new byte[32]; // y-coordinate private byte[] y = new byte[32]; // y-coordinate
private byte[] pinUvAuthParam = new byte[64]; // byte string private byte[] pinUvAuthParam = new byte[64]; // byte string
private byte[] newPinEnc = new byte[64]; // byte string private byte[] newPinEnc = new byte[64]; // byte string
private byte[] pinHashEnc = new byte[32]; // byte string private byte[] pinHashEnc = new byte[16]; // byte string, aes256
private byte permissions; // unsigned int private byte permissions; // unsigned int
private byte[] rpId = new byte[64]; // text string private byte[] rpId = new byte[64]; // text string
byte[] scratch = JCSystem.makeTransientByteArray((short)64, JCSystem.CLEAR_ON_RESET); byte[] scratch = JCSystem.makeTransientByteArray((short)64, JCSystem.CLEAR_ON_RESET);
...@@ -61,15 +61,15 @@ public class ClientPINCommand { ...@@ -61,15 +61,15 @@ public class ClientPINCommand {
break; break;
case PARAMETER_PIN_UV_AUTH_PARAM: case PARAMETER_PIN_UV_AUTH_PARAM:
// cborDecoder.readByteString(pinUvAuthParam, (short) 0); cborDecoder.readByteString(pinUvAuthParam, (short) 0);
cborDecoder.skipEntry(); // cborDecoder.skipEntry();
break; break;
case PARAMETER_NEW_PIN_ENC: case PARAMETER_NEW_PIN_ENC:
cborDecoder.readByteString(newPinEnc, (short) 0); cborDecoder.readByteString(newPinEnc, (short) 0);
break; break;
case PARAMETER_PIN_HASH_ENC: case PARAMETER_PIN_HASH_ENC:
// cborDecoder.readByteString(pinHashEnc, (short) 0); cborDecoder.readByteString(pinHashEnc, (short) 0);
cborDecoder.skipEntry(); // cborDecoder.skipEntry();
break; break;
case PARAMETER_PERMISSIONS: case PARAMETER_PERMISSIONS:
// permissions = cborDecoder.readInt8(); // permissions = cborDecoder.readInt8();
...@@ -93,6 +93,10 @@ public class ClientPINCommand { ...@@ -93,6 +93,10 @@ public class ClientPINCommand {
return subCommandCode; return subCommandCode;
} }
/**
*
* @return 0x04 || x-coordinate || y-coordinate
*/
public byte[] getKeyAgreement() { public byte[] getKeyAgreement() {
keyAgreement[0] = 0x04; keyAgreement[0] = 0x04;
Util.arrayCopy(x, (short)0, keyAgreement, (short)1, (short)x.length); Util.arrayCopy(x, (short)0, keyAgreement, (short)1, (short)x.length);
......
...@@ -121,14 +121,19 @@ public class IDSecret { ...@@ -121,14 +121,19 @@ public class IDSecret {
return tempBufferLength; return tempBufferLength;
} }
public void writeTempBuffer(byte[] inputBuffer){ /**
if((short)inputBuffer.length > (short)tempBuffer.length){ *
* @param inputBuffer the buffer copy from
* @param offset output offset
*/
public void writeTempBuffer(byte[] inputBuffer, short offset){
if((short)(inputBuffer.length + offset) > (short)tempBuffer.length){
tempBuffer[0] = 'T'; // too tempBuffer[0] = 'T'; // too
tempBuffer[1] = 'L'; // long tempBuffer[1] = 'L'; // long
Util.setShort(tempBuffer, (short)2, (short)inputBuffer.length); // input length Util.setShort(tempBuffer, (short)2, (short)inputBuffer.length); // input length
return; return;
} }
Util.arrayCopy(inputBuffer, (short)0, tempBuffer, (short)0, (short)inputBuffer.length); Util.arrayCopy(inputBuffer, (short)0, tempBuffer, offset, (short)inputBuffer.length);
} }
/** /**
......
...@@ -10,5 +10,5 @@ public abstract class PinUvAuthProtocol { ...@@ -10,5 +10,5 @@ public abstract class PinUvAuthProtocol {
public abstract byte[] getPublicKey(); public abstract byte[] getPublicKey();
public abstract byte[] decapsulate(COSEKey peerCoseKey); public abstract byte[] decapsulate(COSEKey peerCoseKey);
public abstract byte[] decrypt(byte[] sharedSecret, byte[] cipherText); public abstract byte[] decrypt(byte[] sharedSecret, byte[] cipherText);
public abstract void verify(byte[] key, byte[] message, byte[] signature); public abstract boolean verify(byte[] key, byte[] message, byte[] signature);
} }
package com.josh.vku2f; package com.josh.vku2f;
import javacard.framework.JCSystem; import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.*; import javacard.security.*;
import javacardx.crypto.Cipher; import javacardx.crypto.Cipher;
import jdk.nashorn.internal.ir.Block;
public class PinUvAuthProtocolOne extends PinUvAuthProtocol{ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
...@@ -73,8 +75,20 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{ ...@@ -73,8 +75,20 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
return null; return null;
} }
/**
*
* @param key shared key from kdf()
* @param plaintext pinToken
* @return encrypted pinToken
*/
public byte[] encrypt(byte[] key, byte[] plaintext){ public byte[] encrypt(byte[] key, byte[] plaintext){
return null; byte[] cipherText = new byte[32];
aesKey.setKey(key, (short)0);
aesEncrypt.init(aesKey, Cipher.MODE_ENCRYPT, IV_ZERO_AES, (short)0, (short)IV_ZERO_AES.length);
aesEncrypt.update(plaintext, (short)0, (short)16, cipherText, (short)0);
aesEncrypt.doFinal(plaintext, (short)16, (short)16, cipherText, (short)16);
return cipherText;
} }
@Override @Override
...@@ -87,13 +101,45 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{ ...@@ -87,13 +101,45 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
return plainText; return plainText;
} }
/**
*
* @param key the key output from kdf()
* @param cipherText encrypted hashedPin
* @return hashed pin
*/
public byte[] decryptHashedPin(byte[] key, byte[] cipherText) {
byte[] hashedPin = new byte[16];
aesKey.setKey(key, (short)0);
aesDecrypt.init(aesKey, Cipher.MODE_DECRYPT, IV_ZERO_AES, (short)0, (short)IV_ZERO_AES.length);
aesDecrypt.doFinal(cipherText, (short)0, (short)16, hashedPin, (short)0);
return hashedPin;
}
/**
*
* @param key pinToken : 32 bytes
* @param message clientDataHash : 32 bytes
* @return signature
*/
public byte[] authenticate(byte[] key, byte[] message){ public byte[] authenticate(byte[] key, byte[] message){
return null; return hmac256(key, message);
} }
/**
*
* @param key pinToken 32 bytes
* @param message clientDataHash 32 bytes
* @param signature pinUvAuthToken 16 bytes : LEFT(hmac-sha-256(pinToken, clientDataHash), 16)
* @return boolean result
*/
@Override @Override
public void verify(byte[] key, byte[] message, byte[] signature) { public boolean verify(byte[] key, byte[] message, byte[] signature) {
byte[] authenticate = authenticate(key, message);
for(short i = 0; i < (short)signature.length; i++){
if(authenticate[i] != signature[i])
return false;
}
return true;
} }
public byte[] ecdh(byte[] peerKey){ public byte[] ecdh(byte[] peerKey){
...@@ -103,9 +149,71 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{ ...@@ -103,9 +149,71 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
keyAgreement.generateSecret(peerKey, (short)0, (short)65, sharedKey, (short)0); keyAgreement.generateSecret(peerKey, (short)0, (short)65, sharedKey, (short)0);
return kdf(sharedKey, (short)1); return kdf(sharedKey, (short)1);
} }
/**
*
* @param Z shared key from ecdh
* @param offset where the x-coordinate begin
* @return derivative key
*/
public byte[] kdf(byte[] Z, short offset){ public byte[] kdf(byte[] Z, short offset){
byte[] hashed = new byte[32]; byte[] hashed = new byte[32];
sha256.reset();
sha256.doFinal(Z, offset, (short)32, hashed, (short)0); sha256.doFinal(Z, offset, (short)32, hashed, (short)0);
return hashed; return hashed;
} }
/**
*
* @param pin pin
* @return hashed pin
*/
public byte[] hashPin(byte[] pin){
byte[] hashedPin = new byte[32];
sha256.reset();
sha256.doFinal(pin, (short)0, (short)pin.length, hashedPin, (short)0);
return hashedPin;
}
/**
*
* @param key key must <= 64 bytes
* @param message message must <= 32 bytes
* @return hmac
*/
public byte[] hmac256(byte[] key, byte[] message){
short BLOCKSIZE=64; // 512 bits
short HASHSIZE=32; // 256 bits
byte[] hashed = new byte[HASHSIZE];
byte[] hmacBuffer = new byte[(short)(BLOCKSIZE + hashed.length)];
for (short i=0; i < (short)key.length; i++){
hmacBuffer[i]= (byte) (key[i] ^ (0x36));
}
Util.arrayFillNonAtomic(hmacBuffer, (short)key.length, (short)(BLOCKSIZE-key.length), (byte)0x36); // ipad
Util.arrayCopyNonAtomic(message, (short)0, hmacBuffer, BLOCKSIZE, (short)message.length);
sha256.update(hmacBuffer, (short)0, HASHSIZE);
sha256.update(hmacBuffer, (short)32, HASHSIZE);
sha256.doFinal(hmacBuffer, BLOCKSIZE, (short)(message.length), hashed, (short)0);
for (short i=0; i< (short)key.length; i++){
hmacBuffer[i]= (byte) (key[i] ^ (0x5c));
}
Util.arrayFillNonAtomic(hmacBuffer, (short)key.length, (short)(BLOCKSIZE - key.length), (byte)0x5c); // opad
Util.arrayCopy(hashed, (short)0, hmacBuffer, BLOCKSIZE, (short)hashed.length);
sha256.update(hmacBuffer, (short)0, HASHSIZE);
sha256.update(hmacBuffer, (short)32, HASHSIZE);
sha256.doFinal(hmacBuffer, BLOCKSIZE, (short)(hashed.length), hashed, (short)0);
return hashed;
}
} }
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
package com.josh.vku2f; package com.josh.vku2f;
public class Utf8Strings { public class Utf8Strings {
public static final byte[] UTF8_UP = {'u', 'p'};
// Representation of "id" in UTF8 // Representation of "id" in UTF8
public static final byte[] UTF8_ID = {'i', 'd'}; public static final byte[] UTF8_ID = {'i', 'd'};
// Representation of "name" in UTF8 // Representation of "name" in UTF8
...@@ -26,20 +25,28 @@ public class Utf8Strings { ...@@ -26,20 +25,28 @@ public class Utf8Strings {
public static final byte[] UTF8_DISPLAYNAME = {'d', 'i', 's', 'p', 'l', 'a', 'y', 'n', 'a', 'm', 'e'}; public static final byte[] UTF8_DISPLAYNAME = {'d', 'i', 's', 'p', 'l', 'a', 'y', 'n', 'a', 'm', 'e'};
// Representation of "alg" in UTF8 // Representation of "alg" in UTF8
public static final byte[] UTF8_ALG = {'a', 'l', 'g'}; 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_RK = {'r', 'k'};
public static final byte[] UTF8_UP = {'u', 'p'};
public static final byte[] UTF8_UV = {'u', 'v'};
public static final byte[] UTF8_plat = {'p', 'l', 'a', 't'};
public static final byte[] UTF8_CLIENT_PIN = {'c', 'l', 'i', 'e', 'n', 't', 'P', 'i', 'n'}; public static final byte[] UTF8_CLIENT_PIN = {'c', 'l', 'i', 'e', 'n', 't', 'P', 'i', 'n'};
public static final byte[] UTF8_CREDENTIAL_MGMT_PREVIEW = {'c', 'r', 'e', 'd', 'e', 'n', 't', 'i', 'a', 'l', 'M', 'g', 'm', 't', 'P', 'r', 'e', 'v', 'i', 'e', 'w', };
public static final byte[] UTF8_nfc = {'n', 'f', 'c'};
public static final byte[] UTF8_usb = {'u', 's', 'b'};
public static final byte[] UTF8_TYPE = {'t', 'y', 'p', 'e'}; 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_PACKED = {'p', 'a', 'c', 'k', 'e', 'd'};
public static final byte[] UTF8_SIG = {'s', 'i', 'g'}; public static final byte[] UTF8_SIG = {'s', 'i', 'g'};
public static final byte[] UTF8_X5C = {'x', '5', 'c'}; public static final byte[] UTF8_X5C = {'x', '5', 'c'};
public static final byte[] UTF8_PUBLIC_KEY = {'p', 'u', 'b', 'l', 'i', 'c', '-', 'k', 'e', 'y'}; public static final byte[] UTF8_PUBLIC_KEY = {'p', 'u', 'b', 'l', 'i', 'c', '-', 'k', 'e', 'y'};
public static final byte[] UTF8_U2F_V2 = {'U', '2', 'F', '_', 'V', '2'};
public static final byte[] UTF8_FIDO2 = {'F', 'I', 'D', 'O', '_', '2', '_', '0'}; public static final byte[] UTF8_FIDO2 = {'F', 'I', 'D', 'O', '_', '2', '_', '0'};
public static final byte[] UTF8_FIDO_2_1_PRE = {'F', 'I', 'D', 'O', '_', '2', '_', '1', '_', 'P', 'R', 'E'};
public static final byte[] UTF8_ICON = {'i', 'c', 'o', 'n'}; 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_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_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_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_credProtect = {'c','r','e','d','P','r','o','t','e','c','t'};
public static final byte[] UTF8_hmac_secret = {'h','m','a','c','-','s','e','c','r','e','t'};
public static final byte[] UTF8_HMAC = {'H', 'M', 'A', 'C'}; public static final byte[] UTF8_HMAC = {'H', 'M', 'A', 'C'};
public static final byte[] UTF8_Cx = {'C', 'x'}; public static final byte[] UTF8_Cx = {'C', 'x'};
public static final byte[] UTF8_IDx = {'I', 'D', 'x'}; public static final byte[] UTF8_IDx = {'I', 'D', 'x'};
......
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