/* ******************************************************************************* * Java Card Bitcoin Hardware Wallet * (c) 2015 Ledger * * 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 com.ledger.wallet; import javacard.framework.Util; public class HmacSha512 { private static final short DIGEST_SIZE = 64; private static final byte IPAD = (byte)0x36; private static final byte OPAD = (byte)0x5c; private static final short BLOCK_SIZE = (short)128; public static void hmac(byte[] key, short keyOffset, short keyLength, byte[] data, short dataOffset, short dataLength, byte[] out, short outOffset, byte[] block, short blockOffset) { byte i; boolean nativeSha512 = (Crypto.digestSha512 != null); if (!nativeSha512) { Crypto.sha512.init(); } for (i=0; i<2; i++) { Util.arrayFillNonAtomic(block, blockOffset, BLOCK_SIZE, (i == 0 ? IPAD : OPAD)); for (short j=0; j<keyLength; j++) { block[(short)(blockOffset + j)] ^= key[(short)(keyOffset + j)]; } if (nativeSha512) { Crypto.digestSha512.update(block, blockOffset, BLOCK_SIZE); } else { Crypto.sha512.update(block, blockOffset, BLOCK_SIZE); } if (i == 0) { if (nativeSha512) { Crypto.digestSha512.doFinal(data, dataOffset, dataLength, out, outOffset); } else { Crypto.sha512.doFinal(data, dataOffset, dataLength, out, outOffset); } } else { if (nativeSha512) { Crypto.digestSha512.doFinal(out, outOffset, DIGEST_SIZE, out, outOffset); } else { Crypto.sha512.doFinal(out, outOffset, DIGEST_SIZE, out, outOffset); } } } } }