Commit a1fe309b authored by Josh Ji's avatar Josh Ji

add HKDFChain.java, HKDF.java, HMAC.java

parent 87d01cad
package com.josh.vku2f;
import javacard.framework.*;
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);
public HKDF(){
hmac = new HMAC();
}
public void extract(byte[] salt, byte[] ikm, byte[] output, short offset){
hmac.setKey(salt);
hmac.update(ikm);
hmac.doFinal(output, offset); // the output is prk (pseudo random key)
}
public void expand(byte[] prk, byte[] info, short length, byte[] output, short offset){
if(length/32>=255 && length%32>0){
// up to 255 rounds for hmac operation
// which means the max output length is 255*32=8160
return;
}
short N = (short)(length/32);
short remainder = (short)(length%32);
// if has remainder, plus one
if(remainder>0)
N++;
for(short i=0; i < N; i++){
hmac.setKey(prk);
hmac.update(info);
counter[0] = (byte)(i+1);
hmac.update(counter);
if(i<N-1)
hmac.doFinal(output, (short)(i*32+offset));
else{
if(remainder==0)
hmac.doFinal(output, (short)(i*32+offset));
else{
hmac.doFinal(temp, (short)0);
Util.arrayCopy(temp, (short)0, output, (short)(i*32+offset), remainder);
}
}
}
}
}
package com.josh.vku2f;
import javacard.framework.*;
import javacard.security.*;
public class HKDFChain
{
private byte[] key;
private byte[] iv;
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];
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);
hkdf.expand(previousPrk, info, okmLength, output, offset);
}
}
package com.josh.vku2f;
import javacard.framework.*;
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 prkLength = (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);
public void setKey(byte[] key){
if(key.length <= BLOCK_SIZE){
Util.arrayCopy(key, (short)0, prk, (short)0, (short)key.length);
prkLength = (short)key.length;
}else{
sha256.doFinal(key, (short)0, (short)key.length, prk, (short)0);
prkLength = BLOCK_SIZE;
}
for(short i = 0; i<prkLength; i++){
ikeypad[i] = (byte)(prk[i]^0x36);
okeypad[i] = (byte)(prk[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-prkLength), (byte)0x36);
Util.arrayFillNonAtomic(okeypad, prkLength, (short)(okeypad.length-prkLength), (byte)0x5c);
}
public void update(byte[] newMsg){
if(newMsg.length + msgCursor > msg.length)
return;
Util.arrayCopy(newMsg, (short)0, msg, msgCursor, (short)newMsg.length);
msgCursor+=(short)newMsg.length;
}
public void doFinal(byte[] output, short offset){
sha256.update(ikeypad, (short)0, (short)ikeypad.length);
sha256.doFinal(msg, (short)0, msgCursor, output, offset);
sha256.update(okeypad, (short)0, (short)okeypad.length);
sha256.doFinal(output, (short)offset, (short)32, output, offset);
msgCursor = (short)0;
}
}
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