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
alan
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 {
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_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
;
...
...
@@ -324,13 +325,17 @@ public class CTAP2 extends Applet implements ExtendedLength {
getCredentialCount
(
apdu
);
break
;
case
ID_SECRET_GET_PUKX_RX:
// 0x50
getPuKxRx
(
apdu
,
tempVars
[
3
]);
// deprecated
break
;
case
ID_SECRET_GET_CX:
// 0x51
getCx
(
apdu
,
tempVars
[
3
]);
// deprecated
break
;
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
;
case
ID_SECRET_DUMP_ALL:
// 0x5F
dumpIDSecret
(
apdu
);
...
...
@@ -386,16 +391,16 @@ public class CTAP2 extends Applet implements ExtendedLength {
*/
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
]);
apdu
.
setOutgoing
();
apdu
.
setOutgoingLength
(
cborEncoder
.
getCurrentOffset
());
apdu
.
sendBytesLong
(
dataBuffer
,
(
short
)
0
,
cborEncoder
.
getCurrentOffset
());
//
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());
}
/**
...
...
@@ -412,23 +417,24 @@ public class CTAP2 extends Applet implements ExtendedLength {
* return: PuKx, encryptedCx in CBOR form
*/
private
void
getPuKxCx
(
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
.
IDx
=
new
DomString
(
scratch
,
length
);
idSecret.
id
= new DomString(scratch, length);
// read PuKp
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) {
returnError(apdu, e.getReason());
}
KeyAgreement keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
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.encryptCx();
...
...
@@ -447,6 +453,44 @@ public class CTAP2 extends Applet implements ExtendedLength {
// generate HMAC
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
.
setOutgoingLength
(
cborEncoder
.
getCurrentOffset
());
apdu
.
sendBytesLong
(
dataBuffer
,
(
short
)
0
,
cborEncoder
.
getCurrentOffset
());
...
...
@@ -623,13 +667,15 @@ public class CTAP2 extends Applet implements ExtendedLength {
cborEncoder
.
startArray
((
short
)
1
);
cborEncoder
.
encodeByteString
(
attestationKeyPair
.
x509cert
,
(
short
)
0
,
attestationKeyPair
.
x509len
);
if
(
authenticatorMakeCredential
.
opCode
==
OpCode
.
GET_IDENTITY_CREDENTIAL
){
idSecret
.
PIVInfoNext
();
// add extension label 這邊是暫時找個地方放
cborEncoder
.
encodeTextString
(
Utf8Strings
.
UTF8_EXTENSIONS
,
(
short
)
0
,
(
short
)
Utf8Strings
.
UTF8_EXTENSIONS
.
length
);
// add extension element
cborEncoder
.
startArray
((
short
)
2
);
idSecret
.
next
();
cborEncoder
.
encodeByteString
(
idSecret
.
hmac
,
(
short
)
0
,
(
short
)
idSecret
.
hmac
.
length
);
cborEncoder
.
encodeByteString
(
idSecret
.
encryptedCx
,
(
short
)
0
,
(
short
)
idSecret
.
encryptedCx
.
length
);
cborEncoder
.
startArray
((
short
)
4
);
cborEncoder
.
encodeByteString
(
idSecret
.
nonce
,
(
short
)
0
,
(
short
)
idSecret
.
nonce
.
length
);
cborEncoder
.
encodeByteString
(
idSecret
.
idHash
,
(
short
)
0
,
(
short
)
idSecret
.
idHash
.
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
...
...
src/main/java/com/josh/vku2f/HKDF.java
View file @
97229b46
...
...
@@ -6,9 +6,10 @@ public class HKDF
{
private
HMAC
hmac
;
private
byte
[]
counter
=
new
byte
[
1
];
// for expand()
private
byte
[]
temp
=
JCSystem
.
makeTransientByteArray
((
short
)
32
,
JCSystem
.
CLEAR_ON_RESET
)
;
private
byte
[]
temp
;
public
HKDF
(){
hmac
=
new
HMAC
();
temp
=
JCSystem
.
makeTransientByteArray
((
short
)
32
,
JCSystem
.
CLEAR_ON_RESET
);
}
public
void
extract
(
byte
[]
salt
,
byte
[]
ikm
,
byte
[]
output
,
short
offset
){
hmac
.
setKey
(
salt
);
...
...
@@ -17,7 +18,7 @@ public class HKDF
}
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
// which means the max output length is 255*32=8160
return
;
...
...
@@ -33,7 +34,7 @@ public class HKDF
hmac
.
update
(
info
);
counter
[
0
]
=
(
byte
)(
i
+
1
);
hmac
.
update
(
counter
);
if
(
i
<
N
-
1
)
if
(
i
<
(
short
)(
N
-
1
)
)
hmac
.
doFinal
(
output
,
(
short
)(
i
*
32
+
offset
));
else
{
if
(
remainder
==
0
)
...
...
src/main/java/com/josh/vku2f/HKDFChain.java
View file @
97229b46
...
...
@@ -10,33 +10,19 @@ public class HKDFChain
private
byte
[]
info
;
private
short
okmLength
;
private
HKDF
hkdf
;
private
byte
[]
tempPrk
;
private
byte
[]
previousPrk
;
public
HKDFChain
(
byte
[]
key
,
byte
[]
iv
,
byte
[]
info
,
short
okmLength
){
this
.
key
=
new
byte
[
key
.
length
];
this
.
iv
=
new
byte
[
iv
.
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
(
iv
,
(
short
)
0
,
this
.
iv
,
(
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
);
this
.
okmLength
=
okmLength
;
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
){
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.*;
public
class
HMAC
{
private
final
short
BLOCK_SIZE
=
(
short
)
64
;
private
byte
[]
prk
=
JCSystem
.
makeTransientByteArray
(
BLOCK_SIZE
,
JCSystem
.
CLEAR_ON_RESET
)
;
private
short
prk
Length
=
(
short
)
0
;
private
byte
[]
key
;
private
short
key
Length
=
(
short
)
0
;
private
byte
[]
msg
=
JCSystem
.
makeTransientByteArray
((
short
)
256
,
JCSystem
.
CLEAR_ON_RESET
);
private
short
msgCursor
=
(
short
)
0
;
private
MessageDigest
sha256
=
MessageDigest
.
getInstance
(
MessageDigest
.
ALG_SHA_256
,
false
);
private
byte
[]
ikeypad
=
JCSystem
.
makeTransientByteArray
(
BLOCK_SIZE
,
JCSystem
.
CLEAR_ON_RESET
);
private
byte
[]
okeypad
=
JCSystem
.
makeTransientByteArray
(
BLOCK_SIZE
,
JCSystem
.
CLEAR_ON_RESET
);
private
byte
[]
ikeypad
;
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
){
if
(
key
.
length
<=
BLOCK_SIZE
){
Util
.
arrayCopy
(
key
,
(
short
)
0
,
prk
,
(
short
)
0
,
(
short
)
key
.
length
);
prk
Length
=
(
short
)
key
.
length
;
Util
.
arrayCopy
(
key
,
(
short
)
0
,
this
.
key
,
(
short
)
0
,
(
short
)
key
.
length
);
key
Length
=
(
short
)
key
.
length
;
}
else
{
sha256
.
doFinal
(
key
,
(
short
)
0
,
(
short
)
key
.
length
,
prk
,
(
short
)
0
);
prk
Length
=
BLOCK_SIZE
;
sha256
.
doFinal
(
key
,
(
short
)
0
,
(
short
)
key
.
length
,
this
.
key
,
(
short
)
0
);
key
Length
=
BLOCK_SIZE
;
}
for
(
short
i
=
0
;
i
<
prk
Length
;
i
++){
ikeypad
[
i
]
=
(
byte
)(
prk
[
i
]^
0x36
);
okeypad
[
i
]
=
(
byte
)(
prk
[
i
]^
0x5c
);
for
(
short
i
=
0
;
i
<
key
Length
;
i
++){
ikeypad
[
i
]
=
(
byte
)(
this
.
key
[
i
]^
0x36
);
okeypad
[
i
]
=
(
byte
)(
this
.
key
[
i
]^
0x5c
);
}
// 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
(
okeypad
,
prkLength
,
(
short
)(
okeypad
.
length
-
prk
Length
),
(
byte
)
0x5c
);
Util
.
arrayFillNonAtomic
(
ikeypad
,
keyLength
,
(
short
)(
ikeypad
.
length
-
key
Length
),
(
byte
)
0x36
);
Util
.
arrayFillNonAtomic
(
okeypad
,
keyLength
,
(
short
)(
okeypad
.
length
-
key
Length
),
(
byte
)
0x5c
);
}
public
void
update
(
byte
[]
newMsg
){
if
(
newMsg
.
length
+
msgCursor
>
msg
.
length
)
if
(
(
short
)(
newMsg
.
length
+
msgCursor
)
>
msg
.
length
)
return
;
Util
.
arrayCopy
(
newMsg
,
(
short
)
0
,
msg
,
msgCursor
,
(
short
)
newMsg
.
length
);
msgCursor
+=(
short
)
newMsg
.
length
;
...
...
src/main/java/com/josh/vku2f/IDSecret.java
View file @
97229b46
package
com.josh.vku2f
;
import
javacard.framework.*
;
import
javacard.security.AESKey
;
import
javacard.security.KeyBuilder
;
import
javacard.security.MessageDigest
;
import
javacardx.crypto.Cipher
;
import
josh.passport.ShareName
;
import
josh.passport.SharePIN
;
...
...
@@ -15,131 +12,44 @@ import josh.passport.SharePIN;
*/
public
class
IDSecret
{
public
DomString
IDx
;
public
final
byte
[]
Rx
=
new
byte
[
4
];
public
final
byte
[]
Rp
=
new
byte
[
4
];
private
final
byte
[]
RxRp
=
new
byte
[
4
];
public
final
byte
[]
PuKp
=
new
byte
[
65
];
public
final
byte
[]
sharedSecret
=
new
byte
[
20
];
public
DomString
id
;
public
final
byte
[]
puK_idp
=
new
byte
[
65
];
public
final
byte
[]
sharedSecret
=
new
byte
[
20
];
public
final
byte
[]
hashedSharedSecret
=
new
byte
[
32
];
public
final
byte
[]
Cx
=
new
byte
[
4
];
public
final
byte
[]
paddedCx
=
new
byte
[
16
];
// for pkcs#7 padding
public
final
byte
[]
encryptedCx
=
new
byte
[
16
];
public
final
byte
[]
hmac
=
new
byte
[
48
];
private
AESKey
aesKey
;
private
Cipher
aesEncrypt
;
private
Cipher
aesDecrypt
;
private
final
byte
[]
IV_ZERO_AES
=
new
byte
[]{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
private
MessageDigest
sha256
;
private
byte
[]
scratch
;
private
final
short
SCRATCH_LENGTH
=
(
short
)
128
;
private
CBOREncoder
encoder
=
new
CBOREncoder
();
public
static
byte
[]
tempBuffer
=
new
byte
[
256
];
public
short
tempBufferLength
=
(
short
)
0
;
private
static
short
tempCursor
=
(
short
)
0
;
public
final
byte
[]
HKDF_CHAIN_IV
=
new
byte
[
32
];
public
final
byte
[]
nonce
=
new
byte
[
32
];
public
final
byte
[]
idHash
=
new
byte
[
32
];
public
final
byte
[]
counter
=
new
byte
[
4
];
// for hkdfChain
public
final
byte
[]
hmacValue
=
new
byte
[
32
];
public
final
byte
[]
hmacKey
=
new
byte
[
32
];
public
final
short
OKM_LENGTH
=
(
short
)
32
;
public
final
MessageDigest
sha256
;
public
HKDFChain
hkdfChain
;
public
final
HMAC
hmac
=
new
HMAC
();
public
final
CBOREncoder
encoder
=
new
CBOREncoder
();
public
final
byte
[]
temp
=
JCSystem
.
makeTransientByteArray
((
short
)
32
,
JCSystem
.
CLEAR_ON_DESELECT
);
public
IDSecret
(){
IDx
=
new
DomString
(
Utf8Strings
.
UTF8_NULL
,
(
short
)
Utf8Strings
.
UTF8_NULL
.
length
);
Random
.
getInstance
().
nextBytes
(
Rx
,
(
short
)
0
,
(
short
)
Rx
.
length
);
Util
.
arrayFill
(
Rp
,
(
short
)
0
,
(
short
)
4
,
(
byte
)
Rp
.
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
);
//
id
=
new
DomString
(
Utf8Strings
.
UTF8_NULL
,
(
short
)
Utf8Strings
.
UTF8_NULL
.
length
);
puK_idp
[(
byte
)
0
]
=
(
byte
)
0x04
;
Random
.
getInstance
().
nextBytes
(
HKDF_CHAIN_IV
,
(
short
)
0
,
(
short
)
HKDF_CHAIN_IV
.
length
);
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
(){
plusOne
(
Cx
);
encryptCx
();
generateHMAC
();
public
void
initHKDFChain
(){
hkdfChain
=
new
HKDFChain
(
sharedSecret
,
HKDF_CHAIN_IV
,
id
.
str
,
OKM_LENGTH
);
}
/**
*
* @param extensionBuffer outputBuffer
* @return extension byte string length
*/
public
short
generateExtensions
(
byte
[]
extensionBuffer
){
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
);
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
;
public
void
PIVInfoNext
(){
Random
.
getInstance
().
nextBytes
(
nonce
,
(
short
)
0
,
(
short
)
nonce
.
length
);
sha256
.
doFinal
(
id
.
str
,
(
short
)
0
,
id
.
len
,
temp
,
(
short
)
0
);
sha256
.
update
(
temp
,
(
short
)
0
,
(
short
)
temp
.
length
);
sha256
.
doFinal
(
nonce
,
(
short
)
0
,
(
short
)
nonce
.
length
,
idHash
,
(
short
)
0
);
hkdfChain
.
next
(
hmacKey
,
(
short
)
0
);
plusOne
(
counter
);
hmac
.
setKey
(
hmacKey
);
hmac
.
update
(
idHash
);
hmac
.
doFinal
(
hmacValue
,
(
short
)
0
);
}
/**
...
...
@@ -147,12 +57,18 @@ public class IDSecret {
* return data length
*/
public
short
dump
(
byte
[]
apduBuffer
,
byte
[]
dataBuffer
,
CBOREncoder
encoder
){
PIVInfoNext
();
encoder
.
init
(
dataBuffer
,
(
short
)
0
,
(
short
)
1200
);
encoder
.
startMap
((
short
)
1
);
encoder
.
encodeTextString
(
Utf8Strings
.
UTF8_TEMP
,
(
short
)
0
,
(
short
)
Utf8Strings
.
UTF8_TEMP
.
length
);
encoder
.
encodeByteString
(
tempBuffer
,
(
short
)
0
,
(
short
)
tempBuffer
.
length
);
encoder
.
startArray
((
short
)
9
);
encoder
.
encodeTextString
(
id
.
str
,(
short
)
0
,
id
.
len
);
encoder
.
encodeByteString
(
nonce
,(
short
)
0
,
(
short
)
nonce
.
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
();
}
...
...
@@ -178,7 +94,7 @@ public class IDSecret {
}
private
void
testSharedObjects
(
byte
[]
apduBuffer
){
/*
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);
SharePIN sharePIN = (SharePIN) JCSystem.getAppletShareableInterfaceObject(passportAID,(byte)0x00);
...
...
@@ -214,5 +130,6 @@ public class IDSecret {
}catch (Exception e){
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