| @@ -0,0 +1,122 @@ | |||||
| // function clone_script_node(node){ | |||||
| // // console.log("\n\n\nnew script!") | |||||
| // var script = document.createElement("script"); | |||||
| // script.text = node.innerHTML; | |||||
| // // console.log("text: " + script.text) | |||||
| // var i = -1, attrs = node.attributes, attr; | |||||
| // while (++i < attrs.length) { | |||||
| // script.setAttribute((attr = attrs[i]).name, attr.value); | |||||
| // if (attr.name === "src") | |||||
| // console.log(attr.value) | |||||
| // } | |||||
| // return script; | |||||
| // } | |||||
| // function replace_all_script_nodes(node) { | |||||
| // if (node.tagName === 'SCRIPT') { | |||||
| // node.parentNode.replaceChild(clone_script_node(node), node); | |||||
| // } else { | |||||
| // var i = -1, children = node.childNodes; | |||||
| // while (++i < children.length) { | |||||
| // replace_all_script_nodes(children[i]); | |||||
| // } | |||||
| // } | |||||
| // return node; | |||||
| // } | |||||
| function insertHTML(html){ | |||||
| // if no append is requested, clear the target element | |||||
| // if(!append) dest.innerHTML = ''; | |||||
| // create a temporary container and insert provided HTML code | |||||
| let container = document.createElement('div'); | |||||
| container.innerHTML = html; | |||||
| // cache a reference to all the scripts in the container | |||||
| let scripts = container.querySelectorAll('script'); | |||||
| // get all child elements and clone them in the target element | |||||
| let nodes = container.childNodes; | |||||
| // for( let i=0; i< nodes.length; i++) dest.appendChild( nodes[i].cloneNode(true) ); | |||||
| // force the found scripts to execute... | |||||
| for( let i=0; i< scripts.length; i++){ | |||||
| let script = document.createElement('script'); | |||||
| script.type = scripts[i].type || 'text/javascript'; | |||||
| if( scripts[i].hasAttribute('src') ) script.src = scripts[i].src; | |||||
| script.innerHTML = scripts[i].innerHTML; | |||||
| document.head.appendChild(script); | |||||
| document.head.removeChild(script); | |||||
| } | |||||
| // done! | |||||
| return true; | |||||
| } | |||||
| function decrypt_page() { | |||||
| var key_str = "" | |||||
| var html_name = window.location.pathname; | |||||
| var allcookies = document.cookie; | |||||
| cookiearray = allcookies.split(';'); | |||||
| for(var i=0; i<cookiearray.length; i++) { | |||||
| name = cookiearray[i].split('=')[0].trim(); | |||||
| value = cookiearray[i].split('=')[1]; | |||||
| if (name == html_name) | |||||
| key_str = value; | |||||
| if (name == "__master__") { | |||||
| key_str = value; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (key_str.length == 0) | |||||
| key_str = document.querySelector('input[name=pwd]').value | |||||
| // check key length | |||||
| if (key_str.length != 16 && | |||||
| key_str.length != 24 && | |||||
| key_str.length != 32) | |||||
| { | |||||
| return; | |||||
| } | |||||
| var entered_key = aesjs.utils.utf8.toBytes(key_str); | |||||
| var enc_bytes = aesjs.utils.hex.toBytes(enc_hex_body) | |||||
| // check if the user input / loaded cookie is the master key | |||||
| var aesCtr = new aesjs.ModeOfOperation.ctr(entered_key, new aesjs.Counter(initial_counter)) | |||||
| var master_key_dec_real_key = aesCtr.decrypt(aesjs.utils.hex.toBytes(master_key_enc_real_key)) | |||||
| aesCtr = new aesjs.ModeOfOperation.ctr(master_key_dec_real_key, new aesjs.Counter(initial_counter)) | |||||
| var dec_bytes = aesCtr.decrypt(enc_bytes) | |||||
| // Convert our bytes back into text | |||||
| var dec_text = aesjs.utils.utf8.fromBytes(dec_bytes) | |||||
| if (!dec_text.endsWith(correct_key_marker)) { | |||||
| // check if it is a regular password | |||||
| aesCtr = new aesjs.ModeOfOperation.ctr(entered_key, new aesjs.Counter(initial_counter)) | |||||
| var org_key_dec_real_key = aesCtr.decrypt(aesjs.utils.hex.toBytes(org_key_enc_real_key)) | |||||
| aesCtr = new aesjs.ModeOfOperation.ctr(org_key_dec_real_key, new aesjs.Counter(initial_counter)) | |||||
| dec_bytes = aesCtr.decrypt(enc_bytes) | |||||
| dec_text = aesjs.utils.utf8.fromBytes(dec_bytes) | |||||
| if (!dec_text.endsWith(correct_key_marker)) { | |||||
| key_str = ""; | |||||
| return | |||||
| } else { | |||||
| // entered correct file key | |||||
| document.cookie = html_name + "=" + key_str; | |||||
| } | |||||
| } else { | |||||
| // entered correct master key | |||||
| document.cookie = "__master__=" + key_str; | |||||
| } | |||||
| // Convert our bytes back into text | |||||
| // var dec_text = aesjs.utils.utf8.fromBytes(dec_bytes) | |||||
| var dec_text = new TextDecoder().decode(dec_bytes) | |||||
| document.body.outerHTML = "<body" + dec_text + "</body>" | |||||
| // insertHTML(document.body.innerHTML) | |||||
| // replace_all_script_nodes(document.getElementsByTagName("body")[0]); | |||||
| } | |||||
| window.onload = decrypt_page | |||||
| @@ -0,0 +1,4 @@ | |||||
| <div style="line-height: initial; position: absolute; left: 50%; top: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);"> | |||||
| <p id="sd" onclick="decrypt_page()" style="margin: 0 auto;font-size:100px;text-align:center">🔒</p> | |||||
| <input type="password" id="pwd" name="pwd"> | |||||
| </div> | |||||
| @@ -0,0 +1,131 @@ | |||||
| #!/usr/bin/env python3 | |||||
| import argparse | |||||
| import pyaes | |||||
| import os | |||||
| import sys | |||||
| import random | |||||
| import string | |||||
| sample_usage = """example: | |||||
| python passwordify_html.py file.html --password "this is the password" | |||||
| python passwordify_html.py file.html --password "this is the password" --master-password "master-password" | |||||
| """ | |||||
| parser = argparse.ArgumentParser(description="Generate a chart showing character traits.", | |||||
| epilog=sample_usage, | |||||
| formatter_class=argparse.RawDescriptionHelpFormatter) | |||||
| parser.add_argument('input_file', type=str, metavar="input", | |||||
| help='the html file') | |||||
| parser.add_argument("--password", "-p", dest="password", | |||||
| required=False, type=str, metavar="page password", | |||||
| help="The names of the character traits") | |||||
| parser.add_argument("--master-password", "-m", dest="master_password", | |||||
| required=False, type=str, metavar="master password", | |||||
| help="The values for the character traits") | |||||
| parser.add_argument("--output", "-o", dest="output_file", | |||||
| required=False, type=str, metavar="output", | |||||
| help="The file which should be created") | |||||
| args = parser.parse_args() | |||||
| script_dir = os.path.dirname(__file__) | |||||
| # passwords length must be in [16, 24, 32] | |||||
| # at least one must be supplied, the other is chosen random | |||||
| if args.password: | |||||
| assert(len(args.password) in [16, 24, 32]) | |||||
| if not args.master_password: | |||||
| args.master_password = "".join(random.choice(string.ascii_letters) for i in range(32)) | |||||
| elif args.master_password: | |||||
| assert(len(args.master_password) in [16, 24, 32]) | |||||
| if not args.password: | |||||
| args.password = "".join(random.choice(string.ascii_letters) for i in range(32)) | |||||
| else: | |||||
| assert(not "At least one of password or master password must be supplied") | |||||
| # if no out_file was passed, append .pw.html to in_file | |||||
| in_file = args.input_file | |||||
| out_file = args.output_file | |||||
| if not out_file: | |||||
| out_file = f"{in_file}.pw.html" | |||||
| print(f"passwordifying {in_file} -> {out_file}") | |||||
| # read the whole html file | |||||
| with open(in_file, "r") as in_file_handle: | |||||
| text = in_file_handle.read() | |||||
| # if the html has no body tag, then just copy it over | |||||
| if "<body" not in text: | |||||
| sys.exit(0) | |||||
| initial_counter = random.choice(list(range(128))) | |||||
| # generate a real key | |||||
| real_key = "".join(random.choice(string.ascii_letters) for i in range(32)).encode("utf-8") | |||||
| aes = pyaes.AESModeOfOperationCTR(args.password.encode("utf-8"), | |||||
| counter=pyaes.Counter(initial_value=initial_counter)) | |||||
| org_key_enc_real_key = aes.encrypt(real_key).hex() | |||||
| aes = pyaes.AESModeOfOperationCTR(args.master_password.encode("utf-8"), | |||||
| counter=pyaes.Counter(initial_value=initial_counter)) | |||||
| master_key_enc_real_key = aes.encrypt(real_key).hex() | |||||
| #extract header, body, and footer | |||||
| text_list = text.split("<body") | |||||
| # assert that the <body> tag only appears once | |||||
| if len(text_list) != 2: | |||||
| print(f"len(text_list) is {len(text_list)}") | |||||
| assert(False) | |||||
| header = text_list[0] | |||||
| text_list = text_list[1].split("</body>") | |||||
| # assert that the </body> tag only appears once | |||||
| assert(len(text_list) == 2) | |||||
| body, footer = text_list | |||||
| # read in the decipher function text | |||||
| with open(os.path.join(script_dir, "decipher.js"), "r") as decipher_file: | |||||
| decipher_function_text = decipher_file.read() | |||||
| # read in the html input prompt | |||||
| with open(os.path.join(script_dir, "input_form.html"), "r") as html_prompt_file: | |||||
| html_prompt_text = html_prompt_file.read() | |||||
| # have a "correct_marker" so the decrypter can check if the password was correct | |||||
| # by identifiying if the decryped text ends with the correct_marker | |||||
| correct_key_marker = "<!--Correct Key-->" | |||||
| body = body + correct_key_marker | |||||
| aes = pyaes.AESModeOfOperationCTR(real_key, | |||||
| counter=pyaes.Counter(initial_value=initial_counter)) | |||||
| real_key_enc_body = aes.encrypt(body.encode("utf-8")).hex() | |||||
| header = header.replace("</head>", f""" | |||||
| <script type="text/javascript" src="https://cdn.rawgit.com/ricmoo/aes-js/e27b99df/index.js"></script> | |||||
| <script> | |||||
| var master_key_enc_real_key = "{master_key_enc_real_key}"; | |||||
| var org_key_enc_real_key = "{org_key_enc_real_key}"; | |||||
| var correct_key_marker = "{correct_key_marker}" | |||||
| var initial_counter = {initial_counter}; | |||||
| var enc_hex_body = "{real_key_enc_body}"; | |||||
| </script> | |||||
| <script> | |||||
| {decipher_function_text} | |||||
| </script> | |||||
| </head>""") | |||||
| text = " ".join([header, f""" | |||||
| <body> | |||||
| {html_prompt_text} | |||||
| </body>""", footer]) | |||||
| # write html to new location | |||||
| with open(out_file, "wb") as new_html: | |||||
| new_html.write(text.encode('utf-8')) | |||||
| print(f"successfully passwordified {in_file}") | |||||
| @@ -0,0 +1,9 @@ | |||||
| <!DOCTYPE html> | |||||
| <html> | |||||
| <head> | |||||
| <title>Example</title> | |||||
| </head> | |||||
| <body> | |||||
| <p>This is an example of a simple HTML page with one paragraph.</p> | |||||
| </body> | |||||
| </html> | |||||
| @@ -0,0 +1,87 @@ | |||||
| <!DOCTYPE html> | |||||
| <html> | |||||
| <head> | |||||
| <title>Example</title> | |||||
| <script type="text/javascript" src="https://cdn.rawgit.com/ricmoo/aes-js/e27b99df/index.js"></script> | |||||
| <script> | |||||
| var master_key_enc_real_key = "04a2d6b170354946e39f6d53e8d8d341400c9fce9eb8a766398be99ecfc3bfff"; | |||||
| var org_key_enc_real_key = "15d34714d9853ae918ec53a7fabae45cc9536c210f77ecb0822c275fe6c11b49"; | |||||
| var correct_key_marker = "<!--Correct Key-->" | |||||
| var initial_counter = 5; | |||||
| var enc_hex_body = "d3e739429a8408b664023e88700b076cf058d57f6e10cd910c0b7fa4e01ba594b2e2d1a8c226b24022fe3f9ea15942fae2acd6fb70438677cf3925d522780f842a1f05512b3080589ee7148b7905327398df6c1bf8611fe11dd3fc857c0ca10dc5d1e4"; | |||||
| </script> | |||||
| <script> | |||||
| function decrypt_page() { | |||||
| var key_str = document.querySelector('input[name=pwd]').value | |||||
| var html_name = window.location.pathname; | |||||
| var allcookies = document.cookie; | |||||
| cookiearray = allcookies.split(';'); | |||||
| for(var i=0; i<cookiearray.length; i++) { | |||||
| name = cookiearray[i].split('=')[0].trim(); | |||||
| value = cookiearray[i].split('=')[1]; | |||||
| if (name == html_name) | |||||
| key_str = value; | |||||
| if (name == "__master__") { | |||||
| key_str = value; | |||||
| break; | |||||
| } | |||||
| } | |||||
| // check key length | |||||
| if (key_str.length != 16 && | |||||
| key_str.length != 24 && | |||||
| key_str.length != 32) | |||||
| { | |||||
| return; | |||||
| } | |||||
| var entered_key = aesjs.utils.utf8.toBytes(key_str); | |||||
| var enc_bytes = aesjs.utils.hex.toBytes(enc_hex_body) | |||||
| // check if the user input / loaded cookie is the master key | |||||
| var aesCtr = new aesjs.ModeOfOperation.ctr(entered_key, new aesjs.Counter(initial_counter)) | |||||
| var master_key_dec_real_key = aesCtr.decrypt(aesjs.utils.hex.toBytes(master_key_enc_real_key)) | |||||
| aesCtr = new aesjs.ModeOfOperation.ctr(master_key_dec_real_key, new aesjs.Counter(initial_counter)) | |||||
| var dec_bytes = aesCtr.decrypt(enc_bytes) | |||||
| // Convert our bytes back into text | |||||
| var dec_text = aesjs.utils.utf8.fromBytes(dec_bytes) | |||||
| if (!dec_text.startsWith(correct_key_marker)) { | |||||
| // check if it is a regular password | |||||
| aesCtr = new aesjs.ModeOfOperation.ctr(entered_key, new aesjs.Counter(initial_counter)) | |||||
| var org_key_dec_real_key = aesCtr.decrypt(aesjs.utils.hex.toBytes(org_key_enc_real_key)) | |||||
| aesCtr = new aesjs.ModeOfOperation.ctr(org_key_dec_real_key, new aesjs.Counter(initial_counter)) | |||||
| dec_bytes = aesCtr.decrypt(enc_bytes) | |||||
| dec_text = aesjs.utils.utf8.fromBytes(dec_bytes) | |||||
| if (!dec_text.startsWith(correct_key_marker)) { | |||||
| key_str = ""; | |||||
| return | |||||
| } else { | |||||
| // entered correct file key | |||||
| document.cookie = html_name + "=" + key_str; | |||||
| } | |||||
| } else { | |||||
| // entered correct master key | |||||
| document.cookie = "__master__=" + key_str; | |||||
| } | |||||
| // Convert our bytes back into text | |||||
| // var dec_text = aesjs.utils.utf8.fromBytes(dec_bytes) | |||||
| var dec_text = new TextDecoder().decode(dec_bytes) | |||||
| document.body.innerHTML = dec_text | |||||
| } | |||||
| </script> | |||||
| </head> | |||||
| <body> | |||||
| <div style="position: absolute; left: 50%; top: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);"> | |||||
| <p id="sd" onclick="decrypt_page()" style="margin: 0 auto;font-size:100px;text-align:center">🔒</p> | |||||
| <input type="password" id="pwd" name="pwd"> | |||||
| </div> | |||||
| </body> | |||||
| </html> | |||||