0

I am trying to dynamically generate a password to be sent with each api request to mpesa apis. According to documentation I need to first concatenate the provided passkey with timestamp and merchant id and then do a sha256 to get a hashed password which I should then encode to base 64 however doing this in Java returns a wrong encoded string whereas a similar process and code works in PHP, where could I be going wrong?

import org.apache.commons.codec.binary.Base64;
import org.apache.cxf.headers.Header;
import org.apache.cxf.jaxb.JAXBDataBinding;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;



public class CheckoutHeaderBuilder {

    public static Header buildHeader(String merchantId, String passKey, String timestamp) throws JAXBException, NoSuchAlgorithmException, UnsupportedEncodingException {
    String hashedEncodedPass = Base64.encodeBase64String(MessageDigest.getInstance("SHA-256").digest((merchantId + passKey + timestamp).getBytes("utf-8")));

    List<Header> headers = new ArrayList<>();
    CheckOutHeader checkOutHeader = new CheckOutHeader();
    checkOutHeader.setTIMESTAMP(timestamp);
    checkOutHeader.setMERCHANTID(merchantId);
    checkOutHeader.setPASSWORD(hashedEncodedPass);
    return new Header(new QName("tns:ns", "CheckOutHeader"), checkOutHeader, new JAXBDataBinding(CheckOutHeader.class));

    }

}
zaph
  • 111,848
  • 21
  • 189
  • 228

3 Answers3

1

Hi Japheth Ongeri Inkalimeva, you do not have to encrypt using SHA256. You may not need to neccesarily set a new password when sending a Lipa na M-Pesa Online Payment API request.

I have ammended your code to remove SHA256 encryption.

import org.apache.commons.codec.binary.Base64;
import org.apache.cxf.headers.Header;
import org.apache.cxf.jaxb.JAXBDataBinding;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;


public class CheckoutHeaderBuilder  {

    public static Header buildHeader(String merchantId, String passKey, String timestamp) throws JAXBException, NoSuchAlgorithmException, UnsupportedEncodingException {
    String hashedEncodedPass = Base64.encodeBase64String((merchantId + passKey + timestamp).getBytes("utf-8"));

    List<Header> headers = new ArrayList<>();
    CheckOutHeader checkOutHeader = new CheckOutHeader();
    checkOutHeader.setTIMESTAMP(timestamp);
    checkOutHeader.setMERCHANTID(merchantId);
    checkOutHeader.setPASSWORD(hashedEncodedPass);
    return new Header(new QName("tns:ns", "CheckOutHeader"), checkOutHeader, new JAXBDataBinding(CheckOutHeader.class));

    }

}
Beliot
  • 134
  • 1
  • 6
  • This won't work, it amounts to sending the password in plaintext(with just base64 encoding) without hashing which is highly unsecured. That is why the documentation specifically requires sha256 hashing. – Japheth Ongeri - inkalimeva Dec 18 '17 at 14:35
  • @JaphethOngeri-inkalimeva You do not need to hash it. As the API doc indicates you are expected to concatenate merchantcode, passkey and timestamp, then encode it in base64. – S.Serem Jun 29 '18 at 04:56
1

Example encode SHA256

import java.nio.charset.StandardCharsets;
import com.google.common.hash.Hashing;

String password = “123456”;
Hashing.sha256().hashString(password, StandardCharsets.UTF_8).toString();

Hope will help you

0

You can encode the password for Mpesa in this way:

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class MpesaUtils {

    public static String getMpesaEncodedPassword(String lipaNaMpesaShortCode,
                              String password, String timeStamp) {
        StringBuilder sb = new StringBuilder();
        sb.append(lipaNaMpesaShortCode).append(password).append(timeStamp);

        byte[] bytes = sb.toString().getBytes(StandardCharsets.ISO_8859_1);
        return Base64.getEncoder().encodeToString(bytes);
    }
}

Usage example:

    String lnmShortCode = "your lipa na mpesa short code here";
    String password = "your password here";
    String timeStamp = getTimeStamp();

    String encodedPassword = MpesaUtils.getMpesaEncodedPassword(lnmShortCode, password, timeStamp);
zdrsoft
  • 2,417
  • 19
  • 10