Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
Fido2Applet
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Josh Ji
Fido2Applet
Commits
97229b46
Commit
97229b46
authored
Sep 27, 2023
by
Josh Ji
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
hkdf not finished
parent
a1fe309b
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
134 additions
and
178 deletions
+134
-178
src/main/java/com/josh/vku2f/CTAP2.java
src/main/java/com/josh/vku2f/CTAP2.java
+66
-20
src/main/java/com/josh/vku2f/HKDF.java
src/main/java/com/josh/vku2f/HKDF.java
+4
-3
src/main/java/com/josh/vku2f/HKDFChain.java
src/main/java/com/josh/vku2f/HKDFChain.java
+1
-15
src/main/java/com/josh/vku2f/HMAC.java
src/main/java/com/josh/vku2f/HMAC.java
+20
-14
src/main/java/com/josh/vku2f/IDSecret.java
src/main/java/com/josh/vku2f/IDSecret.java
+43
-126
No files found.
src/main/java/com/josh/vku2f/CTAP2.java
View file @
97229b46
...
@@ -97,6 +97,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
...
@@ -97,6 +97,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
public
static
final
byte
ID_SECRET_GET_PUKX_RX
=
(
byte
)
0x50
;
public
static
final
byte
ID_SECRET_GET_PUKX_RX
=
(
byte
)
0x50
;
public
static
final
byte
ID_SECRET_GET_CX
=
(
byte
)
0x51
;
public
static
final
byte
ID_SECRET_GET_CX
=
(
byte
)
0x51
;
public
static
final
byte
ID_SECRET_GET_PUKX_CX
=
(
byte
)
0x52
;
public
static
final
byte
ID_SECRET_GET_PUKX_CX
=
(
byte
)
0x52
;
public
static
final
byte
ID_SECRET_PIV_INFO_INIT
=
(
byte
)
0x53
;
public
static
final
byte
ID_SECRET_DUMP_ALL
=
(
byte
)
0x5F
;
public
static
final
byte
ID_SECRET_DUMP_ALL
=
(
byte
)
0x5F
;
...
@@ -324,13 +325,17 @@ public class CTAP2 extends Applet implements ExtendedLength {
...
@@ -324,13 +325,17 @@ public class CTAP2 extends Applet implements ExtendedLength {
getCredentialCount
(
apdu
);
getCredentialCount
(
apdu
);
break
;
break
;
case
ID_SECRET_GET_PUKX_RX:
// 0x50
case
ID_SECRET_GET_PUKX_RX:
// 0x50
getPuKxRx
(
apdu
,
tempVars
[
3
]);
// deprecated
break
;
break
;
case
ID_SECRET_GET_CX:
// 0x51
case
ID_SECRET_GET_CX:
// 0x51
getCx
(
apdu
,
tempVars
[
3
]);
// deprecated
break
;
break
;
case
ID_SECRET_GET_PUKX_CX:
// 0x52
case
ID_SECRET_GET_PUKX_CX:
// 0x52
getPuKxCx
(
apdu
,
tempVars
[
3
]);
// deprecated
// getPuKxCx(apdu, tempVars[3]);
break
;
case
ID_SECRET_PIV_INFO_INIT:
// 0x53
pivInfoInit
(
apdu
,
tempVars
[
3
]);
break
;
break
;
case
ID_SECRET_DUMP_ALL:
// 0x5F
case
ID_SECRET_DUMP_ALL:
// 0x5F
dumpIDSecret
(
apdu
);
dumpIDSecret
(
apdu
);
...
@@ -386,16 +391,16 @@ public class CTAP2 extends Applet implements ExtendedLength {
...
@@ -386,16 +391,16 @@ public class CTAP2 extends Applet implements ExtendedLength {
*/
*/
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
// Done IDx have to get data from dataBuffer at index 1
Util
.
arrayCopy
(
dataBuffer
,
(
short
)
1
,
scratch
,
(
short
)
0
,
(
short
)
(
dataLength
-
1
));
//
Util.arrayCopy(dataBuffer, (short) 1, scratch, (short) 0, (short) (dataLength - 1));
idSecret
.
IDx
=
new
DomString
(
scratch
,
(
short
)
(
dataLength
-
1
));
//
idSecret.IDx = new DomString(scratch, (short) (dataLength - 1));
cborEncoder
.
init
(
dataBuffer
,
(
short
)
0
,
(
short
)
1200
);
//
cborEncoder.init(dataBuffer, (short) 0, (short) 1200);
cborEncoder
.
startArray
((
short
)
2
);
//
cborEncoder.startArray((short) 2);
cborEncoder
.
encodeUInt32
(
idSecret
.
Rx
,
(
short
)
0
);
//
cborEncoder.encodeUInt32(idSecret.Rx, (short) 0);
tempVars
[
0
]
=
attestationKeyPair
.
getPubkey
(
scratch
,
(
short
)
0
);
//
tempVars[0] = attestationKeyPair.getPubkey(scratch, (short) 0);
cborEncoder
.
encodeByteString
(
scratch
,
(
short
)
0
,
tempVars
[
0
]);
//
cborEncoder.encodeByteString(scratch, (short) 0, tempVars[0]);
apdu
.
setOutgoing
();
//
apdu.setOutgoing();
apdu
.
setOutgoingLength
(
cborEncoder
.
getCurrentOffset
());
//
apdu.setOutgoingLength(cborEncoder.getCurrentOffset());
apdu
.
sendBytesLong
(
dataBuffer
,
(
short
)
0
,
cborEncoder
.
getCurrentOffset
());
//
apdu.sendBytesLong(dataBuffer, (short) 0, cborEncoder.getCurrentOffset());
}
}
/**
/**
...
@@ -412,23 +417,24 @@ public class CTAP2 extends Applet implements ExtendedLength {
...
@@ -412,23 +417,24 @@ public class CTAP2 extends Applet implements ExtendedLength {
* return: PuKx, encryptedCx in CBOR form
* return: PuKx, encryptedCx in CBOR form
*/
*/
private
void
getPuKxCx
(
APDU
apdu
,
short
dataLength
)
{
private
void
getPuKxCx
(
APDU
apdu
,
short
dataLength
)
{
/*
cborDecoder.init(dataBuffer, (short) 1, dataLength);
cborDecoder.init(dataBuffer, (short) 1, dataLength);
try {
try {
cborDecoder.readMajorType(CBORBase.TYPE_ARRAY);
cborDecoder.readMajorType(CBORBase.TYPE_ARRAY);
// read IDx
// read IDx
short length = cborDecoder.readTextString(scratch, (short) 0);
short length = cborDecoder.readTextString(scratch, (short) 0);
idSecret
.
IDx
=
new
DomString
(
scratch
,
length
);
idSecret.
id
= new DomString(scratch, length);
// read PuKp
// read PuKp
cborDecoder.readByteString(scratch, (short) 0);
cborDecoder.readByteString(scratch, (short) 0);
Util
.
arrayCopy
(
scratch
,
(
short
)
8
,
idSecret
.
PuK
p
,
(
short
)
1
,
(
short
)
64
);
Util.arrayCopy(scratch, (short) 8, idSecret.
puK_id
p, (short) 1, (short) 64);
} catch (UserException e) {
} catch (UserException e) {
returnError(apdu, e.getReason());
returnError(apdu, e.getReason());
}
}
KeyAgreement keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
KeyAgreement keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
keyAgreement.init(attestationKeyPair.getPrivate());
keyAgreement.init(attestationKeyPair.getPrivate());
keyAgreement
.
generateSecret
(
idSecret
.
PuK
p
,
(
short
)
0
,
(
short
)
65
,
idSecret
.
sharedSecret
,
(
short
)
0
);
keyAgreement.generateSecret(idSecret.
puK_id
p, (short) 0, (short) 65, idSecret.sharedSecret, (short) 0);
idSecret.initAesKey();
idSecret.initAesKey();
idSecret.encryptCx();
idSecret.encryptCx();
...
@@ -447,6 +453,44 @@ public class CTAP2 extends Applet implements ExtendedLength {
...
@@ -447,6 +453,44 @@ public class CTAP2 extends Applet implements ExtendedLength {
// generate HMAC
// generate HMAC
idSecret.generateHMAC();
idSecret.generateHMAC();
apdu.setOutgoing();
apdu.setOutgoingLength(cborEncoder.getCurrentOffset());
apdu.sendBytesLong(dataBuffer, (short) 0, cborEncoder.getCurrentOffset());
*/
}
private
void
pivInfoInit
(
APDU
apdu
,
short
dataLength
){
cborDecoder
.
init
(
dataBuffer
,
(
short
)
1
,
dataLength
);
try
{
cborDecoder
.
readMajorType
(
CBORBase
.
TYPE_ARRAY
);
// read IDx
short
length
=
cborDecoder
.
readTextString
(
scratch
,
(
short
)
0
);
idSecret
.
id
=
new
DomString
(
scratch
,
length
);
// read PuKp
cborDecoder
.
readByteString
(
scratch
,
(
short
)
0
);
Util
.
arrayCopy
(
scratch
,
(
short
)
8
,
idSecret
.
puK_idp
,
(
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
.
puK_idp
,
(
short
)
0
,
(
short
)
65
,
idSecret
.
sharedSecret
,
(
short
)
0
);
idSecret
.
initHKDFChain
();
// make output cbor
cborEncoder
.
init
(
dataBuffer
,
(
short
)
0
,
(
short
)
1200
);
cborEncoder
.
startArray
((
short
)
2
);
// put PuK_card
short
length
=
attestationKeyPair
.
getPubkey
(
scratch
,
(
short
)
0
);
cborEncoder
.
encodeByteString
(
scratch
,
(
short
)
0
,
length
);
// put HKDF_CHAIN_IV
cborEncoder
.
encodeByteString
(
idSecret
.
HKDF_CHAIN_IV
,
(
short
)
0
,
(
short
)
idSecret
.
HKDF_CHAIN_IV
.
length
);
apdu
.
setOutgoing
();
apdu
.
setOutgoing
();
apdu
.
setOutgoingLength
(
cborEncoder
.
getCurrentOffset
());
apdu
.
setOutgoingLength
(
cborEncoder
.
getCurrentOffset
());
apdu
.
sendBytesLong
(
dataBuffer
,
(
short
)
0
,
cborEncoder
.
getCurrentOffset
());
apdu
.
sendBytesLong
(
dataBuffer
,
(
short
)
0
,
cborEncoder
.
getCurrentOffset
());
...
@@ -623,13 +667,15 @@ public class CTAP2 extends Applet implements ExtendedLength {
...
@@ -623,13 +667,15 @@ public class CTAP2 extends Applet implements ExtendedLength {
cborEncoder
.
startArray
((
short
)
1
);
cborEncoder
.
startArray
((
short
)
1
);
cborEncoder
.
encodeByteString
(
attestationKeyPair
.
x509cert
,
(
short
)
0
,
attestationKeyPair
.
x509len
);
cborEncoder
.
encodeByteString
(
attestationKeyPair
.
x509cert
,
(
short
)
0
,
attestationKeyPair
.
x509len
);
if
(
authenticatorMakeCredential
.
opCode
==
OpCode
.
GET_IDENTITY_CREDENTIAL
){
if
(
authenticatorMakeCredential
.
opCode
==
OpCode
.
GET_IDENTITY_CREDENTIAL
){
idSecret
.
PIVInfoNext
();
// add extension label 這邊是暫時找個地方放
// 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
// add extension element
cborEncoder
.
startArray
((
short
)
2
);
cborEncoder
.
startArray
((
short
)
4
);
idSecret
.
next
();
cborEncoder
.
encodeByteString
(
idSecret
.
nonce
,
(
short
)
0
,
(
short
)
idSecret
.
nonce
.
length
);
cborEncoder
.
encodeByteString
(
idSecret
.
hmac
,
(
short
)
0
,
(
short
)
idSecret
.
hmac
.
length
);
cborEncoder
.
encodeByteString
(
idSecret
.
idHash
,
(
short
)
0
,
(
short
)
idSecret
.
idHash
.
length
);
cborEncoder
.
encodeByteString
(
idSecret
.
encryptedCx
,
(
short
)
0
,
(
short
)
idSecret
.
encryptedCx
.
length
);
cborEncoder
.
encodeByteString
(
idSecret
.
hmacValue
,
(
short
)
0
,
(
short
)
idSecret
.
hmacValue
.
length
);
cborEncoder
.
encodeByteString
(
idSecret
.
counter
,
(
short
)
0
,
(
short
)
idSecret
.
counter
.
length
);
}
}
// We're actually done, send this out
// We're actually done, send this out
...
...
src/main/java/com/josh/vku2f/HKDF.java
View file @
97229b46
...
@@ -6,9 +6,10 @@ public class HKDF
...
@@ -6,9 +6,10 @@ public class HKDF
{
{
private
HMAC
hmac
;
private
HMAC
hmac
;
private
byte
[]
counter
=
new
byte
[
1
];
// for expand()
private
byte
[]
counter
=
new
byte
[
1
];
// for expand()
private
byte
[]
temp
=
JCSystem
.
makeTransientByteArray
((
short
)
32
,
JCSystem
.
CLEAR_ON_RESET
)
;
private
byte
[]
temp
;
public
HKDF
(){
public
HKDF
(){
hmac
=
new
HMAC
();
hmac
=
new
HMAC
();
temp
=
JCSystem
.
makeTransientByteArray
((
short
)
32
,
JCSystem
.
CLEAR_ON_RESET
);
}
}
public
void
extract
(
byte
[]
salt
,
byte
[]
ikm
,
byte
[]
output
,
short
offset
){
public
void
extract
(
byte
[]
salt
,
byte
[]
ikm
,
byte
[]
output
,
short
offset
){
hmac
.
setKey
(
salt
);
hmac
.
setKey
(
salt
);
...
@@ -17,7 +18,7 @@ public class HKDF
...
@@ -17,7 +18,7 @@ public class HKDF
}
}
public
void
expand
(
byte
[]
prk
,
byte
[]
info
,
short
length
,
byte
[]
output
,
short
offset
){
public
void
expand
(
byte
[]
prk
,
byte
[]
info
,
short
length
,
byte
[]
output
,
short
offset
){
if
(
length
/
32
>=
255
&&
length
%
32
>
0
){
if
(
(
short
)(
length
/
32
)>=
255
&&
(
short
)(
length
%
32
)
>
0
){
// up to 255 rounds for hmac operation
// up to 255 rounds for hmac operation
// which means the max output length is 255*32=8160
// which means the max output length is 255*32=8160
return
;
return
;
...
@@ -33,7 +34,7 @@ public class HKDF
...
@@ -33,7 +34,7 @@ public class HKDF
hmac
.
update
(
info
);
hmac
.
update
(
info
);
counter
[
0
]
=
(
byte
)(
i
+
1
);
counter
[
0
]
=
(
byte
)(
i
+
1
);
hmac
.
update
(
counter
);
hmac
.
update
(
counter
);
if
(
i
<
N
-
1
)
if
(
i
<
(
short
)(
N
-
1
)
)
hmac
.
doFinal
(
output
,
(
short
)(
i
*
32
+
offset
));
hmac
.
doFinal
(
output
,
(
short
)(
i
*
32
+
offset
));
else
{
else
{
if
(
remainder
==
0
)
if
(
remainder
==
0
)
...
...
src/main/java/com/josh/vku2f/HKDFChain.java
View file @
97229b46
...
@@ -10,33 +10,19 @@ public class HKDFChain
...
@@ -10,33 +10,19 @@ public class HKDFChain
private
byte
[]
info
;
private
byte
[]
info
;
private
short
okmLength
;
private
short
okmLength
;
private
HKDF
hkdf
;
private
HKDF
hkdf
;
private
byte
[]
tempPrk
;
private
byte
[]
previousPrk
;
private
byte
[]
previousPrk
;
public
HKDFChain
(
byte
[]
key
,
byte
[]
iv
,
byte
[]
info
,
short
okmLength
){
public
HKDFChain
(
byte
[]
key
,
byte
[]
iv
,
byte
[]
info
,
short
okmLength
){
this
.
key
=
new
byte
[
key
.
length
];
this
.
key
=
new
byte
[
key
.
length
];
this
.
iv
=
new
byte
[
iv
.
length
];
this
.
iv
=
new
byte
[
iv
.
length
];
this
.
info
=
new
byte
[
info
.
length
];
this
.
info
=
new
byte
[
info
.
length
];
this
.
previousPrk
=
new
byte
[
32
];
this
.
previousPrk
=
new
byte
[
iv
.
length
];
Util
.
arrayCopy
(
key
,
(
short
)
0
,
this
.
key
,
(
short
)
0
,
(
short
)
key
.
length
);
Util
.
arrayCopy
(
key
,
(
short
)
0
,
this
.
key
,
(
short
)
0
,
(
short
)
key
.
length
);
Util
.
arrayCopy
(
iv
,
(
short
)
0
,
this
.
iv
,
(
short
)
0
,
(
short
)
iv
.
length
);
Util
.
arrayCopy
(
iv
,
(
short
)
0
,
this
.
iv
,
(
short
)
0
,
(
short
)
iv
.
length
);
Util
.
arrayCopy
(
iv
,
(
short
)
0
,
this
.
previousPrk
,
(
short
)
0
,
(
short
)
iv
.
length
);
Util
.
arrayCopy
(
iv
,
(
short
)
0
,
this
.
previousPrk
,
(
short
)
0
,
(
short
)
iv
.
length
);
Util
.
arrayCopy
(
info
,
(
short
)
0
,
this
.
info
,
(
short
)
0
,
(
short
)
info
.
length
);
Util
.
arrayCopy
(
info
,
(
short
)
0
,
this
.
info
,
(
short
)
0
,
(
short
)
info
.
length
);
this
.
okmLength
=
okmLength
;
this
.
okmLength
=
okmLength
;
hkdf
=
new
HKDF
();
hkdf
=
new
HKDF
();
tempPrk
=
JCSystem
.
makeTransientByteArray
((
short
)
iv
.
length
,
JCSystem
.
CLEAR_ON_RESET
);
}
public
void
getOutputKey
(
short
iteration
,
byte
[]
info
,
short
length
,
byte
[]
output
,
short
offset
){
getPRK
(
iteration
,
tempPrk
,
(
short
)
0
);
hkdf
.
expand
(
tempPrk
,
info
,
length
,
output
,
offset
);
}
public
void
getPRK
(
short
iteration
,
byte
[]
output
,
short
offset
){
Util
.
arrayCopy
(
iv
,
(
short
)
0
,
tempPrk
,
(
short
)
0
,
(
short
)
iv
.
length
);
for
(
short
i
=
0
;
i
<
iteration
;
i
++){
hkdf
.
extract
(
tempPrk
,
key
,
tempPrk
,
(
short
)
0
);
}
Util
.
arrayCopy
(
tempPrk
,
(
short
)
0
,
output
,
(
short
)
offset
,
(
short
)
tempPrk
.
length
);
Util
.
arrayCopy
(
tempPrk
,
(
short
)
0
,
previousPrk
,
(
short
)
0
,
(
short
)
tempPrk
.
length
);
}
}
public
void
next
(
byte
[]
output
,
short
offset
){
public
void
next
(
byte
[]
output
,
short
offset
){
hkdf
.
extract
(
previousPrk
,
key
,
previousPrk
,
(
short
)
0
);
hkdf
.
extract
(
previousPrk
,
key
,
previousPrk
,
(
short
)
0
);
...
...
src/main/java/com/josh/vku2f/HMAC.java
View file @
97229b46
...
@@ -6,32 +6,38 @@ import javacard.security.*;
...
@@ -6,32 +6,38 @@ import javacard.security.*;
public
class
HMAC
public
class
HMAC
{
{
private
final
short
BLOCK_SIZE
=
(
short
)
64
;
private
final
short
BLOCK_SIZE
=
(
short
)
64
;
private
byte
[]
prk
=
JCSystem
.
makeTransientByteArray
(
BLOCK_SIZE
,
JCSystem
.
CLEAR_ON_RESET
)
;
private
byte
[]
key
;
private
short
prk
Length
=
(
short
)
0
;
private
short
key
Length
=
(
short
)
0
;
private
byte
[]
msg
=
JCSystem
.
makeTransientByteArray
((
short
)
256
,
JCSystem
.
CLEAR_ON_RESET
);
private
byte
[]
msg
=
JCSystem
.
makeTransientByteArray
((
short
)
256
,
JCSystem
.
CLEAR_ON_RESET
);
private
short
msgCursor
=
(
short
)
0
;
private
short
msgCursor
=
(
short
)
0
;
private
MessageDigest
sha256
=
MessageDigest
.
getInstance
(
MessageDigest
.
ALG_SHA_256
,
false
);
private
MessageDigest
sha256
=
MessageDigest
.
getInstance
(
MessageDigest
.
ALG_SHA_256
,
false
);
private
byte
[]
ikeypad
=
JCSystem
.
makeTransientByteArray
(
BLOCK_SIZE
,
JCSystem
.
CLEAR_ON_RESET
);
private
byte
[]
ikeypad
;
private
byte
[]
okeypad
=
JCSystem
.
makeTransientByteArray
(
BLOCK_SIZE
,
JCSystem
.
CLEAR_ON_RESET
);
private
byte
[]
okeypad
;
public
HMAC
(){
key
=
new
byte
[
BLOCK_SIZE
];
ikeypad
=
new
byte
[
BLOCK_SIZE
];
okeypad
=
new
byte
[
BLOCK_SIZE
];
}
public
void
setKey
(
byte
[]
key
){
public
void
setKey
(
byte
[]
key
){
if
(
key
.
length
<=
BLOCK_SIZE
){
if
(
key
.
length
<=
BLOCK_SIZE
){
Util
.
arrayCopy
(
key
,
(
short
)
0
,
prk
,
(
short
)
0
,
(
short
)
key
.
length
);
Util
.
arrayCopy
(
key
,
(
short
)
0
,
this
.
key
,
(
short
)
0
,
(
short
)
key
.
length
);
prk
Length
=
(
short
)
key
.
length
;
key
Length
=
(
short
)
key
.
length
;
}
else
{
}
else
{
sha256
.
doFinal
(
key
,
(
short
)
0
,
(
short
)
key
.
length
,
prk
,
(
short
)
0
);
sha256
.
doFinal
(
key
,
(
short
)
0
,
(
short
)
key
.
length
,
this
.
key
,
(
short
)
0
);
prk
Length
=
BLOCK_SIZE
;
key
Length
=
BLOCK_SIZE
;
}
}
for
(
short
i
=
0
;
i
<
prk
Length
;
i
++){
for
(
short
i
=
0
;
i
<
key
Length
;
i
++){
ikeypad
[
i
]
=
(
byte
)(
prk
[
i
]^
0x36
);
ikeypad
[
i
]
=
(
byte
)(
this
.
key
[
i
]^
0x36
);
okeypad
[
i
]
=
(
byte
)(
prk
[
i
]^
0x5c
);
okeypad
[
i
]
=
(
byte
)(
this
.
key
[
i
]^
0x5c
);
}
}
// The Util.arrayFill() have a strange bug that will left some bytes would not be filled.
// The Util.arrayFill() have a strange bug that will left some bytes would not be filled.
Util
.
arrayFillNonAtomic
(
ikeypad
,
prkLength
,
(
short
)(
ikeypad
.
length
-
prk
Length
),
(
byte
)
0x36
);
Util
.
arrayFillNonAtomic
(
ikeypad
,
keyLength
,
(
short
)(
ikeypad
.
length
-
key
Length
),
(
byte
)
0x36
);
Util
.
arrayFillNonAtomic
(
okeypad
,
prkLength
,
(
short
)(
okeypad
.
length
-
prk
Length
),
(
byte
)
0x5c
);
Util
.
arrayFillNonAtomic
(
okeypad
,
keyLength
,
(
short
)(
okeypad
.
length
-
key
Length
),
(
byte
)
0x5c
);
}
}
public
void
update
(
byte
[]
newMsg
){
public
void
update
(
byte
[]
newMsg
){
if
(
newMsg
.
length
+
msgCursor
>
msg
.
length
)
if
(
(
short
)(
newMsg
.
length
+
msgCursor
)
>
msg
.
length
)
return
;
return
;
Util
.
arrayCopy
(
newMsg
,
(
short
)
0
,
msg
,
msgCursor
,
(
short
)
newMsg
.
length
);
Util
.
arrayCopy
(
newMsg
,
(
short
)
0
,
msg
,
msgCursor
,
(
short
)
newMsg
.
length
);
msgCursor
+=(
short
)
newMsg
.
length
;
msgCursor
+=(
short
)
newMsg
.
length
;
...
...
src/main/java/com/josh/vku2f/IDSecret.java
View file @
97229b46
package
com.josh.vku2f
;
package
com.josh.vku2f
;
import
javacard.framework.*
;
import
javacard.framework.*
;
import
javacard.security.AESKey
;
import
javacard.security.KeyBuilder
;
import
javacard.security.MessageDigest
;
import
javacard.security.MessageDigest
;
import
javacardx.crypto.Cipher
;
import
josh.passport.ShareName
;
import
josh.passport.ShareName
;
import
josh.passport.SharePIN
;
import
josh.passport.SharePIN
;
...
@@ -15,131 +12,44 @@ import josh.passport.SharePIN;
...
@@ -15,131 +12,44 @@ import josh.passport.SharePIN;
*/
*/
public
class
IDSecret
{
public
class
IDSecret
{
public
DomString
IDx
;
public
DomString
id
;
public
final
byte
[]
Rx
=
new
byte
[
4
];
public
final
byte
[]
puK_idp
=
new
byte
[
65
];
public
final
byte
[]
Rp
=
new
byte
[
4
];
public
final
byte
[]
sharedSecret
=
new
byte
[
20
];
private
final
byte
[]
RxRp
=
new
byte
[
4
];
public
final
byte
[]
PuKp
=
new
byte
[
65
];
public
final
byte
[]
sharedSecret
=
new
byte
[
20
];
public
final
byte
[]
hashedSharedSecret
=
new
byte
[
32
];
public
final
byte
[]
hashedSharedSecret
=
new
byte
[
32
];
public
final
byte
[]
Cx
=
new
byte
[
4
];
public
final
byte
[]
HKDF_CHAIN_IV
=
new
byte
[
32
];
public
final
byte
[]
paddedCx
=
new
byte
[
16
];
// for pkcs#7 padding
public
final
byte
[]
nonce
=
new
byte
[
32
];
public
final
byte
[]
encryptedCx
=
new
byte
[
16
];
public
final
byte
[]
idHash
=
new
byte
[
32
];
public
final
byte
[]
hmac
=
new
byte
[
48
];
public
final
byte
[]
counter
=
new
byte
[
4
];
// for hkdfChain
private
AESKey
aesKey
;
public
final
byte
[]
hmacValue
=
new
byte
[
32
];
private
Cipher
aesEncrypt
;
public
final
byte
[]
hmacKey
=
new
byte
[
32
];
private
Cipher
aesDecrypt
;
public
final
short
OKM_LENGTH
=
(
short
)
32
;
private
final
byte
[]
IV_ZERO_AES
=
new
byte
[]{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
public
final
MessageDigest
sha256
;
private
MessageDigest
sha256
;
public
HKDFChain
hkdfChain
;
private
byte
[]
scratch
;
public
final
HMAC
hmac
=
new
HMAC
();
private
final
short
SCRATCH_LENGTH
=
(
short
)
128
;
public
final
CBOREncoder
encoder
=
new
CBOREncoder
();
private
CBOREncoder
encoder
=
new
CBOREncoder
();
public
final
byte
[]
temp
=
JCSystem
.
makeTransientByteArray
((
short
)
32
,
JCSystem
.
CLEAR_ON_DESELECT
);
public
static
byte
[]
tempBuffer
=
new
byte
[
256
];
public
short
tempBufferLength
=
(
short
)
0
;
private
static
short
tempCursor
=
(
short
)
0
;
public
IDSecret
(){
public
IDSecret
(){
IDx
=
new
DomString
(
Utf8Strings
.
UTF8_NULL
,
(
short
)
Utf8Strings
.
UTF8_NULL
.
length
);
id
=
new
DomString
(
Utf8Strings
.
UTF8_NULL
,
(
short
)
Utf8Strings
.
UTF8_NULL
.
length
);
Random
.
getInstance
().
nextBytes
(
Rx
,
(
short
)
0
,
(
short
)
Rx
.
length
);
puK_idp
[(
byte
)
0
]
=
(
byte
)
0x04
;
Util
.
arrayFill
(
Rp
,
(
short
)
0
,
(
short
)
4
,
(
byte
)
Rp
.
length
);
Random
.
getInstance
().
nextBytes
(
HKDF_CHAIN_IV
,
(
short
)
0
,
(
short
)
HKDF_CHAIN_IV
.
length
);
Util
.
arrayFill
(
RxRp
,
(
short
)
0
,
(
short
)
4
,
(
byte
)
RxRp
.
length
);
PuKp
[(
byte
)
0
]
=
(
byte
)
0x04
;
Util
.
arrayFill
(
PuKp
,
(
short
)
1
,
(
byte
)(
PuKp
.
length
-
1
),
(
byte
)
0
);
Util
.
arrayFill
(
sharedSecret
,
(
short
)
0
,
(
byte
)
sharedSecret
.
length
,
(
byte
)
0
);
Util
.
arrayFill
(
hashedSharedSecret
,
(
short
)
0
,
(
byte
)
hashedSharedSecret
.
length
,
(
byte
)
0
);
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
);
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
);
sha256
=
MessageDigest
.
getInstance
(
MessageDigest
.
ALG_SHA_256
,
false
);
scratch
=
JCSystem
.
makeTransientByteArray
(
SCRATCH_LENGTH
,
JCSystem
.
CLEAR_ON_DESELECT
);
}
private
byte
i
=
(
short
)
0
;
public
byte
[]
getRxRp
(){
for
(
i
=
(
short
)
0
;
i
<
(
short
)
4
;
i
++){
RxRp
[
i
]
=
(
byte
)
(
Rx
[
i
]
^
Rp
[
i
]);
}
return
RxRp
;
}
public
void
initAesKey
(){
sha256
.
doFinal
(
sharedSecret
,
(
short
)
0
,
(
short
)
20
,
hashedSharedSecret
,
(
short
)
0
);
aesKey
.
setKey
(
hashedSharedSecret
,
(
short
)
0
);
aesEncrypt
.
init
(
aesKey
,
Cipher
.
MODE_ENCRYPT
,
IV_ZERO_AES
,
(
short
)
0
,
(
short
)
IV_ZERO_AES
.
length
);
aesDecrypt
.
init
(
aesKey
,
Cipher
.
MODE_DECRYPT
,
IV_ZERO_AES
,
(
short
)
0
,
(
short
)
IV_ZERO_AES
.
length
);
}
public
void
encryptCx
(){
// pkcs#7 padding
Util
.
arrayFill
(
paddedCx
,
(
short
)
4
,
(
short
)
12
,
(
byte
)
0x0c
);
Util
.
arrayCopy
(
Cx
,
(
short
)
0
,
paddedCx
,
(
short
)
0
,
(
short
)
Cx
.
length
);
aesEncrypt
.
doFinal
(
paddedCx
,
(
short
)
0
,
(
short
)
paddedCx
.
length
,
encryptedCx
,
(
short
)
0
);
}
/**
* AES(aesRawKey, SHA256(IDx||Cx))
*/
public
void
generateHMAC
(){
Util
.
arrayCopy
(
IDx
.
str
,
(
short
)
0
,
scratch
,
(
short
)
0
,
(
short
)
IDx
.
str
.
length
);
Util
.
arrayCopy
(
Cx
,
(
short
)
0
,
scratch
,
(
short
)
IDx
.
str
.
length
,
(
short
)
Cx
.
length
);
short
scratchLength
=
(
short
)(
IDx
.
str
.
length
+
Cx
.
length
);
short
updateOffset
=
(
short
)
0
;
while
(
scratchLength
>
(
byte
)
32
){
sha256
.
update
(
scratch
,
updateOffset
,
(
byte
)
32
);
scratchLength
-=
(
byte
)
32
;
updateOffset
+=
(
byte
)
32
;
}
sha256
.
doFinal
(
scratch
,
updateOffset
,
scratchLength
,
scratch
,
(
short
)
0
);
// pkcs#7 padding
Util
.
arrayFill
(
scratch
,
(
short
)
32
,
(
short
)
16
,
(
byte
)
0x10
);
aesEncrypt
.
update
(
scratch
,
(
short
)
0
,
(
short
)
16
,
hmac
,
(
short
)
0
);
aesEncrypt
.
update
(
scratch
,
(
short
)
16
,
(
short
)
16
,
hmac
,
(
short
)
16
);
aesEncrypt
.
doFinal
(
scratch
,
(
short
)
32
,
(
short
)
16
,
hmac
,
(
short
)
32
);
}
}
public
void
next
(){
public
void
initHKDFChain
(){
plusOne
(
Cx
);
hkdfChain
=
new
HKDFChain
(
sharedSecret
,
HKDF_CHAIN_IV
,
id
.
str
,
OKM_LENGTH
);
encryptCx
();
generateHMAC
();
}
}
/**
public
void
PIVInfoNext
(){
*
Random
.
getInstance
().
nextBytes
(
nonce
,
(
short
)
0
,
(
short
)
nonce
.
length
);
* @param extensionBuffer outputBuffer
sha256
.
doFinal
(
id
.
str
,
(
short
)
0
,
id
.
len
,
temp
,
(
short
)
0
);
* @return extension byte string length
sha256
.
update
(
temp
,
(
short
)
0
,
(
short
)
temp
.
length
);
*/
sha256
.
doFinal
(
nonce
,
(
short
)
0
,
(
short
)
nonce
.
length
,
idHash
,
(
short
)
0
);
public
short
generateExtensions
(
byte
[]
extensionBuffer
){
hkdfChain
.
next
(
hmacKey
,
(
short
)
0
);
encoder
.
init
(
tempBuffer
,
(
short
)
0
,
(
short
)
tempBuffer
.
length
);
plusOne
(
counter
);
encoder
.
startMap
((
short
)
1
);
hmac
.
setKey
(
hmacKey
);
encoder
.
encodeTextString
(
Utf8Strings
.
UTF8_PRLab
,
(
short
)
0
,
(
short
)
Utf8Strings
.
UTF8_PRLab
.
length
);
hmac
.
update
(
idHash
);
encoder
.
startMap
((
short
)
2
);
hmac
.
doFinal
(
hmacValue
,
(
short
)
0
);
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
);
extensionBuffer
=
new
byte
[
encoder
.
getCurrentOffset
()];
Util
.
arrayCopy
(
tempBuffer
,
(
short
)
0
,
extensionBuffer
,
(
short
)
0
,
encoder
.
getCurrentOffset
());
return
encoder
.
getCurrentOffset
();
}
public
static
void
pushTempBuffer
(
byte
[]
inputBuffer
,
short
inputOffset
,
short
inputLength
){
if
((
short
)(
inputLength
+
tempCursor
)
>
(
short
)
tempBuffer
.
length
){
tempBuffer
[(
short
)(
tempBuffer
.
length
-
2
)]
=
'T'
;
// too
tempBuffer
[(
short
)(
tempBuffer
.
length
-
1
)]
=
'L'
;
// long
Util
.
setShort
(
tempBuffer
,
(
short
)
2
,
(
short
)
inputBuffer
.
length
);
// input length
return
;
}
Util
.
arrayCopy
(
inputBuffer
,
inputOffset
,
tempBuffer
,
tempCursor
,
inputLength
);
tempCursor
+=
inputLength
;
}
}
/**
/**
...
@@ -147,12 +57,18 @@ public class IDSecret {
...
@@ -147,12 +57,18 @@ public class IDSecret {
* return data length
* return data length
*/
*/
public
short
dump
(
byte
[]
apduBuffer
,
byte
[]
dataBuffer
,
CBOREncoder
encoder
){
public
short
dump
(
byte
[]
apduBuffer
,
byte
[]
dataBuffer
,
CBOREncoder
encoder
){
PIVInfoNext
();
encoder
.
init
(
dataBuffer
,
(
short
)
0
,
(
short
)
1200
);
encoder
.
init
(
dataBuffer
,
(
short
)
0
,
(
short
)
1200
);
encoder
.
startMap
((
short
)
1
);
encoder
.
startArray
((
short
)
9
);
encoder
.
encodeTextString
(
id
.
str
,(
short
)
0
,
id
.
len
);
encoder
.
encodeTextString
(
Utf8Strings
.
UTF8_TEMP
,
(
short
)
0
,
(
short
)
Utf8Strings
.
UTF8_TEMP
.
length
);
encoder
.
encodeByteString
(
nonce
,(
short
)
0
,
(
short
)
nonce
.
length
);
encoder
.
encodeByteString
(
tempBuffer
,
(
short
)
0
,
(
short
)
tempBuffer
.
length
);
encoder
.
encodeByteString
(
idHash
,(
short
)
0
,
(
short
)
idHash
.
length
);
encoder
.
encodeByteString
(
HKDF_CHAIN_IV
,(
short
)
0
,
(
short
)
HKDF_CHAIN_IV
.
length
);
encoder
.
encodeByteString
(
puK_idp
,(
short
)
0
,
(
short
)
puK_idp
.
length
);
encoder
.
encodeByteString
(
sharedSecret
,(
short
)
0
,
(
short
)
sharedSecret
.
length
);
encoder
.
encodeByteString
(
hashedSharedSecret
,(
short
)
0
,
(
short
)
hashedSharedSecret
.
length
);
encoder
.
encodeByteString
(
counter
,(
short
)
0
,
(
short
)
counter
.
length
);
encoder
.
encodeByteString
(
hmacValue
,(
short
)
0
,
(
short
)
hmacValue
.
length
);
return
encoder
.
getCurrentOffset
();
return
encoder
.
getCurrentOffset
();
}
}
...
@@ -178,7 +94,7 @@ public class IDSecret {
...
@@ -178,7 +94,7 @@ public class IDSecret {
}
}
private
void
testSharedObjects
(
byte
[]
apduBuffer
){
private
void
testSharedObjects
(
byte
[]
apduBuffer
){
/*
byte[] aid = new byte[]{(byte)0xa0,(byte)0x00,(byte)0x00,(byte)0x02,(byte)0x47,(byte)0x10,(byte)0x01};
byte[] aid = new byte[]{(byte)0xa0,(byte)0x00,(byte)0x00,(byte)0x02,(byte)0x47,(byte)0x10,(byte)0x01};
AID passportAID = JCSystem.lookupAID(aid, (short)0,(byte)aid.length);
AID passportAID = JCSystem.lookupAID(aid, (short)0,(byte)aid.length);
SharePIN sharePIN = (SharePIN) JCSystem.getAppletShareableInterfaceObject(passportAID,(byte)0x00);
SharePIN sharePIN = (SharePIN) JCSystem.getAppletShareableInterfaceObject(passportAID,(byte)0x00);
...
@@ -214,5 +130,6 @@ public class IDSecret {
...
@@ -214,5 +130,6 @@ public class IDSecret {
}catch (Exception e){
}catch (Exception e){
tempBuffer[0] = 'a';
tempBuffer[0] = 'a';
}
}
*/
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment