I have an Android client that sends JSON data to my spring boot application server.
In other to maintain a certain level of data integrity during communication I require that the original payload be hashed and then set into the outgoing payload along with the original JSON data.
This is what I mean (Android Client)
signUpUserRequest = new SignUpUserRequest(
lastName.getText().toString(),
Long.valueOf(phoneNumber.getText().toString().trim()),
emailAddress.getText().toString(),
Config.getAndroidId(this),
Type.INDIVIDUAL.toString(),
firstName.getText().toString(),
Config.ToBase64Encode(confirmPassword.getText().toString())
);
signUpUserRequest.setHash(Config.HashString(signUpUserRequest.toDataString().trim()));
Below is the the SignUpUserRequest
Pojo (Setters and getters removed for brevity)
public class SignUpUserRequest {
private String firstName;
private String lastName;
private long phoneNumber;
private String type;
private String email;
private String password;
private String phoneId;
private String hash;
public SignUpUserRequest(String lastName, Long phoneNumber, String email, String phoneId, String type, String firstName, String password) {
this.lastName = lastName;
this.phoneNumber = phoneNumber;
this.email = email;
this.phoneId = phoneId;
this.type = type;
this.firstName = firstName;
this.password = password;
}
.... setters and getters removed ....
public String toDataString() {
return "SignUpUserRequest{" + "firstName=" + firstName + ", lastName=" + lastName + ", phoneNumber=" + phoneNumber + ", type=" + type + ", email=" + email + ", password=" + password + ", phoneId=" + phoneId + '}';
}
@Override
public String toString() {
return "SignUpUserRequest{" + "firstName=" + firstName + ", lastName=" + lastName + ", phoneNumber=" + phoneNumber + ", type=" + type + ", email=" + email + ", password=" + password + ", phoneId=" + phoneId + ", hash=" + hash + '}';
}
The problem I have is when I send the JSON over to my spring boot application and then carry out an integrity check on the request data, the hash generated on the server side is always different from the hash generated on the client side.
Server Side Code (Spring boot Application)
public ResponseEntity getSignupSessionJWTToken(@RequestBody SignUpUserRequest request) {
Response response = new Response();
String hashString = Config.HashString(request.toDataString().trim());
if (hashString.equals(request.getHash())) {
...... do anything here .....
}else{
..... integrity exception ....
}
So My question is this the right approach? Am I doing something fundamentally wrong and how best can I achieve data integrity between my client and server.
Implementation of the hashString
(Android)
public static String HashString(String text) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.trim().getBytes("UTF-8"));
Log.i("CONFIG", "HASHING TEXT = " + ToBase64Encode(hash));
return ToBase64Encode(hash);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(Config.class.getName()).log(Level.SEVERE, null, ex);
return "";
} catch (UnsupportedEncodingException e) {
Logger.getLogger(Config.class.getName()).log(Level.SEVERE, null, e);
return "";
}
}
public static String ToBase64Encode(byte[] originalInput) {
return new String(Base64.encodeToString(originalInput, Base64.DEFAULT));
}
Implementation of the hashString
(SpringBoot)
public static String HashString(String text) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
// System.out.println("Compare this = " + ToBase64Encode(hash));
return Base64.getEncoder().encodeToString(hash);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(RiceHelper.class.getName()).log(Level.SEVERE, null, ex);
return "";
}
}