/* * SatoChip Bitcoin Hardware Wallet based on javacard * (c) 2015 by Toporin - 16DMCk4WUaHofchAhpMaQS4UPm4urcy2dN * Sources available on https://github.com/Toporin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.satochip.applet; import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.security.MessageDigest; // very limited Hmac-SHA160 implementation public class HmacSha160 { private static MessageDigest sha160; public static final short BLOCKSIZE=64; // 64 bytes public static final short HASHSIZE=20; public static final short MAXMSGSIZE=192; private static final short SW_UNSUPPORTED_KEYSIZE = (short) 0x9c0E; private static final short SW_UNSUPPORTED_MSGSIZE = (short) 0x9c0F; private static byte[] data; public static void init(byte[] tmp){ sha160= MessageDigest.getInstance(MessageDigest.ALG_SHA, false); data= tmp; } public static short computeHmacSha160( byte[] key, short key_offset, short key_length, byte[] message, short message_offset, short message_length, byte[] mac, short mac_offset){ if (key_length>BLOCKSIZE || key_length<0){ ISOException.throwIt(SW_UNSUPPORTED_KEYSIZE); // don't accept keys bigger than block size } if (message_length>MAXMSGSIZE || message_length<0){ ISOException.throwIt(SW_UNSUPPORTED_MSGSIZE); } // compute inner hash for (short i=0; i<key_length; i++){ data[i]= (byte) (key[(short)(key_offset+i)] ^ (0x36)); } for (short i=key_length; i<BLOCKSIZE; i++){ data[i]= (byte) 0x36; } for (short i=0; i<message_length; i++){ data[(short)(BLOCKSIZE+i)]= message[(short)(message_offset+i)]; } sha160.reset(); sha160.doFinal(data, (short)0, (short)(BLOCKSIZE+message_length), data, BLOCKSIZE); // copy hash result to data buffer! // compute outer hash for (short i=0; i<key_length; i++){ data[i]= (byte) (key[(short)(key_offset+i)] ^ (0x5c)); } for (short i=key_length; i<BLOCKSIZE; i++){ data[i]= (byte) 0x5c; } // previous hash already copied to correct offset in data sha160.reset(); sha160.doFinal(data, (short)0, (short)(BLOCKSIZE+HASHSIZE), mac, mac_offset); return HASHSIZE; } }