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
An error occurred while fetching merge requests data.
Commit
97229b46
authored
1 year ago
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
...
...
This diff is collapsed.
Click to expand it.
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
)
...
...
This diff is collapsed.
Click to expand it.
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
);
...
...
This diff is collapsed.
Click to expand it.
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
;
...
...
This diff is collapsed.
Click to expand it.
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';
}
*/
}
}
This diff is collapsed.
Click to expand it.
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