/* * 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.framework.Util; // very limited Hmac-SHA512 implementation public class HmacSha512 { public static final short BLOCKSIZE=128; // 128 bytes public static final short HASHSIZE=64; 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){ data= tmp; } public static short computeHmacSha512(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>HASHSIZE || message_length<0){ ISOException.throwIt(SW_UNSUPPORTED_MSGSIZE); // don't accept messsage bigger than block size (should be sufficient for BIP32) } // compute inner hash for (short i=0; i<key_length; i++){ data[i]= (byte) (key[(short)(key_offset+i)] ^ (0x36)); } Util.arrayFillNonAtomic(data, key_length, (short)(BLOCKSIZE-key_length), (byte)0x36); Util.arrayCopyNonAtomic(message, message_offset, data, BLOCKSIZE, message_length); //Sha512.reset(); //Sha512.doFinal(data, (short)0, (short)(BLOCKSIZE+message_length), data, BLOCKSIZE); // copy hash result to data buffer! Sha512.resetUpdateDoFinal(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)); } Util.arrayFillNonAtomic(data, key_length, (short)(BLOCKSIZE-key_length), (byte)0x5c); // previous hash already copied to correct offset in data //Sha512.reset(); //Sha512.doFinal(data, (short)0, (short)(BLOCKSIZE+HASHSIZE), mac, mac_offset); Sha512.resetUpdateDoFinal(data, (short)0, (short)(BLOCKSIZE+HASHSIZE), mac, mac_offset); return HASHSIZE; } }