# How to perform Base64 on top of HASH in Java

**URL:** <https://community.rapyd.net/t/how-to-perform-base64-on-top-of-hash-in-java/1801>\
**Category:** ⚙️ API\
**Created:** [May 22, 2022, 8:51pm UTC](https://community.rapyd.net/t/how-to-perform-base64-on-top-of-hash-in-java/1801 "2022-05-22T20:51:11Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![abiieez](https://sea2.discourse-cdn.com/flex016/user_avatar/community.rapyd.net/abiieez/32/1739_2.png) [@abiieez](https://community.rapyd.net/u/abiieez)\
**Post date:** [May 22, 2022, 8:51pm UTC](https://community.rapyd.net/t/how-to-perform-base64-on-top-of-hash-in-java/1801/1 "2022-05-22T20:51:11Z")

</div>

I tried the following but still get 401 Unauthorized: [no body]

```auto
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("access_key", accessKey);
        long currentTimestamp = (System.currentTimeMillis() / 1000) - 10;
        headers.add("timestamp", String.valueOf(currentTimestamp));
        String randomSalt = generateRandomAlphanumericString();
        headers.add("salt", randomSalt);

        JSONObject body = new JSONObject();
        body.put("amount", 123.45);
        body.put("complete_payment_url", "http://example.com/complete");
        body.put("country", "ID");
        body.put("currency", "IDR");
        body.put("error_payment_url", "IDR");
        body.put("merchant_reference_id", "IDR");
        body.put("cardholder_preferred_currency", "IDR");
        body.put("language", "en");
        body.put("metadata", "something");
        body.put("payment_method_types_include", List.of("id_ovo_ewallet",
            "id_dana_ewallet",
            "id_linkaja_ewallet"));

        String tobeSigned = HttpMethod.POST.toString().toLowerCase() + "/v1/checkout" + randomSalt + currentTimestamp + accessKey
            + secretKey + body;

        log.info("to_sign {}",tobeSigned);
        String encodedString = encode(secretKey,tobeSigned);
        log.info("rapyd_signature {}", encodedString);
        headers.add("signature", encodedString);

        HttpEntity<String> entity = new HttpEntity<>(body.toString(), headers);

        ResponseEntity<String> result = restTemplate.exchange(baseUrl + "/checkout", HttpMethod.POST, entity, String.class);

```

---

<div class="post-metadata">

**Author:** ![sandy\_inspires](https://sea2.discourse-cdn.com/flex016/user_avatar/community.rapyd.net/sandy_inspires/32/1732_2.png) [@sandy\_inspires](https://community.rapyd.net/u/sandy_inspires)\
**Post date:** [May 23, 2022, 3:58am UTC](https://community.rapyd.net/t/how-to-perform-base64-on-top-of-hash-in-java/1801/2 "2022-05-23T03:58:21Z")

</div>

Use this example from the docs - [Message Security (rapyd.net)](https://docs.rapyd.net/build-with-rapyd/reference/message-security#request-signatures)  
Once the body is created, try to do a string replacement of spaces. (You’ll get a signature mismatch if you don’t - in some cases)

```auto
body.replace(" ", "");

```

```auto
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Random;

public class GetPOS {
    
    public static String hash256(String data) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(data.getBytes());
        return bytesToHex(md.digest());
    }
    
    public static String bytesToHex(byte[]bytes) {
        StringBuffer result = new StringBuffer();
        for (byte byt: bytes)
            result.append(Integer.toString((byt & 0xff) + 0x100, 16).substring(1));
        return result.toString();
    }
    
    public static String hmacDigest(String msg, String keyString, String algo) {
        String digest = null;
        try {
            SecretKeySpec key = new SecretKeySpec((keyString).getBytes("ASCII"), algo);
            Mac mac = Mac.getInstance(algo);
            mac.init(key);
            
            byte[]bytes = mac.doFinal(msg.getBytes("UTF-8"));
            
            StringBuffer hash = new StringBuffer();
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(0xFF & bytes[i]);
                if (hex.length() == 1) {
                    hash.append('0');
                }
                hash.append(hex);
            }
            digest = hash.toString();
        } catch (UnsupportedEncodingException e) {
            System.out.println("hmacDigest UnsupportedEncodingException");
        }
        catch (InvalidKeyException e) {
            System.out.println("hmacDigest InvalidKeyException");
        }
        catch (NoSuchAlgorithmException e) {
            System.out.println("hmacDigest NoSuchAlgorithmException");
        }
        return digest;
    }
    
    public static String givenUsingPlainJava_whenGeneratingRandomStringUnbounded_thenCorrect() {
        int leftLimit = 97; // letter 'a'
        int rightLimit = 122; // letter 'z'
        int targetStringLength = 10;
        Random random = new Random();
        StringBuilder buffer = new StringBuilder(targetStringLength);
        for (int i = 0; i < targetStringLength; i++) {
            int randomLimitedInt = leftLimit + (int)
                (random.nextFloat() * (rightLimit - leftLimit + 1));
            buffer.append((char)randomLimitedInt);
        }
        String generatedString = buffer.toString();
        
        return (generatedString);
    }

    public static void main(String[]args)throws Exception {
        try {
            System.out.println("GetPOS Start");
                  String httpMethod = "get"; // get|put|post|delete - must be lowercase
                  String urlPath = "/v1/" + "data/countries"; // hardkeyed for this example
            String salt = givenUsingPlainJava_whenGeneratingRandomStringUnbounded_thenCorrect(); // Randomly generated for each request.
            long timestamp = System.currentTimeMillis() / 1000L; // Unix time (seconds).
            String accessKey = "AAAAAAAAAAA"; // The access key received from Rapyd.
            String secretKey = "SSSSSSSSSSS"; // Never transmit the secret key by itself.
                  bodyString = ""; // Always empty for GET; strip nonfunctional whitespace.
                                                                       // Must be a String or an empty String.
            String toEnc = httpMethod + urlPath + salt + Long.toString(timestamp) + accessKey + secretKey + bodyString;
            System.out.println("String to be encrypted::" + toEnc);
            String StrhashCode = hmacDigest(toEnc, secretKey, "HmacSHA256");
            String signature = Base64.getEncoder().encodeToString(StrhashCode.getBytes());
            HttpClient httpclient = HttpClients.createDefault();
            
            try {
                HttpGet httpget = new HttpGet("/v1/data/countries");
                
                httpget.addHeader("Content-Type", "application/json");
                httpget.addHeader("access_key", accessKey);
                httpget.addHeader("salt", salt);
                httpget.addHeader("timestamp", Long.toString(timestamp));
                httpget.addHeader("signature", signature);
                
                // Create a custom response handler
                ResponseHandler < String > responseHandler = new ResponseHandler < String > () {
                     @ Override
                    public String handleResponse(
                        final HttpResponse response)throws ClientProtocolException,
                    IOException {
                        int status = response.getStatusLine().getStatusCode();
                        HttpEntity entity = response.getEntity();
                        return entity != null ? EntityUtils.toString(entity) : null;
                    }
                };
                String responseBody = httpclient.execute(httpget, responseHandler);
                System.out.println("----------------------------------------");
                System.out.println(responseBody);
            }
            finally {
            }
        } catch (Exception e) {
        }
    }
}

```

---

<div class="post-metadata">

**Author:** ![fredjinbility](https://avatars.discourse-cdn.com/v4/letter/f/22d042/32.png) [@fredjinbility](https://community.rapyd.net/u/fredjinbility)\
**Post date:** [May 23, 2022, 5:04am UTC](https://community.rapyd.net/t/how-to-perform-base64-on-top-of-hash-in-java/1801/3 "2022-05-23T05:04:27Z")

</div>

In addition to solution posted @sandy_inspires. These are my own observations in your body parameters. You will need to enter correct value where appropriate

1.) The **error\_payment\_url** should be a working url under http or https. Entering anything other thing like localhost will create a **no body error message**

2.) and Many more.  
Finally, here is a clear documentations on how to create a checkout page. [checkout page creation doc.](https://docs.rapyd.net/build-with-rapyd/reference/checkout-page-object#create-checkout-page)

I hope this will also help you in trouble shooting you error

---

<div class="post-metadata">

**Author:** ![fredjinbility](https://avatars.discourse-cdn.com/v4/letter/f/22d042/32.png) [@fredjinbility](https://community.rapyd.net/u/fredjinbility)\
**Post date:** [May 23, 2022, 7:05am UTC](https://community.rapyd.net/t/how-to-perform-base64-on-top-of-hash-in-java/1801/5 "2022-05-23T07:05:11Z")

</div>

@CharlesDorsett ,you are right. decimal points is not a problem. After I trouble shoot my php codes, I found out they are some whitespaces and little err on my code from my own end. I have fixed it and everything is working great now. Thanks for pointing me out in the right direction…

---

<div class="post-metadata">

**Author:** ![abiieez](https://sea2.discourse-cdn.com/flex016/user_avatar/community.rapyd.net/abiieez/32/1739_2.png) [@abiieez](https://community.rapyd.net/u/abiieez)\
**Post date:** [May 23, 2022, 9:08am UTC](https://community.rapyd.net/t/how-to-perform-base64-on-top-of-hash-in-java/1801/6 "2022-05-23T09:08:22Z")

</div>

Glad got it working now. Thanks everyone!
