/** * This method implements the {@code P_SHA-1} function as defined in the <i>RFC 2246 - The TLS * Protocol Version 1.0 Section 5. HMAC and the pseudorandom function</i>: * * <pre> * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + * HMAC_hash(secret, A(2) + seed) + * HMAC_hash(secret, A(3) + seed) + ... * * Where + indicates concatenation. * * A() is defined as: * A(0) = seed * A(i) = HMAC_hash(secret, A(i-1)) * </pre> * * @param secret a {@code byte[]} that represents the HMAC secret. * @param seed a {@code byte[]} that represents the seed to be used. * @param requiredSize an {@code int} that specifies the size (in bytes) of the result. * @return a {@code byte[]} containing the result of the {@code P_SHA-1} function. * @throws NoSuchAlgorithmException if an error occurs while creating the {@code Mac} instance. * @throws InvalidKeyException if an error occurs while initializing the {@code Mac} instance. */ public static byte[] P_SHA1(byte[] secret, byte[] seed, int requiredSize) throws NoSuchAlgorithmException, InvalidKeyException { int offset = 0, copySize; byte[] result = new byte[requiredSize]; byte[] A, partialResult; SecretKeySpec key = new SecretKeySpec(secret, "HMACSHA1"); Mac mac = Mac.getInstance("HMACSHA1"); // initialize A - A(0) = seed A = seed; while (requiredSize > 0) { // calculate the value of A() mac.init(key); mac.update(A); A = mac.doFinal(); // now calculate HMAC_hash(secret, A + seed) mac.reset(); mac.init(key); mac.update(A); mac.update(seed); partialResult = mac.doFinal(); // copy the necessary bytes to the result. copySize = Math.min(requiredSize, partialResult.length); System.arraycopy(partialResult, 0, result, offset, copySize); offset += copySize; requiredSize -= copySize; } return result; }
/** * From the Lucky13 paper: An individual record R (viewed as a byte sequence of length at least * zero) is processed as follows. The sender maintains an 8-byte sequence number SQN which is * incremented for each record sent, and forms a 5-byte field HDR consisting of a 1-byte type * field, a 2-byte version field, and a 2-byte length field. It then calculates a MAC over the * bytes SQN || HDR || R. * * @param protocolVersion * @param contentType * @param data * @return */ public byte[] calculateMac( ProtocolVersion protocolVersion, ProtocolMessageType contentType, byte[] data) { byte[] SQN = ArrayConverter.longToUint64Bytes(sequenceNumber); byte[] HDR = ArrayConverter.concatenate( contentType.getArrayValue(), protocolVersion.getValue(), ArrayConverter.intToBytes(data.length, 2)); writeMac.update(SQN); writeMac.update(HDR); writeMac.update(data); LOGGER.debug( "The MAC was caluculated over the following data: {}", ArrayConverter.bytesToHexString(ArrayConverter.concatenate(SQN, HDR, data))); byte[] result = writeMac.doFinal(); LOGGER.debug("MAC result: {}", ArrayConverter.bytesToHexString(result)); // we increment sequence number for the sent records sequenceNumber++; return result; }
@Override public String digestParams(RestInvocation restInvocation) { mac.update(restInvocation.getMethodPath().getBytes()); mac.update(new byte[] {0}); mac.update(restInvocation.getRequestBody().getBytes()); return Base64.encodeBytes(mac.doFinal()).trim(); }
/** * Creates the GenericStreamCipher or GenericBlockCipher data structure for specified data of * specified type. * * @throws AlertException if alert was occurred. */ @Override protected byte[] encrypt(byte type, byte[] fragment, int offset, int len) { try { int content_mac_length = len + hash_size; int padding_length = is_block_cipher ? ((8 - (++content_mac_length & 0x07)) & 0x07) : 0; byte[] res = new byte[content_mac_length + padding_length]; System.arraycopy(fragment, offset, res, 0, len); mac_material_header[0] = type; mac_material_header[3] = (byte) ((0x00FF00 & len) >> 8); mac_material_header[4] = (byte) (0x0000FF & len); encMac.update(write_seq_num); encMac.update(mac_material_header); encMac.update(fragment, offset, len); encMac.doFinal(res, len); // if (logger != null) { // logger.println("MAC Material:"); // logger.print(write_seq_num); // logger.print(mac_material_header); // logger.print(fragment, offset, len); // } if (is_block_cipher) { // do padding: Arrays.fill(res, content_mac_length - 1, res.length, (byte) (padding_length)); } if (logger != null) { logger.println( "SSLRecordProtocol.do_encryption: Generic" + (is_block_cipher ? "BlockCipher with padding[" + padding_length + "]:" : "StreamCipher:")); logger.print(res); } byte[] rez = new byte[encCipher.getOutputSize(res.length)]; // We should not call just doFinal because it reinitialize // the cipher, but as says rfc 2246: // "For stream ciphers that do not use a synchronization // vector (such as RC4), the stream cipher state from the end // of one record is simply used on the subsequent packet." // and for block ciphers: // "The IV for subsequent records is the last ciphertext block from // the previous record." // i.e. we should keep the cipher state. encCipher.update(res, 0, res.length, rez); incSequenceNumber(write_seq_num); return rez; } catch (GeneralSecurityException e) { e.printStackTrace(); throw new AlertException( AlertProtocol.INTERNAL_ERROR, new SSLProtocolException("Error during the encryption")); } }
/** * @param sequenceNo * @param data * @param offset * @param len * @return */ public byte[] generate(long sequenceNo, byte[] data, int offset, int len) { // Write the sequence no byte[] sequenceBytes = new byte[4]; sequenceBytes[0] = (byte) (sequenceNo >> 24); sequenceBytes[1] = (byte) (sequenceNo >> 16); sequenceBytes[2] = (byte) (sequenceNo >> 8); sequenceBytes[3] = (byte) (sequenceNo >> 0); mac.update(sequenceBytes); mac.update(data, offset, len); return mac.doFinal(); }
/* * makes an access token. */ public String signRequest(HttpPost post) throws AuthException { URI uri = post.getURI(); String path = uri.getRawPath(); String query = uri.getRawQuery(); HttpEntity entity = post.getEntity(); byte[] secretKey = this.secretKey.getBytes(); javax.crypto.Mac mac = null; try { mac = javax.crypto.Mac.getInstance("HmacSHA1"); } catch (NoSuchAlgorithmException e) { throw new AuthException("No algorithm called HmacSHA1!", e); } SecretKeySpec keySpec = new SecretKeySpec(secretKey, "HmacSHA1"); try { mac.init(keySpec); mac.update(path.getBytes()); } catch (InvalidKeyException e) { throw new AuthException("You've passed an invalid secret key!", e); } catch (IllegalStateException e) { throw new AuthException(e); } if (query != null && query.length() != 0) { mac.update((byte) ('?')); mac.update(query.getBytes()); } mac.update((byte) '\n'); if (entity != null) { org.apache.http.Header ct = entity.getContentType(); if (ct != null && ct.getValue() == "application/x-www-form-urlencoded") { ByteArrayOutputStream w = new ByteArrayOutputStream(); try { entity.writeTo(w); } catch (IOException e) { throw new AuthException(e); } mac.update(w.toByteArray()); } } byte[] digest = mac.doFinal(); byte[] digestBase64 = EncodeUtils.urlsafeEncodeBytes(digest); StringBuffer b = new StringBuffer(); b.append(this.accessKey); b.append(':'); b.append(new String(digestBase64)); return b.toString(); }
/** * Retrieves the fragment of the Plaintext structure of the specified type from the provided data * representing the Generic[Stream|Block]Cipher structure. * * @throws AlertException if alert was occurred. */ @Override protected byte[] decrypt(byte type, byte[] fragment, int offset, int len) { // plain data of the Generic[Stream|Block]Cipher structure byte[] data = decCipher.update(fragment, offset, len); // the 'content' part of the structure byte[] content; if (is_block_cipher) { // check padding int padding_length = data[data.length - 1]; for (int i = 0; i < padding_length; i++) { if (data[data.length - 2 - i] != padding_length) { throw new AlertException( AlertProtocol.DECRYPTION_FAILED, new SSLProtocolException("Received message has bad padding")); } } content = new byte[data.length - hash_size - padding_length - 1]; } else { content = new byte[data.length - hash_size]; } mac_material_header[0] = type; mac_material_header[3] = (byte) ((0x00FF00 & content.length) >> 8); mac_material_header[4] = (byte) (0x0000FF & content.length); decMac.update(read_seq_num); decMac.update(mac_material_header); decMac.update(data, 0, content.length); // mac.update(fragment); byte[] mac_value = decMac.doFinal(); if (logger != null) { logger.println("Decrypted:"); logger.print(data); // logger.println("MAC Material:"); // logger.print(read_seq_num); // logger.print(mac_material_header); // logger.print(data, 0, content.length); logger.println("Expected mac value:"); logger.print(mac_value); } // checking the mac value for (int i = 0; i < hash_size; i++) { if (mac_value[i] != data[i + content.length]) { throw new AlertException( AlertProtocol.BAD_RECORD_MAC, new SSLProtocolException("Bad record MAC")); } } System.arraycopy(data, 0, content, 0, content.length); incSequenceNumber(read_seq_num); return content; }
public static void main(String[] args) throws Exception { // // check args and get plaintext if (args.length != 1) { System.err.println("Usage: java MessageAuthenticationCodeExample text"); System.exit(1); } byte[] plainText = args[0].getBytes("UTF8"); // // get a key for the HmacMD5 algorithm System.out.println("\nStart generating key"); KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5"); SecretKey MD5key = keyGen.generateKey(); System.out.println("Finish generating key"); // // get a MAC object and update it with the plaintext Mac mac = Mac.getInstance("HmacMD5"); mac.init(MD5key); mac.update(plainText); // // print out the provider used and the MAC System.out.println("\n" + mac.getProvider().getInfo()); System.out.println("\nMAC: "); System.out.println(new String(mac.doFinal(), "UTF8")); }
/* * 解析站内应用post的SignedRequest split为part1和part2两部分 */ public String parseSignedRequest(String signed_request) throws IOException, InvalidKeyException, NoSuchAlgorithmException { String[] t = signed_request.split("\\.", 2); // 为了和 url encode/decode 不冲突,base64url 编码方式会将 // '+','/'转换成'-','_',并且去掉结尾的'='。 因此解码之前需要还原到默认的base64编码,结尾的'='可以用以下算法还原 int padding = (4 - t[0].length() % 4); for (int i = 0; i < padding; i++) t[0] += "="; String part1 = t[0].replace("-", "+").replace("_", "/"); SecretKey key = new SecretKeySpec(WeiboConfig.getValue("client_SERCRET").getBytes(), "hmacSHA256"); Mac m; m = Mac.getInstance("hmacSHA256"); m.init(key); m.update(t[1].getBytes()); String part1Expect = BASE64Encoder.encode(m.doFinal()); sun.misc.BASE64Decoder decode = new sun.misc.BASE64Decoder(); String s = new String(decode.decodeBuffer(t[1])); if (part1.equals(part1Expect)) { return ts(s); } else { return null; } }
public int read(byte[] b, int off, int len) throws IOException { int n = in.read(b, off, len); if (n >= 0) { mac.update(b, off, n); } return n; }
public static byte[] deriveSyncKey(byte[] secretBytes, String username) throws GeneralSecurityException { int keySizeInBytes = 256 / 8; Mac hMac = Mac.getInstance("HMACSHA256"); byte[] state = new byte[hMac.getMacLength()]; SecretKeySpec param = new SecretKeySpec(secretBytes, "SHA256"); hMac.init(param); hMac.update(HMAC_INPUT); hMac.update(WeaveUtil.toAsciiBytes(username)); hMac.update((byte) 0x1); hMac.doFinal(state, 0); byte[] retval = new byte[keySizeInBytes]; System.arraycopy(state, 0, retval, 0, keySizeInBytes); return retval; }
/** * This method: Encrypts bytes using a cipher. Generates MAC for intialization vector of the * cipher Generates MAC for encrypted data Returns a byte array consisting of the following * concatenated together: |MAC for cnrypted Data | MAC for Init Vector | Encrypted Data | * * @param bytes The byte array to be encrypted. * @return the encrypted byte array. */ public byte[] encrypt(byte[] bytes) { byte[] securedata = null; try { // Generate IV SecureRandom rand = new SecureRandom(); byte[] iv = new byte[16]; rand.nextBytes(iv); IvParameterSpec ivspec = new IvParameterSpec(iv); Cipher encryptCipher = Cipher.getInstance(CIPHER_CODE); encryptCipher.init(Cipher.ENCRYPT_MODE, sk, ivspec); Mac encryptMac = Mac.getInstance(MAC_CODE); encryptMac.init(sk); encryptMac.update(iv); // encrypt the plaintext byte[] encdata = encryptCipher.doFinal(bytes); byte[] macBytes = encryptMac.doFinal(encdata); byte[] tmp = concatBytes(macBytes, iv); securedata = concatBytes(tmp, encdata); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalStateException | IllegalBlockSizeException | BadPaddingException e) { if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.log( Level.SEVERE, "Unexpected exception initializing encryption." + " No encryption will be performed.", e); } return null; } return securedata; }
@Override public String digestParams(RestInvocation restInvocation) { String postBody = restInvocation.getRequestBody(); mac.update(Base64.encodeBytes(postBody.getBytes()).getBytes()); return String.format("%096x", new BigInteger(1, mac.doFinal())); }
public int read() throws IOException { int b = in.read(); if (b >= 0) { mac.update((byte) b); } return b; }
private static void JCE_HMACSHA1( byte[] key, byte[] inOut, byte[] roc, int offset, int len, int testround) { try { Mac mac = Mac.getInstance("HmacSHA1", "SunJCE"); mac.init(new SecretKeySpec(key, "HmacSHA1")); long time = System.nanoTime(); for (int r = 0; r < testround; r++) { mac.update(inOut, offset, len); mac.update(roc); mac.doFinal(inOut, offset + len); } System.out.println("JCE_HMACSHA1 : " + ((System.nanoTime() - time) / testround)); } catch (Exception e) { System.out.println("JCE_HMACSHA1 : " + e); } }
public static byte[] createSaltedPassword(byte[] salt, String password, int iters) throws SaslException { Mac mac = createSha1Hmac(password.getBytes(StandardCharsets.UTF_8)); mac.update(salt); mac.update(new byte[] {0, 0, 0, 1}); byte[] result = mac.doFinal(); byte[] previous = null; for (int i = 1; i < iters; i++) { mac.update(previous != null ? previous : result); previous = mac.doFinal(); for (int x = 0; x < result.length; x++) { result[x] ^= previous[x]; } } return result; }
private static void BC_HMACSHA1( byte[] key, byte[] inOut, byte[] roc, int offset, int len, int testround) { try { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); Mac mac = Mac.getInstance("HmacSHA1", "BC"); mac.init(new SecretKeySpec(key, "HmacSHA1")); long time = System.nanoTime(); for (int r = 0; r < testround; r++) { mac.update(inOut, offset, len); mac.update(roc); mac.doFinal(inOut, offset + len); } System.out.println("BC_HMACSHA1 : " + ((System.nanoTime() - time) / testround)); } catch (Exception e) { System.out.println("BC_HMACSHA1 : " + e); } }
/** * This method decrypts the provided byte array. The decryption is only performed if the * regenerated MAC is the same as the MAC for the received value. * * @param bytes Encrypted byte array to be decrypted. * @return Decrypted byte array. */ public byte[] decrypt(byte[] bytes) { try { // Extract MAC byte[] macBytes = new byte[MAC_LENGTH]; System.arraycopy(bytes, 0, macBytes, 0, macBytes.length); // Extract IV byte[] iv = new byte[IV_LENGTH]; System.arraycopy(bytes, macBytes.length, iv, 0, iv.length); // Extract encrypted data byte[] encdata = new byte[bytes.length - macBytes.length - iv.length]; System.arraycopy(bytes, macBytes.length + iv.length, encdata, 0, encdata.length); IvParameterSpec ivspec = new IvParameterSpec(iv); Cipher decryptCipher = Cipher.getInstance(CIPHER_CODE); decryptCipher.init(Cipher.DECRYPT_MODE, sk, ivspec); // verify MAC by regenerating it and comparing it with the received value Mac decryptMac = Mac.getInstance(MAC_CODE); decryptMac.init(sk); decryptMac.update(iv); decryptMac.update(encdata); byte[] macBytesCalculated = decryptMac.doFinal(); if (areArrayEqualsConstantTime(macBytes, macBytesCalculated)) { // continue only if the MAC was valid // System.out.println("Valid MAC found!"); byte[] plaindata = decryptCipher.doFinal(encdata); return plaindata; } else { System.err.println("ERROR: MAC did not verify!"); return null; } } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalStateException | IllegalBlockSizeException | BadPaddingException e) { System.err.println("ERROR: Decrypting:" + e.getCause()); return null; // Signal to JSF runtime } }
private static void SunPKCS11_HMACSHA1( byte[] key, byte[] inOut, byte[] roc, int offset, int len, int testround) { try { Provider provider = new sun.security.pkcs11.SunPKCS11( "--name=test456\\n" + "nssDbMode=noDb\\n" + "attributes=compatibility"); Mac mac = Mac.getInstance("HmacSHA1", provider); mac.init(new SecretKeySpec(key, "HmacSHA1")); long time = System.nanoTime(); for (int r = 0; r < testround; r++) { mac.update(inOut, offset, len); mac.update(roc); mac.doFinal(inOut, offset + len); } System.out.println("SunPKCS11_HMACSHA1 : " + ((System.nanoTime() - time) / testround)); } catch (Exception e) { System.out.println("SunPKCS11_HMACSHA1 : " + e); } }
@Override public String digestParams(RestInvocation RestInvocation) { try { String postBody = RestInvocation.getRequestBody(); mac.update(postBody.getBytes("UTF-8")); return String.format("%0128x", new BigInteger(1, mac.doFinal())); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Illegal encoding, check the code.", e); } // return Base64.encodeBytes(mac.doFinal()).trim(); }
/** * Updates the given {@link Mac}. This generates a digest for valueToDigest and the key the Mac * was initialized * * @param mac the initialized {@link Mac} to update * @param valueToDigest the value to update the {@link Mac} with * <p>The InputStream must not be null and will not be closed * @return the updated {@link Mac} * @throws IOException If an I/O error occurs. * @throws IllegalStateException If the Mac was not initialized * @since 1.x */ public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException { mac.reset(); final byte[] buffer = new byte[STREAM_BUFFER_LENGTH]; int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH); while (read > -1) { mac.update(buffer, 0, read); read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH); } return mac; }
public byte[] calculateDtlsMac( ProtocolVersion protocolVersion, ProtocolMessageType contentType, byte[] data, long dtlsSequenceNumber, int epochNumber) { byte[] SQN = ArrayConverter.concatenate( ArrayConverter.intToBytes(epochNumber, 2), ArrayConverter.longToUint48Bytes(dtlsSequenceNumber)); byte[] HDR = ArrayConverter.concatenate( contentType.getArrayValue(), protocolVersion.getValue(), ArrayConverter.intToBytes(data.length, 2)); writeMac.update(SQN); writeMac.update(HDR); writeMac.update(data); if (LOGGER.isDebugEnabled()) { LOGGER.debug( "The MAC will be caluculated over the following data: {}", ArrayConverter.bytesToHexString( ArrayConverter.concatenate( ArrayConverter.intToBytes(epochNumber, 2), ArrayConverter.longToUint48Bytes(sequenceNumber), HDR, data))); } byte[] result = writeMac.doFinal(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("MAC result: {}", ArrayConverter.bytesToHexString(result)); } return result; }
@Override public String digestParams(RestInvocation restInvocation) { final String message = restInvocation.getParamValue(HeaderParam.class, "ACCESS_NONCE").toString() + restInvocation.getInvocationUrl() + restInvocation.getRequestBody(); Mac mac256 = getMac(); mac256.update(message.getBytes()); return String.format("%064x", new BigInteger(1, mac256.doFinal())); }
@Override public void handle(Address address, ByteBuffer buffer) { if ((cipher == null) || (mac == null)) { sequence++; wrappee.handle(address, buffer); return; } ByteBuffer sequenceBuffer = ByteBuffer.allocate(Ints.BYTES); sequenceBuffer.putInt(sequence); sequence++; sequenceBuffer.flip(); mac.reset(); mac.update(sequenceBuffer); int p = buffer.position(); mac.update(buffer); buffer.position(p); byte[] calculatedMac = new byte[mac.getMacLength()]; try { mac.doFinal(calculatedMac, 0); } catch (ShortBufferException e) { throw new RuntimeException(e); } catch (IllegalStateException e) { throw new RuntimeException(e); } ByteBuffer b = ByteBuffer.allocate(buffer.remaining() + calculatedMac.length); try { cipher.update(buffer, b); } catch (ShortBufferException e) { throw new RuntimeException(e); } b.put(calculatedMac); b.flip(); wrappee.handle(address, b); }
private static void derivePKCS5S2Helper( Mac hMac, byte[] P, byte[] S, int c, byte[] iBuf, byte[] out, int outOff) throws GeneralSecurityException { byte[] state = new byte[hMac.getMacLength()]; SecretKeySpec param = new SecretKeySpec(P, "SHA1"); hMac.init(param); if (S != null) { hMac.update(S, 0, S.length); } hMac.update(iBuf, 0, iBuf.length); hMac.doFinal(state, 0); System.arraycopy(state, 0, out, outOff, state.length); if (c == 0) { throw new IllegalArgumentException("iteration count must be at least 1."); } for (int count = 1; count < c; count++) { hMac.init(param); hMac.update(state, 0, state.length); hMac.doFinal(state, 0); for (int j = 0; j != state.length; j++) { out[outOff + j] ^= state[j]; } } }
/** * Computes a message authentication code of a given text (as byte array) with a given key and a * nonce (iv). * * @param iv Nonce that is used to create MAC. * @param key Key that is used to create MAC. * @param text Text that is used to create MAC. * @param textOffset starting index of the text * @param buffer result buffer that will hold the calculated MAC. * @param offset @return Returns the MAC as byte array. */ @Override public void computeMAC( byte[] iv, SecretKey key, byte[] text, int textOffset, byte[] buffer, int offset) { try { AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv); messageAuthenticationCode.init(key, ivSpec); messageAuthenticationCode.update(text, textOffset, text.length - textOffset); messageAuthenticationCode.doFinal(buffer, offset); } catch (Exception e) { // Error logging ErrorLoggingSingleton log = ErrorLoggingSingleton.getInstance(); log.storeError(ErrorLoggingSingleton.getExceptionStackTraceAsFormattedString(e)); throw new RuntimeException(); } }
public FileDigester( final String pathToFile, final pt.mleiria.algorithm.MessageAuthenticationCode md, final String pwd) throws NoSuchAlgorithmException, FileNotFoundException, IOException, InvalidKeyException { final File f = new File(pathToFile); final FileInputStream in = new FileInputStream(f); final FileChannel fchannel = in.getChannel(); final ByteBuffer bytebuf = ByteBuffer.allocate((int) f.length()); fchannel.read(bytebuf); final SecretKey key = new SecretKeySpec(pwd.getBytes("UTF-8"), md.value()); final Mac m = Mac.getInstance(md.value()); m.init(key); m.update(bytebuf); raw = m.doFinal(); }
private String getSignature(String operation, String timeStamp, byte[] secretBytes) { try { String toSign = operation + timeStamp; byte[] toSignBytes = getBytes(toSign); Mac signer = Mac.getInstance("HmacSHA256"); SecretKeySpec keySpec = new SecretKeySpec(secretBytes, "HmacSHA256"); signer.init(keySpec); signer.update(toSignBytes); byte[] signBytes = signer.doFinal(); String signature = new String(Base64.encodeBase64(signBytes)); return signature; } catch (Exception e) { throw new RuntimeException("NoSuchAlgorithmException thrown.", e); } }
/** * Compute the Message Authentication Code (MAC) value over the supplied input. * * <p>It is up to the caller to ensure that the specified algorithm ID is consistent with the type * of signing key supplied. * * @param signingKey the key with which to compute the MAC * @param jcaAlgorithmID the Java JCA algorithm ID to use * @param input the input over which to compute the MAC * @return the computed MAC value * @throws SecurityException thrown if the MAC computation results in an error */ public static byte[] signMAC(Key signingKey, String jcaAlgorithmID, byte[] input) throws SecurityException { log.debug( "Computing MAC over input using key of type {} and JCA algorithm ID {}", signingKey.getAlgorithm(), jcaAlgorithmID); try { Mac mac = Mac.getInstance(jcaAlgorithmID); mac.init(signingKey); mac.update(input); byte[] rawMAC = mac.doFinal(); log.debug("Computed MAC: {}", new String(Hex.encode(rawMAC))); return rawMAC; } catch (GeneralSecurityException e) { log.error("Error during MAC generation", e); throw new SecurityException("Error during MAC generation", e); } }
/** * Sign a message from this slave with the shared secret. This method will overwrite the last * SIGNATURE_SIZE bytes of the given buffer with the following data: [4 bytes] - a per-client * counter to prevent replays [20 bytes] - a SHA-1 signature on the rest of the client data * * @param message the message to sign * @return the signed message. This method does not create a new byte array, it just signs the * message in place. The return value is a convenience for chaining. */ private synchronized byte[] sign(byte[] message) { int idx = message.length - Proto.SIGNATURE_SIZE; // encode the counter counter++; message[idx++] = (byte) ((counter >> 24) & 0xff); message[idx++] = (byte) ((counter >> 16) & 0xff); message[idx++] = (byte) ((counter >> 8) & 0xff); message[idx++] = (byte) (counter & 0xff); // now sign the whole thing try { mac.update(message, 0, idx); mac.doFinal(message, idx); } catch (ShortBufferException sbe) { // shouldn't happen throw new IllegalStateException(sbe); } return message; }