Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

132 linhas
4.6 KiB

  1. #!/usr/bin/env python3
  2. import argparse
  3. import pyaes
  4. import os
  5. import sys
  6. import random
  7. import string
  8. sample_usage = """example:
  9. python passwordify_html.py file.html --password "this is the password"
  10. python passwordify_html.py file.html --password "this is the password" --master-password "master-password"
  11. """
  12. parser = argparse.ArgumentParser(description="Generate a chart showing character traits.",
  13. epilog=sample_usage,
  14. formatter_class=argparse.RawDescriptionHelpFormatter)
  15. parser.add_argument('input_file', type=str, metavar="input",
  16. help='the html file')
  17. parser.add_argument("--password", "-p", dest="password",
  18. required=False, type=str, metavar="page password",
  19. help="The names of the character traits")
  20. parser.add_argument("--master-password", "-m", dest="master_password",
  21. required=False, type=str, metavar="master password",
  22. help="The values for the character traits")
  23. parser.add_argument("--output", "-o", dest="output_file",
  24. required=False, type=str, metavar="output",
  25. help="The file which should be created")
  26. args = parser.parse_args()
  27. script_dir = os.path.dirname(__file__)
  28. # passwords length must be in [16, 24, 32]
  29. # at least one must be supplied, the other is chosen random
  30. if args.password:
  31. assert(len(args.password) in [16, 24, 32])
  32. if not args.master_password:
  33. args.master_password = "".join(random.choice(string.ascii_letters) for i in range(32))
  34. elif args.master_password:
  35. assert(len(args.master_password) in [16, 24, 32])
  36. if not args.password:
  37. args.password = "".join(random.choice(string.ascii_letters) for i in range(32))
  38. else:
  39. assert(not "At least one of password or master password must be supplied")
  40. # if no out_file was passed, append .pw.html to in_file
  41. in_file = args.input_file
  42. out_file = args.output_file
  43. if not out_file:
  44. out_file = f"{in_file}.pw.html"
  45. print(f"passwordifying {in_file} -> {out_file}")
  46. # read the whole html file
  47. with open(in_file, "r") as in_file_handle:
  48. text = in_file_handle.read()
  49. # if the html has no body tag, then just copy it over
  50. if "<body" not in text:
  51. sys.exit(0)
  52. initial_counter = random.choice(list(range(128)))
  53. # generate a real key
  54. real_key = "".join(random.choice(string.ascii_letters) for i in range(32)).encode("utf-8")
  55. aes = pyaes.AESModeOfOperationCTR(args.password.encode("utf-8"),
  56. counter=pyaes.Counter(initial_value=initial_counter))
  57. org_key_enc_real_key = aes.encrypt(real_key).hex()
  58. aes = pyaes.AESModeOfOperationCTR(args.master_password.encode("utf-8"),
  59. counter=pyaes.Counter(initial_value=initial_counter))
  60. master_key_enc_real_key = aes.encrypt(real_key).hex()
  61. #extract header, body, and footer
  62. text_list = text.split("<body")
  63. # assert that the <body> tag only appears once
  64. if len(text_list) != 2:
  65. print(f"len(text_list) is {len(text_list)}")
  66. assert(False)
  67. header = text_list[0]
  68. text_list = text_list[1].split("</body>")
  69. # assert that the </body> tag only appears once
  70. assert(len(text_list) == 2)
  71. body, footer = text_list
  72. # read in the decipher function text
  73. with open(os.path.join(script_dir, "decipher.js"), "r") as decipher_file:
  74. decipher_function_text = decipher_file.read()
  75. # read in the html input prompt
  76. with open(os.path.join(script_dir, "input_form.html"), "r") as html_prompt_file:
  77. html_prompt_text = html_prompt_file.read()
  78. # have a "correct_marker" so the decrypter can check if the password was correct
  79. # by identifiying if the decryped text ends with the correct_marker
  80. correct_key_marker = "<!--Correct Key-->"
  81. body = body + correct_key_marker
  82. aes = pyaes.AESModeOfOperationCTR(real_key,
  83. counter=pyaes.Counter(initial_value=initial_counter))
  84. real_key_enc_body = aes.encrypt(body.encode("utf-8")).hex()
  85. header = header.replace("</head>", f"""
  86. <script type="text/javascript" src="https://cdn.rawgit.com/ricmoo/aes-js/e27b99df/index.js"></script>
  87. <script>
  88. var master_key_enc_real_key = "{master_key_enc_real_key}";
  89. var org_key_enc_real_key = "{org_key_enc_real_key}";
  90. var correct_key_marker = "{correct_key_marker}"
  91. var initial_counter = {initial_counter};
  92. var enc_hex_body = "{real_key_enc_body}";
  93. </script>
  94. <script>
  95. {decipher_function_text}
  96. </script>
  97. </head>""")
  98. text = " ".join([header, f"""
  99. <body>
  100. {html_prompt_text}
  101. </body>""", footer])
  102. # write html to new location
  103. with open(out_file, "wb") as new_html:
  104. new_html.write(text.encode('utf-8'))
  105. print(f"successfully passwordified {in_file}")