Commit 57224772 authored by Josh Ji's avatar Josh Ji

code review, change version string, change aaguid, remove redundant flag in...

code review, change version string, change aaguid, remove redundant flag in the response of info command, rename project
parent c9d0b00a
#Mon Dec 06 04:06:59 CST 2021
gradle.version=7.1
newJavaCardApplet
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
<bytecodeTargetLevel target="11" />
</component>
</project>
\ No newline at end of file
......@@ -4,7 +4,7 @@
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
rootProject.name = 'newJavaCardApplet'
rootProject.name = 'Fido2Applet'
/*
**
** Copyright 2021, VivoKey Technologies
**
** 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" BASIS,
** 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.
*/
**
** Copyright 2021, VivoKey Technologies
**
** 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" BASIS,
** 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.josh.vku2f;
......@@ -63,7 +63,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
private final byte MAX_UV_RETRIES = (byte) 0x08;
private byte pinRetries = MAX_PIN_RETRIES;
private byte uvRetries = MAX_UV_RETRIES;
// private final KeyPair ecDhKeyPair;
// private final KeyPair ecDhKeyPair;
// private final boolean[] ecDhSet;
private PinUvAuthProtocolOne pinUvAuthProtocolOne;
private short pinLength = 0;
......@@ -105,9 +105,9 @@ public class CTAP2 extends Applet implements ExtendedLength {
// 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 -
// this is unique to manufacturer and device model.
public static final byte[] aaguid = {//yubikey 5c nfc aaguid
(byte) 0x2f, (byte) 0xc0, (byte) 0x57, (byte) 0x9f, (byte) 0x81, (byte) 0x13, (byte) 0x47, (byte) 0xea,
(byte) 0xb1, (byte) 0x16, (byte) 0xbb, (byte) 0x5a, (byte) 0x8d, (byte) 0xb9, (byte) 0x20, (byte) 0x2a, };
public static final byte[] aaguid = {
(byte) 't', (byte) 'e', (byte) 's', (byte) 't', (byte) 'a', (byte) 'a', (byte) 'g', (byte) 'u',
(byte) 'i', (byte) 'd', (byte) 'p', (byte) 'r', (byte) 'l', (byte) 'a', (byte) 'b', (byte) '_',};
private CTAP2() {
......@@ -168,9 +168,9 @@ public class CTAP2 extends Applet implements ExtendedLength {
// return version String when selecting
if (selectingApplet()) {
Util.arrayCopyNonAtomic(Utf8Strings.UTF8_U2F_V2, (short) 0, buffer, (short) 0,
(short) Utf8Strings.UTF8_U2F_V2.length);
apdu.setOutgoingAndSend((short) 0, (short) Utf8Strings.UTF8_U2F_V2.length);
Util.arrayCopyNonAtomic(Utf8Strings.UTF8_FIDO_2_0, (short) 0, buffer, (short) 0,
(short) Utf8Strings.UTF8_FIDO_2_0.length);
apdu.setOutgoingAndSend((short) 0, (short) Utf8Strings.UTF8_FIDO_2_0.length);
return;
}
......@@ -334,7 +334,6 @@ public class CTAP2 extends Applet implements ExtendedLength {
getPuKxCx(apdu, tempVars[3]);
break;
case ID_SECRET_DUMP_ALL: // 0x5F
// apdu.setOutgoingAndSend((short)0, (short)4); // testing, for break point setting
dumpIDSecret(apdu);
break;
case FIDO2_VENDOR_ATTEST_GETCERT: //0x4a
......@@ -372,27 +371,29 @@ public class CTAP2 extends Applet implements ExtendedLength {
apdu.sendBytesLong(dataBuffer, (short) 0, tempVars[0]);
}
/** get counter's value */
private void getCredentialCount(APDU apdu){
Util.setShort(apdu.getBuffer(), (short)0x00, credentialArray.getCount());
apdu.setOutgoingAndSend((short)0x00, (short)2);
/**
* get counter's value
*/
private void getCredentialCount(APDU apdu) {
Util.setShort(apdu.getBuffer(), (short) 0x00, credentialArray.getCount());
apdu.setOutgoingAndSend((short) 0x00, (short) 2);
}
/**
* for original framework purpose
*
* <p>
* input: IDx String
* return: PuKx and Rx in CBOR form
*/
private void getPuKxRx(APDU apdu, short dataLength){
private void getPuKxRx(APDU apdu, short dataLength) {
// Done IDx have to get data from dataBuffer at index 1
Util.arrayCopy(dataBuffer, (short)1, scratch, (short)0, (short)(dataLength-1));
idSecret.IDx = new DomString(scratch, (short)(dataLength-1) );
cborEncoder.init(dataBuffer, (short) 0, (short)1200);
cborEncoder.startArray((short)2);
cborEncoder.encodeUInt32(idSecret.Rx, (short)0);
tempVars[0] = attestationKeyPair.getPubkey(scratch, (short)0);
cborEncoder.encodeByteString(scratch, (short)0, tempVars[0]);
Util.arrayCopy(dataBuffer, (short) 1, scratch, (short) 0, (short) (dataLength - 1));
idSecret.IDx = new DomString(scratch, (short) (dataLength - 1));
cborEncoder.init(dataBuffer, (short) 0, (short) 1200);
cborEncoder.startArray((short) 2);
cborEncoder.encodeUInt32(idSecret.Rx, (short) 0);
tempVars[0] = attestationKeyPair.getPubkey(scratch, (short) 0);
cborEncoder.encodeByteString(scratch, (short) 0, tempVars[0]);
apdu.setOutgoing();
apdu.setOutgoingLength(cborEncoder.getCurrentOffset());
apdu.sendBytesLong(dataBuffer, (short) 0, cborEncoder.getCurrentOffset());
......@@ -401,52 +402,52 @@ public class CTAP2 extends Applet implements ExtendedLength {
/**
* pending
*/
private void getCx(APDU apdu, short dataLength){
private void getCx(APDU apdu, short dataLength) {
}
/**
* for alternative framework purpose
*
* <p>
* input: IDx , PuKp in CBOR form
* return: PuKx, encryptedCx in CBOR form
*/
private void getPuKxCx(APDU apdu, short dataLength){
cborDecoder.init(dataBuffer, (short)1, dataLength);
try{
private void getPuKxCx(APDU apdu, short dataLength) {
cborDecoder.init(dataBuffer, (short) 1, dataLength);
try {
cborDecoder.readMajorType(CBORBase.TYPE_ARRAY);
short length = cborDecoder.readTextString(scratch, (short)0);
short length = cborDecoder.readTextString(scratch, (short) 0);
idSecret.IDx = new DomString(scratch, length);
cborDecoder.readByteString(scratch, (short)0);
Util.arrayCopy(scratch, (short)8, idSecret.PuKp, (short)1, (short)64);
}catch(UserException e){
cborDecoder.readByteString(scratch, (short) 0);
Util.arrayCopy(scratch, (short) 8, idSecret.PuKp, (short) 1, (short) 64);
} catch (UserException e) {
returnError(apdu, e.getReason());
}
KeyAgreement keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
keyAgreement.init(attestationKeyPair.getPrivate());
keyAgreement.generateSecret(idSecret.PuKp, (short)0, (short)65, idSecret.sharedSecret, (short)0);
keyAgreement.generateSecret(idSecret.PuKp, (short) 0, (short) 65, idSecret.sharedSecret, (short) 0);
idSecret.initAesKey();
idSecret.encryptCx();
cborEncoder.init(dataBuffer, (short)0, (short)1200);
cborEncoder.startArray((short)2);
short length = attestationKeyPair.getPubkey(scratch, (short)0);
cborEncoder.encodeByteString(scratch, (short)0, length);
cborEncoder.encodeByteString(idSecret.encryptedCx, (short)0, (short)idSecret.encryptedCx.length);
cborEncoder.init(dataBuffer, (short) 0, (short) 1200);
cborEncoder.startArray((short) 2);
short length = attestationKeyPair.getPubkey(scratch, (short) 0);
cborEncoder.encodeByteString(scratch, (short) 0, length);
cborEncoder.encodeByteString(idSecret.encryptedCx, (short) 0, (short) idSecret.encryptedCx.length);
//for test
idSecret.getHMAC(scratch, (short)0);
idSecret.getHMAC(scratch, (short) 0);
apdu.setOutgoing();
apdu.setOutgoingLength(cborEncoder.getCurrentOffset());
apdu.sendBytesLong(dataBuffer, (short)0, cborEncoder.getCurrentOffset());
apdu.sendBytesLong(dataBuffer, (short) 0, cborEncoder.getCurrentOffset());
}
/**
* dump secrets
*/
private void dumpIDSecret(APDU apdu){
private void dumpIDSecret(APDU apdu) {
tempVars[0] = idSecret.dump(dataBuffer, cborEncoder);
// apdu.setOutgoing();
// apdu.setOutgoingLength(tempVars[0]);
......@@ -490,7 +491,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
}
public void authMakeCredential(APDU apdu, short bufLen) {
if(pinRetries < (short)1){
if (pinRetries < (short) 1) {
returnError(apdu, CTAP2_ERR_PIN_AUTH_BLOCKED);
return;
}
......@@ -521,18 +522,18 @@ public class CTAP2 extends Applet implements ExtendedLength {
return;
}
if (authenticatorMakeCredential.isResident()) {
idSecret.writeTempBuffer(pinUvAuthProtocolOne.authenticate(pinToken, authenticatorMakeCredential.getDataHash()), (short)0);
idSecret.writeTempBuffer(authenticatorMakeCredential.getPinUvAuthParam(), (short)64);
idSecret.writeTempBuffer(pinUvAuthProtocolOne.authenticate(pinToken, authenticatorMakeCredential.getDataHash()), (short) 0);
idSecret.writeTempBuffer(authenticatorMakeCredential.getPinUvAuthParam(), (short) 64);
// verify the pin UV Auth token
if(pinUvAuthProtocolOne.verify(
if (pinUvAuthProtocolOne.verify(
pinToken,
authenticatorMakeCredential.getDataHash(),
authenticatorMakeCredential.getPinUvAuthParam()
)
){
) {
pinRetries = MAX_PIN_RETRIES;
}else{
} else {
pinRetries--;
returnError(apdu, CTAP2_ERR_PIN_AUTH_INVALID);
return;
......@@ -571,7 +572,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
// TODO fix the bug on extension byte string
// tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen() + idSecret.getExtensionsLength() ));
// tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen() + Utf8Strings.UTF8_PRLab.length ));
tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen() ));
tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen()));
/**
* end
*/
......@@ -637,16 +638,16 @@ public class CTAP2 extends Applet implements ExtendedLength {
* extension
*/
// add extension label
cborEncoder.encodeTextString(Utf8Strings.UTF8_EXTENSIONS, (short)0, (short)Utf8Strings.UTF8_EXTENSIONS.length);
cborEncoder.encodeTextString(Utf8Strings.UTF8_EXTENSIONS, (short) 0, (short) Utf8Strings.UTF8_EXTENSIONS.length);
// add extension element
cborEncoder.startArray((short)2);
cborEncoder.startArray((short) 2);
// add HMAC
// cborEncoder.encodeTextString(Utf8Strings.UTF8_HMAC, (short)0, (short)Utf8Strings.UTF8_HMAC.length );
cborEncoder.encodeByteString(idSecret.hmac, (short)0, (short)idSecret.hmac.length);
cborEncoder.encodeByteString(idSecret.hmac, (short) 0, (short) idSecret.hmac.length);
// // add Cx
// cborEncoder.encodeTextString(Utf8Strings.UTF8_Cx, (short)0, (short)Utf8Strings.UTF8_Cx.length);
cborEncoder.encodeByteString(idSecret.encryptedCx, (short)0, (short)idSecret.encryptedCx.length);
cborEncoder.encodeByteString(idSecret.encryptedCx, (short) 0, (short) idSecret.encryptedCx.length);
/**
......@@ -654,8 +655,6 @@ public class CTAP2 extends Applet implements ExtendedLength {
*/
// We're actually done, send this out
sendLongChaining(apdu, cborEncoder.getCurrentOffset());
......@@ -755,11 +754,11 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Start reading
clientPINCommand.decodeCommand(cborDecoder);
switch(clientPINCommand.getSubCommandCode()){
switch (clientPINCommand.getSubCommandCode()) {
case SUBCOMMAND_GET_PIN_RETRIES:
dataBuffer[0] = CTAP1_ERR_SUCCESS; // 0x00 : response success code
cborEncoder.init(dataBuffer, (short)1, (short)(1199));
cborEncoder.startMap((short)1);
cborEncoder.init(dataBuffer, (short) 1, (short) (1199));
cborEncoder.startMap((short) 1);
cborEncoder.encodeUInt8(ClientPINResponse.PIN_RETRIES);
cborEncoder.encodeUInt8(pinRetries);
sendLongChaining(apdu, cborEncoder.getCurrentOffset());
......@@ -803,8 +802,8 @@ public class CTAP2 extends Applet implements ExtendedLength {
clientPINCommand.getNewPinEnc()
);
for(short i = 0 ; i < (short)paddedPin.length ; i ++){
if(paddedPin[i] == 0x00) {
for (short i = 0; i < (short) paddedPin.length; i++) {
if (paddedPin[i] == 0x00) {
pinLength = i;
break;
}
......@@ -812,12 +811,12 @@ public class CTAP2 extends Applet implements ExtendedLength {
pin = new byte[pinLength];
Util.arrayCopy(paddedPin, (short)0, pin, (short)0, (short)pin.length);
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);
Util.arrayCopy(hashedPin, (short) 0, currentStoredPIN, (short) 0, (short) 16);
// idSecret.writeTempBuffer(currentStoredPIN, (short)10);
......@@ -836,8 +835,8 @@ public class CTAP2 extends Applet implements ExtendedLength {
);
// idSecret.writeTempBuffer(hashedPin_leftHalf, (short)36);
for(short i = 0; i < (short)hashedPin_leftHalf.length ; i++){
if(hashedPin_leftHalf[i] != currentStoredPIN[i]){
for (short i = 0; i < (short) hashedPin_leftHalf.length; i++) {
if (hashedPin_leftHalf[i] != currentStoredPIN[i]) {
pinRetries--;
UserException.throwIt(CTAP2_ERR_PIN_INVALID);
break;
......@@ -846,17 +845,17 @@ public class CTAP2 extends Applet implements ExtendedLength {
RandomData r = Random.getInstance();
r.nextBytes(pinToken, (short)0, (short)pinToken.length);
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);
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;
case SUBCOMMAND_GET_PIN_UV_AUTH_TOKEN_UV:
......@@ -1016,19 +1015,19 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Create the authGetInfo - 0x00 is success
dataBuffer[0] = 0x00;
cborEncoder.init(dataBuffer, (short) 1, (short) 1199);
cborEncoder.startMap((short) 8);
cborEncoder.startMap((short) 7);
// 0x01, versions
cborEncoder.encodeUInt8((byte) 0x01);
// Value is an array of strings
cborEncoder.startArray((short) 2);
cborEncoder.startArray((short) 1);
// Type 1, FIDO2
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);
cborEncoder.encodeTextString(Utf8Strings.UTF8_FIDO_2_0, (short) 0, (short) Utf8Strings.UTF8_FIDO_2_0.length);
// cborEncoder.encodeTextString(Utf8Strings.UTF8_FIDO_2_1_PRE, (short) 0, (short) Utf8Strings.UTF8_FIDO_2_1_PRE.length);
// 0x02, Extensions
cborEncoder.encodeUInt8((byte) 0x02);
cborEncoder.startArray((short) 2);
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.encodeUInt8((byte) 0x02);
// cborEncoder.startArray((short) 2);
// 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,
cborEncoder.encodeUInt8((byte) 0x03);
......@@ -1036,37 +1035,37 @@ public class CTAP2 extends Applet implements ExtendedLength {
// 0x04, Options,
cborEncoder.encodeUInt8((byte) 0x04);
// Map of 3
cborEncoder.startMap((short) 5);
cborEncoder.startMap((short) 4);
// 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);
// 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);
// // 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.encodeTextString(Utf8Strings.UTF8_plat, (short) 0, (short) Utf8Strings.UTF8_plat.length);
cborEncoder.encodeBoolean(false);
// 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);
// credentialMgmtPreview
cborEncoder.encodeTextString(Utf8Strings.UTF8_CREDENTIAL_MGMT_PREVIEW, (short) 0, (short)Utf8Strings.UTF8_CREDENTIAL_MGMT_PREVIEW.length);
cborEncoder.encodeBoolean(true);
// cborEncoder.encodeTextString(Utf8Strings.UTF8_CREDENTIAL_MGMT_PREVIEW, (short) 0, (short)Utf8Strings.UTF8_CREDENTIAL_MGMT_PREVIEW.length);
// cborEncoder.encodeBoolean(true);
// Max msg size, 0x05
cborEncoder.encodeUInt8((byte) 0x05);
cborEncoder.encodeUInt16((short) 1200);
// pin Protocols, 0x06
cborEncoder.encodeUInt8((byte) 0x06);
cborEncoder.startArray((short)0x01);
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);
cborEncoder.startArray((short) 0x01);
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
cborEncoder.encodeUInt8((byte) 0x0D);
cborEncoder.encodeUInt8((byte) 0x04);
......
......@@ -39,7 +39,7 @@ public class Utf8Strings {
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_U2F_V2 = {'U', '2', 'F', '_', 'V', '2'};
public static final byte[] UTF8_FIDO2 = {'F', 'I', 'D', 'O', '_', '2', '_', '0'};
public static final byte[] UTF8_FIDO_2_0 = {'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_NULL = {'n', 'u', 'l', 'l'};
......
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