This is a Java example of how to enable HMAC signing within your application. The example implementation of the HMAC signing algorithm allows you to authenticate with the Veracode APIs.
HmacRequestSigner.java
package com.veracode.hmac_request_signing; import java.io.UnsupportedEncodingException; import java.net.URL; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Locale; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; public final class HmacRequestSigner { // Included in the signature to inform Veracode of the signature version. private static final String VERACODE_REQUEST_VERSION_STRING = "vcode_request_version_1"; // Expected format for the unencrypted data string. private static final String DATA_FORMAT = "id=%s&host=%s&url=%s&method=%s"; // Expected format for the Authorization header. private static final String HEADER_FORMAT = "%s id=%s,ts=%s,nonce=%s,sig=%s"; // Expect prefix to the Authorization header. private static final String VERACODE_HMAC_SHA_256 = "VERACODE-HMAC-SHA-256"; // HMAC encryption algorithm. private static final String HMAC_SHA_256 = "HmacSHA256"; // Charset to use when encrypting a string. private static final String UTF_8 = "UTF-8"; // A cryptographically secure random number generator. private static final SecureRandom secureRandom = new SecureRandom(); // Private constructor. private HmacRequestSigner() { /* * This is a utility class that should only be accessed through its * static methods. */ } /** * Entry point for HmacRequestSigner. Returns the value for the * Authorization header for use with Veracode APIs when provided an API id, * secret key, and target URL. * * @param id * An API id for authentication * @param key * The secret key corresponding to the API id * @param url * The URL of the called API, including query parameters * * @return The value to be put in the Authorization header * * @throws UnsupportedEncodingException * @throws IllegalStateException * @throws NoSuchAlgorithmException * @throws InvalidKeyException */ public static String getVeracodeAuthorizationHeader(final String id, final String key, final URL url, final String httpMethod) throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException { final String urlPath = (url.getQuery() == null) ? url.getPath() : url.getPath().concat("?").concat(url.getQuery()); final String data = String.format(DATA_FORMAT, id, url.getHost(), urlPath, httpMethod); final String timestamp = String.valueOf(System.currentTimeMillis()); final String nonce = DatatypeConverter.printHexBinary(generateRandomBytes(16)).toLowerCase(Locale.US); final String signature = getSignature(key, data, timestamp, nonce); return String.format(HEADER_FORMAT, VERACODE_HMAC_SHA_256, id, timestamp, nonce, signature); } /* * Generate the signature expected by the Veracode platform by chaining * encryption routines in the correct order. */ private static String getSignature(final String key, final String data, final String timestamp, final String nonce) throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException { final byte[] keyBytes = DatatypeConverter.parseHexBinary(key); final byte[] nonceBytes = DatatypeConverter.parseHexBinary(nonce); final byte[] encryptedNonce = hmacSha256(nonceBytes, keyBytes); final byte[] encryptedTimestamp = hmacSha256(timestamp, encryptedNonce); final byte[] signingKey = hmacSha256(VERACODE_REQUEST_VERSION_STRING, encryptedTimestamp); final byte[] signature = hmacSha256(data, signingKey); return DatatypeConverter.printHexBinary(signature).toLowerCase(Locale.US); } // Encrypt a string using the provided key. private static byte[] hmacSha256(final String data, final byte[] key) throws NoSuchAlgorithmException, InvalidKeyException, IllegalStateException, UnsupportedEncodingException { final Mac mac = Mac.getInstance(HMAC_SHA_256); mac.init(new SecretKeySpec(key, HMAC_SHA_256)); return mac.doFinal(data.getBytes(UTF_8)); } // Encrypt a byte array using the provided key. private static byte[] hmacSha256(final byte[] data, final byte[] key) throws NoSuchAlgorithmException, InvalidKeyException { final Mac mac = Mac.getInstance(HMAC_SHA_256); mac.init(new SecretKeySpec(key, HMAC_SHA_256)); return mac.doFinal(data); } // Generate a random byte array for cryptographic use. private static byte[] generateRandomBytes(final int size) { final byte[] key = new byte[size]; secureRandom.nextBytes(key); return key; } }
Main.java
package com.veracode.hmac_request_signing; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.InvalidKeyException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.json.JSONException; import org.json.JSONObject; public class Main { private static final String URL_BASE = "api.veracode.com"; private static final String URL_PATH = "/appsec/v1/applications/"; private static final String GET = "GET"; private static final String APP_GUID = "8b86411e-65f9-4224-948a-64559c777d10"; private static final String ACCESS_KEY_ID = "dbb6f2a2ed0b6890bbd32e949f72c8c8"; private static final String SECRET_ACCESS_KEY = "530da152f87e5530c82f786907fbc74b09a6894785a78bab3891632ba69325400a40713bdc11d2a6d2d1c3969431281c0a73f455a53c0ed5ea0756e9c54f366c"; /** * The main method for our demo. This makes a simple API call using our example HMAC signing class * and writes the response to the output stream. * * @param args command line arguments - ignored */ public static void main(final String[] args) { try { /* * Combine the URL base with the specific URL endpoint we wish to access. * This is REST, so the GUID we are accessing is in the URL. */ final URL applicationsApiUrl = new URL("https://" + URL_BASE + URL_PATH + APP_GUID); /* * Now we use the url above and our example HMAC signer class to generate a Veracode HMAC header for later use. */ final String authorizationHeader = HmacRequestSigner.getVeracodeAuthorizationHeader(ACCESS_KEY_ID, SECRET_ACCESS_KEY, applicationsApiUrl, GET); /* * Here we are using Java built in HTTPS protocols to handle making a call to the API's URL. * We also set the request method to GET. */ final HttpsURLConnection connection = (HttpsURLConnection) applicationsApiUrl.openConnection(); connection.setRequestMethod(GET); /* * This is where we add the Authorization header with the value returned by our example HMAC signer class. */ connection.setRequestProperty("Authorization", authorizationHeader); /* * Now we just need to make the actual call by opening up the response stream and read from it. */ try (InputStream responseInputStream = connection.getInputStream()) { readResponse(responseInputStream); } } catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) { e.printStackTrace(); } } /* * A simple method to read an input stream (containing JSON) to System.out. */ private static void readResponse(InputStream responseInputStream) throws IOException, JSONException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] responseBytes = new byte[16384]; int x = 0; while ((x = responseInputStream.read(responseBytes, 0, responseBytes.length)) != -1) { outputStream.write(responseBytes, 0, x); } outputStream.flush(); System.out.println((new JSONObject(outputStream.toString())).toString(4)); } }