Implemented HMAC authentication in RecorderServlet

This commit is contained in:
0xboobface 2018-07-07 12:50:21 +02:00
parent 8c7385229f
commit d62bba5599
4 changed files with 86 additions and 1 deletions

View File

@ -71,7 +71,7 @@ public class Config {
public void save() throws IOException {
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<Settings> adapter = moshi.adapter(Settings.class);
JsonAdapter<Settings> adapter = moshi.adapter(Settings.class).indent(" ");
String json = adapter.toJson(settings);
File configDir = OS.getConfigDir();
File configFile = new File(configDir, filename);

View File

@ -0,0 +1,55 @@
package ctbrec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Hmac {
private static final transient Logger LOG = LoggerFactory.getLogger(Hmac.class);
public static byte[] generateKey() {
LOG.debug("Generating key");
SecureRandom random = new SecureRandom();
byte[] key = new byte[32];
random.nextBytes(key);
return key;
}
public static String calculate(String msg, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException, IllegalStateException, UnsupportedEncodingException {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
mac.init(keySpec);
byte[] result = mac.doFinal(msg.getBytes("UTF-8"));
String hmac = bytesToHex(result);
return hmac;
}
public static boolean validate(String msg, byte[] key, String hmacToCheck) throws InvalidKeyException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException {
return Hmac.calculate(msg, key).equals(hmacToCheck);
}
/**
* Converts a byte array to a string
*
* @param hash
* @return string
*/
static String bytesToHex(byte[] hash) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1)
hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
}

View File

@ -16,4 +16,6 @@ public class Settings {
public String lastDownloadDir = "";
public List<Model> models = new ArrayList<Model>();
public boolean determineResolution = false;
public boolean requireAuthentication = false;
public byte[] key = null;
}

View File

@ -3,9 +3,12 @@ package ctbrec.recorder.server;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import java.io.BufferedReader;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Iterator;
import java.util.List;
@ -21,6 +24,8 @@ import org.slf4j.LoggerFactory;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import ctbrec.Config;
import ctbrec.Hmac;
import ctbrec.InstantJsonAdapter;
import ctbrec.Model;
import ctbrec.Recording;
@ -43,6 +48,14 @@ public class RecorderServlet extends HttpServlet {
try {
String json = body(req);
boolean isRequestAuthenticated = checkAuthentication(req, json);
if(!isRequestAuthenticated) {
resp.setStatus(SC_UNAUTHORIZED);
String response = "{\"status\": \"error\", \"msg\": \"HMAC does not match\"}";
resp.getWriter().write(response);
return;
}
LOG.debug("Request: {}", json);
Moshi moshi = new Moshi.Builder()
.add(Instant.class, new InstantJsonAdapter())
@ -116,6 +129,21 @@ public class RecorderServlet extends HttpServlet {
}
}
private boolean checkAuthentication(HttpServletRequest req, String body) throws IOException, InvalidKeyException, NoSuchAlgorithmException, IllegalStateException {
boolean authenticated = false;
if(Config.getInstance().getSettings().key != null) {
if(req.getHeader("CTBREC-HMAC") == null) {
authenticated = false;
}
byte[] key = Config.getInstance().getSettings().key;
authenticated = Hmac.validate(body, key, req.getHeader("CTBREC-HMAC"));
} else {
authenticated = true;
}
return authenticated;
}
private String body(HttpServletRequest req) throws IOException {
StringBuilder body = new StringBuilder();
BufferedReader br = req.getReader();