Browse Source

Initial commit

Miti Mazmudar 2 years ago
commit
bc3d9b72e4
9 changed files with 842 additions and 0 deletions
  1. 2 0
      README.md
  2. BIN
      alligator.png
  3. 420 0
      background_http_request.js
  4. 325 0
      content.js
  5. 13 0
      extension_startup.html
  6. 29 0
      formfinder.js
  7. 0 0
      jsbn-min.js
  8. 20 0
      jsrsasign-all-min.js
  9. 33 0
      manifest.json

+ 2 - 0
README.md

@@ -0,0 +1,2 @@
++Order of libraries in manifest.json is so that jsbn doesn't replace the global scoped ECPoint decodeFromHex function and so that its getSECCurveByName function still works. 
+

BIN
alligator.png


+ 420 - 0
background_http_request.js

@@ -0,0 +1,420 @@
+Error.stackTraceLimit = Infinity;
+
+let urlPublicKeysMap = new Map();
+// Adapted code from https://stackoverflow.com/questions/36598638/generating-ecdh-keys-in-the-browser-through-webcryptoapi-instead-of-the-browseri
+const hex2Arr = str => {
+    if (!str) {
+        return new Uint8Array()
+    }
+    const arr = []
+    for (let i = 0, len = str.length; i < len; i+=2) {
+        arr.push(parseInt(str.substr(i, 2), 16))
+    }
+    return new Uint8Array(arr)
+}
+
+const buf2Hex = buf => {
+    return Array.from(new Uint8Array(buf))
+        .map(x => ('00' + x.toString(16)).slice(-2))
+        .join('')
+}
+
+function doVerify(msg1, sigval, pubkey) {
+	var curve = "secp256r1";
+	let sigalg = "SHA256withECDSA";
+  var sig = new KJUR.crypto.Signature({"alg": sigalg, "prov": "cryptojs/jsrsa"});
+  sig.init({xy: pubkey, curve: curve});
+  sig.updateHex(msg1); // updateHex for non-printable chars (updateString returns invalid signature); updateString if only printable chars.
+  var result = sig.verify(sigval);
+	return result;
+}
+
+async function generateOwnKeypairAndDeriveKey(dh_ga_x, dh_ga_y)
+{
+	let alicePublicKey = hex2Arr('04' + dh_ga_x + dh_ga_y);
+	try {
+  		const bobKey = await window.crypto.subtle.generateKey(
+  		    { name: 'ECDH', namedCurve: 'P-256' },
+  		    false, // no need to make Bob's private key exportable
+  		    ['deriveKey', 'deriveBits']);
+
+  	  const bobPublicKeyExported = await window.crypto.subtle.exportKey('raw', bobKey.publicKey);
+  		const bobPublicKeyHex = buf2Hex(bobPublicKeyExported);
+
+  		console.log(`Client's publicKey: ${bobPublicKeyHex}`);
+
+  		const aliceKeyImported = await window.crypto.subtle.importKey(
+  				'raw',
+  				alicePublicKey,
+  				{ name: 'ECDH', namedCurve: 'P-256'},
+  				true,
+  				[]);
+
+  		const sharedSecret = await window.crypto.subtle.deriveBits(
+  				{ name: 'ECDH', namedCurve: 'P-256', public: aliceKeyImported },
+  				bobKey.privateKey,
+  				256);
+
+  		const sharedSecretHex = buf2Hex(sharedSecret);
+  		console.log(`sharedSecret: ${sharedSecretHex}`);
+
+  		const hashOfSharedSecret = await window.crypto.subtle.digest("SHA-256", sharedSecret);
+  		console.log("This is the hash" + buf2Hex(hashOfSharedSecret));
+
+      const ownPublicKeyArray=Array.from(hex2Arr(bobPublicKeyHex).slice(1));
+      const ownPublicKeyUnreadableString = ownPublicKeyArray.map(x => String.fromCharCode(x)).join('');
+      const ownPublicKeyBase64=btoa(ownPublicKeyUnreadableString);
+
+  		return {mitigatorClientPublicKey: ownPublicKeyBase64, mitigatorDerivedKey: hashOfSharedSecret.slice(0, 16)};
+
+  		// console.log(aes_key_handle);
+  		// The code below is just for testing that indeed the hash was stored as the aes key. It will fail if the encryptable parameter in importKey (3rd one) is set to false.
+  		//		const aes_key = await window.crypto.subtle.exportKey(raw, aes_key_handle);
+  		//		console.log("This is the exported AES key: " + buf2Hex(aes_key));
+	}
+	catch (err) {
+		console.log(err);
+    return err;
+	}
+}
+
+async function useDecryptorPublicKeyReturnOwnPublicKey(message) // sender
+{
+  // TODO: Lol how d'ya check the URL of the sender (sender["url"]) is the corresponding background JS page?
+  // Need to compare it to a URL that consists of the extension's ID..
+  // Background script only ever calls this when this is true, but still checking it anyway.
+  if(!("decryptorPublicKey" in message))
+    return {error: "could not find decryptorPublicKey"};
+
+  decryptorPublicKeyX=message["decryptorPublicKey"]["x"];
+  decryptorPublicKeyY=message["decryptorPublicKey"]["y"];
+  let returnValue = await generateOwnKeypairAndDeriveKey(decryptorPublicKeyX, decryptorPublicKeyY);
+  if(!("mitigatorClientPublicKey" in returnValue) || !("mitigatorDerivedKey" in returnValue))
+    return {error: "Oh no :( Could not generate the public key or the derived key"};
+  console.log("And this is the derived key.");
+  console.log(buf2Hex(returnValue.mitigatorDerivedKey));
+  return {"ownPublicKeyBase64": returnValue.mitigatorClientPublicKey, "derivedKey": returnValue.mitigatorDerivedKey};
+}
+
+/*
+function recursiveIncrementIV(iv, byteCounter, minByteCounter)
+{
+  if(iv[byteCounter] !== 0xff)
+  {
+    iv[byteCounter]++;
+    return {iv: iv};
+  }
+  else
+  {
+    if(byteCounter === minByteCounter)
+      return {error: "Reached maximum number of messages. Plz regenerate a new key."};
+    else
+      return recursiveIncrementIV(iv, byteCounter-1, minByteCounter);
+  }
+}
+
+function incrementIV(iv)
+{
+  return recursiveIncrementIV(iv, 11, 8);
+}
+*/
+async function regenerateOwnPublicKey(input)
+{
+	if(!input.decryptorPublicKeyObj && !input.url)
+	{
+		console.log("No decryptor public key or URL: dont know which website to regenerate own public key, derived key for");
+		return {error: "No decryptor public key or URL: dont know which website to regenerate own public key, derived key for"};
+	}
+	let decryptorPublicKeyObj;
+
+	if(input.url)
+	{
+		returnValue=getDecryptorPublicKeyForUrl(input.url);
+		if(returnValue.error)
+			return returnValue;
+		decryptorPublicKeyObj=returnValue;
+	}
+	else
+		decryptorPublicKeyObj=input.decryptorPublicKeyObj;
+
+	returnValue=await useDecryptorPublicKeyReturnOwnPublicKey(decryptorPublicKeyObj);
+	console.log(returnValue);
+	if(!returnValue.ownPublicKeyBase64 || !returnValue.derivedKey)
+	{
+		let string3="Could not derive own public key or the derivedkey";
+		console.log(string3 + returnValue);
+		return {error: string3 + returnValue};
+	}
+
+	decryptorPublicKeyObj.ownPublicKey=returnValue.ownPublicKeyBase64;
+	decryptorPublicKeyObj.derivedKey = returnValue.derivedKey;
+  let iv=new Uint8Array(12);
+  window.crypto.getRandomValues(iv);
+  decryptorPublicKeyObj.iv = iv;
+	urlPublicKeysMap.set(input.url, decryptorPublicKeyObj);
+	return {success: "Successfully set own public key"};
+}
+
+async function processMitigatorPublicKeyHeader(e)
+{
+	const headers=e.responseHeaders;
+	const mitigatorHeader = headers.find(function(element) {
+		return element.name === "Mitigator-Public-Key";
+	});
+
+	if(mitigatorHeader === undefined)
+	{
+		const string="Either Mitigator is not supported or this function is called on headers for other objects fetched along with the webpage.";
+		console.log(string);
+		return {log: string};
+	}
+
+		let url;
+		if(e.documentUrl === undefined) // user opened a new tab.
+			url=e.url;
+		else
+			url=e.documentUrl;
+		url=url.split('/').slice(0, 3).join('/').concat('/');
+
+	//urlPublicKeysMap.set(url, undefined);
+
+	console.log("Here's the header value:");
+	console.log(mitigatorHeader["value"]);
+
+	let returnValue = verifyHeaderRetrieveDecryptorPublicKey(mitigatorHeader["value"]);
+	if (!returnValue.decryptorPublicKey)
+	{
+		console.log("Could not find decryptor public key:");
+		return {error: "Could not find decryptor public key:"};
+	}
+	const decryptorPublicKeyObj=returnValue;
+	urlPublicKeysMap.set(url, decryptorPublicKeyObj);
+
+	returnValue = await regenerateOwnPublicKey({decryptorPublicKeyObj: decryptorPublicKeyObj});
+	console.log(returnValue);
+}
+
+async function encryptFieldsForUrl(url, fields_array)
+{
+	let returnValue = getDerivedKeyIvForUrl(url);
+	if(returnValue.error)
+	{
+		console.log(returnValue);
+		return returnValue;
+	}
+
+	//console.log("Encrypting");
+	const derivedKey=returnValue.derivedKey;
+	let iv=returnValue.iv;
+  let ciphertextArray = [];
+
+  const algo = {   name: "AES-GCM", iv: iv };
+
+  const aes_key_handle = await window.crypto.subtle.importKey("raw", derivedKey,
+      algo,
+      false, //    true, //whether the key is extractable (i.e. can be used in exportKey)
+      ["encrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey"
+    );
+  // TODO: Error catching here
+
+  for (field of fields_array) {
+    let fieldAscii = new Uint8Array(field.length);
+    for (let i=0;i<field.length; i++)
+  	{
+      fieldAscii[i] = field.charCodeAt(i);
+    }
+    console.log("About to encrypt this:");
+    console.log(field);
+    console.log("In ASCII:");
+    console.log(fieldAscii.toString());
+  	try {
+      const ciphertextAndTag = await crypto.subtle.encrypt(algo, aes_key_handle, fieldAscii);
+      const ciphertextAndTagUint8 = new Uint8Array(ciphertextAndTag);
+      let ciphertext = ciphertextAndTagUint8.slice(0,-16);
+      let tag = ciphertextAndTagUint8.slice(-16);
+      let ciphertextIVTag = Array.of(...ciphertext, ...iv, ...tag);
+      console.log(ciphertextIVTag);
+      let ciphertextIVTagBase64 = btoa(ciphertextIVTag.map(x => String.fromCharCode(x)).join(''));
+      console.log(ciphertextIVTagBase64);
+      ciphertextArray.push(ciphertextIVTagBase64);
+    }
+    catch(err)
+    {
+      console.log(err);
+      console.log("Something went wrong when encrypting the fields.");
+      return {error: "Something went wrong when encrypting the fields."};
+    }
+    // To change the IV for each field.
+    window.crypto.getRandomValues(iv);
+    returnValue.iv = iv;
+  }
+  return {ciphertextFields: ciphertextArray};
+}
+
+// TODO: PUT THE CODE BELOW INTO ANOTHER FUNCTION, CALL IT AND THEN CALL THE CONTENT SCRIPT TO SET
+// DERIVED KEY, OWN PUBLIC KEY, WHICH THEN CALLS BACK TO SET ITS OWN PUBLIC KEY OVER HERE.
+function verifyHeaderRetrieveDecryptorPublicKey(mitigatorHeaderValue) {
+
+	console.log("Verifying header");
+	let decryptorLongTermPublicKey = "04e2e1449dece8b8cf759b2f52541a9ff28eee70449cfb67807079b04f6d2a10e36dd1f3735ebfc95e1a7a4162c6eede07a8969bd1ff5850008614325002a882c3";
+	//"04
+	//950b235cda836f8660885a9aabe5816fc8142c4912bd44f65c278c1749081061
+	//abad883ca934f8cc11c6c74205d2c9e55285a5696f075d1440a091e3bd6f0d81";
+	// this function does **not** return an array of bytes. It returns a *string* of potentially non-printable characters- it converts the array of bytes into their ASCII representation.
+	const decodedData = atob(mitigatorHeaderValue);
+
+	// converting it into an array of strings of hex representation of bytes.
+	const decodedDataArray = [];
+	for (let i = 0; i < decodedData.length; i++) {
+		decodedDataArray[i] = decodedData.charCodeAt(i).toString(16).padStart(2, '0');
+	}
+
+	const signature_r = decodedDataArray.slice(96,128).join('');
+	const signature_s = decodedDataArray.slice(128).join('');
+	let signature = "30440220";
+	signature=signature + signature_r + "0220" + signature_s;
+	const signature_data = decodedDataArray.slice(0,96).join('');
+
+	const result = doVerify(signature_data, signature, decryptorLongTermPublicKey);
+	if(result)
+		console.log("Yay dude it works wtf");
+	else
+	{
+		console.log("Damn, dude, it doesn't.");
+		// return false;
+	}
+
+	const verifier_mrenclave = decodedDataArray.slice(64).join('');
+	// TODO: Add verifier mrenclave checking code.
+	// Extracting public key components in a hex string format.
+	const public_key_x=decodedDataArray.slice(0,32).join('');
+	const public_key_y=decodedDataArray.slice(32,64).join('');
+
+	const urlDecryptorPublicKeyObject = {decryptorPublicKey: {x: public_key_x, y: public_key_y}};
+	return urlDecryptorPublicKeyObject;
+}
+
+function setMitigatorClientPublicKeyHeader(e) {
+	let headers = e.requestHeaders;
+	let returnValue = getOwnPublicKeyForUrl(e.url);
+	if(returnValue.ownPublicKey)
+	{
+		let clientHeaderObj={name: "mitigator-client-public-key", value:returnValue["ownPublicKey"] };
+		headers.push(clientHeaderObj);
+    console.log("Setting client's public key");
+	}
+	else
+		console.log(returnValue);
+  return {requestHeaders: headers};
+}
+
+function getDecryptorPublicKeyForUrl(url)
+{
+	const searchUrl = url.split('/').slice(0, 3).join('/').concat('/');
+	const hasSearchUrl = urlPublicKeysMap.has(searchUrl);
+	let urlPublicKeyObj;
+	if(hasSearchUrl)
+	{
+		urlPublicKeyObj= urlPublicKeysMap.get(searchUrl);
+		return {decryptorPublicKey: urlPublicKeyObj["decryptorPublicKey"]};
+	}
+	else
+		return {error: "Could not find this URL"};
+}
+/*
+function setOwnPublicKeyForUrl(url, ownPublicKeyBase64)
+{
+	const searchUrl = url.split('/').slice(0, 3).join('/').concat('/');
+	const hasSearchUrl = urlPublicKeysMap.has(searchUrl);
+	if(hasSearchUrl)
+	{
+		let urlPublicKeyObj= urlPublicKeysMap.get(searchUrl);
+		urlPublicKeyObj["ownPublicKey"]=ownPublicKeyBase64;
+		urlPublicKeysMap.set(searchUrl, urlPublicKeyObj);
+		return {success: "Successfully set own public key"};
+	}
+	else
+		return { error: "Could not find this URL"};
+}
+*/
+function getOwnPublicKeyForUrl(url)
+{
+	const searchUrl = url.split('/').slice(0, 3).join('/').concat('/');
+	const hasSearchUrl = urlPublicKeysMap.has(searchUrl);
+	let returnValue;
+	if(hasSearchUrl)
+	{
+		returnValue=urlPublicKeysMap.get(searchUrl);
+		if(returnValue.ownPublicKey)
+			return {ownPublicKey:returnValue["ownPublicKey"]};
+		else {
+			return {error: "Own public key has not been set by content script yet."}
+		}
+	}
+	else
+		return {error: "Could not find this URL"};
+}
+
+function getDerivedKeyIvForUrl(url)
+{
+	const searchUrl = url.split('/').slice(0, 3).join('/').concat('/');
+	const hasSearchUrl = urlPublicKeysMap.has(searchUrl);
+	let returnValue;
+	if(hasSearchUrl)
+	{
+		returnValue=urlPublicKeysMap.get(searchUrl);
+		if(returnValue.derivedKey && returnValue.iv)
+			return {derivedKey:returnValue.derivedKey, iv:returnValue.iv};
+		else {
+			return {error: "Derived key, IV have not been set by content script yet."}
+		}
+	}
+	else
+		return {error: "Could not find this URL"};
+}
+// from the content script and reply back with the decryptor's public key or to set own public key.
+
+async function backgroundListener(message)
+{
+	//	if("getDecryptorPublicKey" in message)
+	//		return returnValue= getDecryptorPublicKeyForUrl(message["url"]);
+
+	//	if("setOwnPublicKey" in message)
+	//		return setOwnPublicKeyForUrl(message["url"], message["setOwnPublicKey"]);
+	let returnValue; let ownPublicKey;
+	if(!message.url)
+	{
+		returnValue={error: "No URL sent: cant check if Mitigator is supported on the content script site."};
+		console.log(returnValue.error);
+		return returnValue;
+	}
+	if(message.regenerateOwnPublicKey) // TODO: Set a home_url property in the url object and if the sent_url and home_url are different, then regenerate.
+	{
+		returnValue = await regenerateOwnPublicKey({url: message.url});
+		console.log(returnValue);
+		if(returnValue.error)
+			return returnValue;
+	}
+	if(message.fields)
+		returnValue=await encryptFieldsForUrl(message.url, message.fields);
+	if(message.getOwnPublicKey)
+	{
+		ownPublicKey=getOwnPublicKeyForUrl(message.url);
+		returnValue.ownPublicKey=ownPublicKey;
+	}
+	return returnValue;
+}
+
+browser.webRequest.onHeadersReceived.addListener(
+  processMitigatorPublicKeyHeader,
+  {urls: ["http://*/*"]},
+  ["responseHeaders"]
+);
+
+browser.webRequest.onBeforeSendHeaders.addListener(
+  setMitigatorClientPublicKeyHeader,
+  {urls: ["http://*/*"]},
+  ["blocking", "requestHeaders"]
+);
+
+browser.runtime.onMessage.addListener(backgroundListener);

+ 325 - 0
content.js

@@ -0,0 +1,325 @@
+// https://stackoverflow.com/questions/40645538/communicate-data-from-popup-to-content-script-injected-by-popup-with-executescri
+let derivedKeyGlobal;
+let ownPublicKeyGlobalTesting;
+
+console.log('from content script');
+
+async function sendFieldsForEncryption(fields_array, regenerateOwnPublicKeyBoolean, getOwnPublicKeyBoolean)
+{
+  let message={"url": document.URL, "fields" : fields_array};
+  if(regenerateOwnPublicKeyBoolean)
+    message.regenerateOwnPublicKey = true;
+  if(getOwnPublicKeyBoolean)
+    message.getOwnPublicKey = true;
+  try {
+      returnValue = await browser.runtime.sendMessage(message);
+    }
+    catch(err) {
+      console.log("Error in browser.runtime.sendMessage in sendFieldsForEncryption");
+      console.log(err);
+      returnValue={error: err};
+    };
+
+  if(returnValue.error)
+  {
+    console.log(returnValue.error);
+    return returnValue;
+  }
+  return returnValue;
+}
+
+// This function assumes that there is just 1 eventlistener, itself
+// In case of multiple event handlers, we need to make sure that the 1) other event handlers handle the user data in a privacy-preserving way and
+// 2) usability - this event handler is executed after all other ones that expect plaintext data (if there are handlers run chronologically after it, then they need to send the current - encrypted - content of the form data)
+async function handleButtonClick(event)
+{
+  event.preventDefault();
+  console.log("Helloworld");
+  let dataObject = {};
+  let name = document.getElementById("name").value;
+  let age = document.getElementById("age").value;
+  dataObject["name"] = name;
+  dataObject["age"] = age;
+
+  // Encrypt name and age
+  let fields = Object.keys(dataObject);
+  let returnValue = await sendFieldsForEncryption([...Object.values(dataObject)], true, true);
+  if(returnValue.error)
+    return;
+  let encryptedFields=returnValue.ciphertextFields;
+  let counter=0;
+  for(obj of fields)
+  {
+    document.getElementById(obj).value=encryptedFields[counter];
+    console.log(document.getElementById(obj).value);
+    counter++;
+  }
+  console.log("Done with buttonclick handling");
+
+  document.getElementById("form").submit();
+}
+
+function getRandomString(length)
+{
+  let randomString="";
+  do {
+    randomString += Math.random().toString(36).substring(2);
+  } while (randomString.length < length+1);
+  return randomString.substring(0,length);
+}
+
+async function handleNButtonClicks(event)
+{
+  event.preventDefault();
+  const url=document.URL + "action.php";
+  const time_measurements = [];
+  const number_of_trials=10;
+  console.log("Hello starting this many trials for case with native server or with SGX:" + number_of_trials);
+  for(let counter=0; counter<number_of_trials; counter++)
+  {
+    const randomName=getRandomString(30);
+    const randomAge=getRandomString(30);
+    const post_data = `name=${randomName}&age=${randomAge}`; // JSON.stringify({name: randomName, age: randomAge});
+    const old_time = Date.now();
+    const ball = await fetch(url, {
+        method: "POST", // *GET, POST, PUT, DELETE, etc.
+        headers: {
+            "Content-Type": "application/x-www-form-urlencoded",
+        },
+        body: post_data
+    });
+    const new_time = Date.now();
+    const response_text= await ball.text();
+    [returnedName, returnedAge] = response_text.slice(12,-12).trim().split(" ");
+    if(returnedName !== randomName || returnedAge !== randomAge)
+    {
+      console.log("Didnt get the right name and age.");
+      console.log(returnedName);
+      console.log(returnedAge);
+      console.log(randomName);
+      console.log(randomAge);
+      break;
+    }
+    const time_lag = new_time - old_time;
+    time_measurements.push(time_lag);
+    if(counter % (number_of_trials/10) === 0)
+    {
+      console.log(time_measurements);
+    }
+  }
+  console.log("Done");
+  compute_stats_on_array(time_measurements);
+}
+
+async function handleNSgxButtonClicks(event)
+{
+    sendOrLogSgxRequests(event, false, 100, 5);
+    //logSgxRequests(event, 1000, 1);
+}
+
+async function logSgxRequests(event, number_of_trials, maxNumberOfFormFields)
+{
+  const send_url=document.URL + "/action.php";
+  const myHeaders = new Headers();
+  myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
+  let expected_response_string = "";
+  let curl_string = "";
+  let numberOfFormFields=1;
+  let formFieldCounter=0;
+
+  for(numberOfFormFields=1; numberOfFormFields<=maxNumberOfFormFields; numberOfFormFields++)
+  {
+    for(let counter=0; counter<number_of_trials; counter++)
+    {
+        let expected_response="";
+        let arrayOfFormFields = [];
+        // Initializing the array of form fields, of numberOfFormFields length, with random values.
+        expected_response+="<html><body> ";
+        for(formFieldCounter=0; formFieldCounter<numberOfFormFields; formFieldCounter++)
+        {
+          const formField=getRandomString(15);
+          expected_response+=formField + " ";
+          arrayOfFormFields.push(formField);
+        }
+        expected_response+="</body></html>\n";
+        expected_response_string+=expected_response;
+        // Encrypting the array of form fields
+        //  encryptionStartTime=Date.now();
+        returnValue = await sendFieldsForEncryption(arrayOfFormFields, false, true);
+        if(returnValue.error)
+          break;
+        // encryptionEndTime=Date.now();
+        // encryptionTimeMeasurements[numberOfFormFields-1][counter]=(encryptionEndTime - encryptionStartTime);
+
+        // Initializing the ciphertext array of form fields
+        let ciphertextArrayOfFormFields=returnValue.ciphertextFields;
+        let post_data="";
+        for(formFieldCounter=0; formFieldCounter<numberOfFormFields; formFieldCounter++)
+        {
+          const encodedCiphertext=encodeURIComponent(ciphertextArrayOfFormFields[formFieldCounter]);
+          post_data+=`f${formFieldCounter+1}=${encodedCiphertext}&`;
+        }
+
+        post_data=post_data.slice(0,-1);
+        curl_string += post_data +"\n";
+      }
+      if(returnValue.error)
+      {
+          console.log("breaking");
+          break;
+      }
+    }
+    if(returnValue.error)
+      return; // woulda been logged at this point
+    console.log(expected_response_string);
+    console.log(curl_string);
+    expected_response_string="";
+    curl_string="";
+
+    //let localStorageObject=window.localStorage;
+    //localStorageObject.setItem('expected_response', expected_response_string);
+    //localStorageObject.setItem('curl_string', curl_string);
+}
+
+async function sendOrLogSgxRequests(event, sendRequestsBoolean, number_of_trials, maxNumberOfFormFields)
+{
+  console.log("Starting tests for this many trials for SGX extension case: " + number_of_trials);
+  console.log("sendRequestsBoolean is " + sendRequestsBoolean);
+
+  let expected_response_string = "";
+  let curl_string = "";
+  let networkTimeMeasurements="";
+  let encryptionTimeMeasurements="";
+  let noMitigatorTimeMeasurements="";
+  let noSgxTimeMeasurements="";
+  let returnValue, encryptionStartTime, encryptionEndTime, networkSendTime, networkReceiveTime;
+  let numberOfFormFields=1;
+  let formFieldCounter=0;
+
+  const send_url=document.URL + "/action.php";
+  const nomitigator_url="http://crysp-server1.cs.uwaterloo.ca:8045/action.php";
+  const nosgx_url="http://crysp-server1.cs.uwaterloo.ca:8046/action.php";
+  const myHeaders = new Headers();
+  myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
+
+  for(let counter=0; counter<number_of_trials; counter++)
+  {
+    // For each of the number_of_trials run of the experiment, do it with a different number of form fields being sent each time.
+    for(numberOfFormFields=1; numberOfFormFields<=maxNumberOfFormFields; numberOfFormFields++)
+    {
+      let expected_response="";
+      let arrayOfFormFields = [];
+
+      // Initializing the array of form fields, of numberOfFormFields length, with random values.
+      expected_response+="<html><body> ";
+      for(formFieldCounter=0; formFieldCounter<numberOfFormFields; formFieldCounter++)
+      {
+        const formField=getRandomString(32);
+        expected_response+=formField + " ";
+        arrayOfFormFields.push(formField);
+      }
+      expected_response+="</body></html>\n";
+
+      // Encrypting the array of form fields
+      encryptionStartTime=Date.now();
+      returnValue = await sendFieldsForEncryption(arrayOfFormFields, false, true);
+      encryptionEndTime=Date.now();
+      if(returnValue.error)
+        break;
+      encryptionTimeMeasurements+=encryptionStartTime + " " + encryptionEndTime + "\n";
+
+      // Initializing the ciphertext array of form fields
+      let ciphertextArrayOfFormFields=returnValue.ciphertextFields;
+      let post_data="";
+      for(formFieldCounter=0; formFieldCounter<numberOfFormFields; formFieldCounter++)
+      {
+        const encodedCiphertext=encodeURIComponent(ciphertextArrayOfFormFields[formFieldCounter]);
+        post_data+=`f${formFieldCounter+1}=${encodedCiphertext}&`;
+      }
+      post_data=post_data.slice(0,-1);
+
+      ownPublicKey=returnValue.ownPublicKey.ownPublicKey;
+
+      if(sendRequestsBoolean)
+      {
+        // Setting header and sending request
+        myHeaders.set("Mitigator-Client-Public-Key", ownPublicKey);
+        networkSendTime = Date.now();
+        const ball = await fetch(send_url, {
+          method: "POST", // *GET, POST, PUT, DELETE, etc.
+          headers: myHeaders,
+          body: post_data
+        });
+        networkReceiveTime = Date.now();
+        networkTimeMeasurements+=networkSendTime + " " + networkReceiveTime +"\n";
+        const response_text= await ball.text();
+
+        // Checking returned values.
+        let returnedTextsArray = response_text.slice(12,-14).trim().split(" ");
+        for(formFieldCounter=0; formFieldCounter<numberOfFormFields; formFieldCounter++)
+        {
+          if(returnedTextsArray[formFieldCounter] !== arrayOfFormFields[formFieldCounter])
+          {
+            returnValue = {error: "Didnt get the right name and age."};
+            console.log("Didnt get the right name and age.");
+            console.log(returnedTextsArray[formFieldCounter]);
+            console.log(arrayOfFormFields[formFieldCounter]);
+            break;
+          }
+        }
+
+        // Sending identical values to the Graphene-SGX server.
+        networkSendTime = Date.now();
+        let ball2 = await fetch(nomitigator_url, {
+          method: "POST", // *GET, POST, PUT, DELETE, etc.
+          headers: myHeaders,
+          body: post_data
+        });
+        networkReceiveTime = Date.now();
+        noMitigatorTimeMeasurements+=networkSendTime + " " + networkReceiveTime +"\n";
+
+        // Sending identical values to the control server.
+        networkSendTime = Date.now();
+        ball2 = await fetch(nosgx_url, {
+          method: "POST", // *GET, POST, PUT, DELETE, etc.
+          headers: myHeaders,
+          body: post_data
+        });
+        networkReceiveTime = Date.now();
+        noSgxTimeMeasurements+=networkSendTime + " " + networkReceiveTime +"\n";
+      }
+      else {
+        expected_response_string+=expected_response;
+        curl_string += post_data +"\n";
+      }
+    }
+    if(returnValue.error)
+      {
+        console.log("breaking");
+        break;}
+  }
+  if(returnValue.error)
+    return; // woulda been logged at this point
+
+  console.log("Done");
+  if(sendRequestsBoolean)
+  {
+    console.log("Network times");
+    console.log(JSON.stringify(networkTimeMeasurements));
+    console.log("Network times for no Mitigator case");
+    console.log(JSON.stringify(noMitigatorTimeMeasurements));
+    console.log("Network times for no SGX case");
+    console.log(JSON.stringify(noSgxTimeMeasurements));
+    console.log("Encryption times");
+    console.log(JSON.stringify(encryptionTimeMeasurements));
+  }
+  else
+  {
+    console.log(expected_response_string);
+    console.log(curl_string);
+  }
+}
+
+document.getElementById("form").addEventListener("submit", handleButtonClick, { once: true});
+document.getElementById("experimenter1Button").addEventListener("click", handleNButtonClicks);
+document.getElementById("experimenter2Button").addEventListener("click", handleNSgxButtonClicks);

+ 13 - 0
extension_startup.html

@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <meta charset="utf-8">
+    <!-- <link rel="stylesheet" href="choose_beast.css"/> -->
+
+  </head>
+
+<body>
+  <p> Form </p>
+  <script src="formfinder.js"></script>
+</body>
+
+</html>

+ 29 - 0
formfinder.js

@@ -0,0 +1,29 @@
+
+function getTextFieldNames()
+{
+    let textFieldsNames=[];
+    let textFields;
+    let formsCollection = document.getElementsByTagName("form");
+    for (let i = 0; i < formsCollection.length; i++) {
+        // TODO: Check for all input types other than ones which cannot be made to look like text.
+        // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
+        textFields=formsCollection[i].querySelectorAll("input[type='text']");
+        for (let j=0; j < textFields.length; j++)
+        {
+            textFieldsNames.push(textFields[j].name);
+        }
+    }
+    return textFieldsNames;
+}
+
+// Input is of format {name: "", value: ""}
+function setTextFieldsWithValues(textFieldNamesValues)
+{
+    let elementsByName;
+    for (let i = 0; i < textFieldNamesValues.length; i++) {
+        elementsByName = document.getElementsByName("textFieldNamesValues[i].name");
+        // TODO: Problematic - it sets the first element of that name to be that value - may be check if it's a text
+        // TODO: Make sure that only the right elements are set to the ciphertext values.
+        elementsByName[0] = textFieldNamesValues[i].value;
+    }
+}

File diff suppressed because it is too large
+ 0 - 0
jsbn-min.js


File diff suppressed because it is too large
+ 20 - 0
jsrsasign-all-min.js


+ 33 - 0
manifest.json

@@ -0,0 +1,33 @@
+{
+
+  "description": "Compliance with privacy policies",
+  "manifest_version": 2,
+  "name": "mitigator",
+  "version": "1.0",
+  "homepage_url": "https://crysp.uwaterloo.ca/",
+  "icons": {
+    "48": "icons/border-48.png"
+  },
+  "permissions": [
+    "webRequest", "webRequestBlocking",
+    "http://*/*"
+  ],
+
+  "background": {
+    "scripts": ["jsbn-min.js", "jsrsasign-all-min.js", "background_http_request.js"]
+  },
+
+  "content_scripts": [ {
+    "matches": [
+      "http://*/*"
+    ],
+    "js":["./content.js"],
+    "run_at":"document_idle"
+  }],
+
+  "browser_action": {
+  "default_icon": "alligator.png",
+  "default_title": "Mitigator",
+  "default_popup": "extension_startup.html"
+}
+}

Some files were not shown because too many files changed in this diff