/*
 * [TestHMAC.java]
 *
 * Summary: Compute an HMAC, in particular use it to sign a message to the Amazon API.
 *
 * Copyright: (c) 2012-2017 Roedy Green, Canadian Mind Products, http://mindprod.com
 *
 * Licence: This software may be copied and used freely for any purpose but military.
 *          http://mindprod.com/contact/nonmil.html
 *
 * Requires: JDK 1.8+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.0 2012-02-17 initial version
 */
package com.mindprod.example;

import com.mindprod.base64.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;

import static java.lang.System.*;

/**
 * Compute an HMAC, in particular use it to sign a message to the Amazon API.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.0 2012-02-17 initial version
 * @since 2012-02-17
 */
public final class TestHMAC
    {
    /**
     * Amazon SOAP transaction we need to sign.
     * Note the three lines prepended, not part of the message proper.
     * Note precisely where the ?s, &s and \ns are. They are all included in the digest.
     * Even a tiny difference will totally change the digest signature.
     */
    private static final String MESSAGE_TO_SIGN =
            "GET\n"
            + "ecs.amazonaws.com\n"
            + "/onca/xml\n"
            + "AWSAccessKeyId=AKIAI53YWBAHR25L72BAAKIAI53YWBAHR25L72BA"
            + "&AssociateTag=canadianmindprod"
            + "&IdType=EAN"
            + "&ItemId=9781880418116"
            + "&Operation=ItemLookup"
            + "&ResponseGroup=Small"
            + "&SearchIndex=Books"
            + "&Service=AWSECommerceService"
            + "&Timestamp=2012-02-18T02%3A32%3A03.000Z"
            + "&Version=2010-11-01";

    /**
     * shared secret key, assigned by Amazon, plucked from the environment, note getenv not getEnv.
     */
    private static final String SHARED_SECRET_KEY = getenv( "awssecretaccesskey" );

    /**
     * Compute the HMAC checksum of a transaction to the Amazon AWS API..
     *
     * @param args not used
     *
     * @throws java.security.SignatureException       if some problem computing the digital signature.
     * @throws java.security.InvalidKeyException      if there is some problem with the shared secret key.
     * @throws java.security.NoSuchAlgorithmException if HmacSHA256 is not supported.
     */
    public static void main( String[] args ) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException
        {
        // get AN HmacSHA256 key from the raw key bytes
        SecretKeySpec signingKey = new SecretKeySpec( SHARED_SECRET_KEY.getBytes(), "HmacSHA256" );
        // get an Hmac_SHA1 Mac instance and initialize with the signing key
        Mac mac = Mac.getInstance( "HmacSHA256" );
        mac.init( signingKey );
        // compute the HMAC digest as a string of bytes.
        byte[] rawHMAC = mac.doFinal( MESSAGE_TO_SIGN.getBytes() );
        // Base64 is available with source from http://mindprod.com/products.html#BASE64
        String armouredHMAC = new Base64().encode( rawHMAC );
        out.println( armouredHMAC );
        // prints out something like: oXzRbvaDPz+Guwz1KXQSaoF8eHoeSamcR3Vtfvan5/Y=
        // To use, tack that on the end of your transaction, URL-Encoded
        // then your URL looks something like this all one line:
        // https://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=AKIAI53YWBAHR25L72BAAKIAI53YWBAHR25L72BA
        //        &AssociateTag=canadianmindprod
        //        &IdType=EAN
        //        &ItemId=9781880418116
        //        &Operation=ItemLookup
        //        &ResponseGroup=Small
        //        &SearchIndex=Books
        //        &Service=AWSECommerceService
        //        &Timestamp=2012-02-18T02%3A32%3A03.000Z
        //        &Version=2010-11-01
        //        &Signature=oXzRbvaDPz%2BGuwz1KXQSaoF8eHoeSamcR3Vtfvan5%2FY%3D-
        }
    }