├── .gitignore ├── demo ├── requirements.txt ├── static │ ├── fonts │ │ └── MaterialIcons-Round.woff2 │ ├── styles │ │ ├── main.css.map │ │ ├── main.css │ │ └── main.scss │ └── scripts │ │ ├── main.js │ │ └── cash.min.js ├── fsociety.py ├── passwords.py └── templates │ └── index.html ├── poster ├── poster.pdf ├── poster.png ├── demo_QR_code.pdf ├── comparison_graph.pdf ├── demo_screenshot.png ├── prompt_diagram.pdf ├── similarity_graph.pdf ├── outline.md ├── demo_QR_code.svg ├── poster_backup.tex ├── prompt_diagram.svg └── similarity_graph.svg ├── code ├── comparison_graph.png ├── similarity_chart.png ├── analysis │ ├── passwordsList100.csv │ ├── passwordsTargeted.csv │ └── checkPasswords.ipynb ├── practice │ ├── gpt2.ipynb │ └── openai_practice.ipynb ├── training.ipynb └── analysis.ipynb └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .venv/ 3 | __pycache__/ 4 | data 5 | output -------------------------------------------------------------------------------- /demo/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | openai 3 | python-dotenv 4 | -------------------------------------------------------------------------------- /poster/poster.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/poster/poster.pdf -------------------------------------------------------------------------------- /poster/poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/poster/poster.png -------------------------------------------------------------------------------- /poster/demo_QR_code.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/poster/demo_QR_code.pdf -------------------------------------------------------------------------------- /code/comparison_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/code/comparison_graph.png -------------------------------------------------------------------------------- /code/similarity_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/code/similarity_chart.png -------------------------------------------------------------------------------- /poster/comparison_graph.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/poster/comparison_graph.pdf -------------------------------------------------------------------------------- /poster/demo_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/poster/demo_screenshot.png -------------------------------------------------------------------------------- /poster/prompt_diagram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/poster/prompt_diagram.pdf -------------------------------------------------------------------------------- /poster/similarity_graph.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/poster/similarity_graph.pdf -------------------------------------------------------------------------------- /demo/static/fonts/MaterialIcons-Round.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACM-Research/targeted-password-guesses/HEAD/demo/static/fonts/MaterialIcons-Round.woff2 -------------------------------------------------------------------------------- /demo/fsociety.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, send_from_directory, request 2 | import json 3 | import passwords 4 | 5 | app = Flask(__name__) 6 | 7 | 8 | @app.route("/") 9 | def index(): 10 | return render_template("index.html", theme=request.cookies.get("theme") or "system") 11 | 12 | @app.route("/guess", methods=["POST"]) 13 | def guess(): 14 | return json.dumps(passwords.guess(request.form)) 15 | 16 | @app.route("/styles/") 17 | def send_css(path): 18 | return send_from_directory("static/styles", path) 19 | 20 | @app.route("/scripts/") 21 | def send_scripts(path): 22 | return send_from_directory("static/scripts", path) 23 | 24 | @app.route("/fonts/") 25 | def send_fonts(path): 26 | return send_from_directory("static/fonts", path) 27 | -------------------------------------------------------------------------------- /demo/static/styles/main.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["main.scss"],"names":[],"mappings":"AAmBA,mCACI,MAhBI,sBACA,2BACA,oBACA,kBACA,gCAkBR,oCACI,MAjBI,sBACA,2BACA,oBACA,kBACA,iCAmBR,MA7BQ,sBACA,2BACA,oBACA,kBACA,+BA8BR,OA5BQ,sBACA,2BACA,oBACA,kBACA,gCA+BR,WACI,6BACA,kBACA,gBACA,0DAGJ,gBACI,6BACA,mBACA,kBACA,eACA,cACA,sBACA,oBACA,qBACA,mBACA,iBACA,cACA,kCACA,kCAOJ,EACE,qBACA,sCAIF,qBACE,UAGF,2BACE,yBAGF,2BACE,yBACA,mBACA,+BAGF,KACI,uBAGJ,KACI,mCACA,wBACA,uBACA,kBACA,SAGJ,OACI,yBAEA,cACI,gBACA,mCACA,YACA,kBACA,wBACA,aACA,uBACA,mBACA,WACA,YACA,aAGJ,oBACI,mCACA,wBAGJ,WACI,mCACA,kBACA,eACA,aACA,mBACA,qBACA,eACA,kBACA,UACA,QAEA,+BACI,aAIR,gBACI,qCAEA,uBACI,aAKZ,KACI,aACA,gBAGJ,aACI,wCACA,mBACA,qCACA,gBACA,aACA,WAGJ,GACI,iBACA,gBACA,yBACA,UAEA,MACI,0CACA,qBACA,mBACA,aAIR,SACI,aAGJ,OACI,wCACA,aAGJ,sCACI,KACI,sBACA,YAGJ,aACI,YACA,YAMR,sCACI,OACI,sBACA,qBACA,kBAGJ,iBACI,KACI,YAGJ,GACI,UAKZ,SACI,uBACA,sBAGJ,mBACI,KACI,UAGJ,GACI,WAMR,KACI,aACA,sBAEA,WACI,gBAGJ,cACI,YAIR,YACI,aACA,sBACA,iBACA,aACA,iBAGJ,MACI,YAEA,eACI,YAIR,eACI,wCACA,mCACA,mBACA,wBACA,eACA,uBACA,gBACA,mBAIJ,SACI,aACA,8BACA,mBAGJ,OACI,gBACA,+BACA,WACA,eACA,YACA,kBACA,aACA,mBAGJ,aACI,qCAGJ,qCACI,KACH,WAGG,YACH,eACA,qBAGG,SACH","file":"main.css"} -------------------------------------------------------------------------------- /code/analysis/passwordsList100.csv: -------------------------------------------------------------------------------- 1 | passwords 2 | 123456 3 | password 4 | 12345678 5 | qwerty 6 | 123456789 7 | 12345 8 | 1234 9 | 111111 10 | 1234567 11 | dragon 12 | 123123 13 | baseball 14 | abc123 15 | football 16 | monkey 17 | letmein 18 | 696969 19 | shadow 20 | master 21 | 666666 22 | qwertyuiop 23 | 123321 24 | mustang 25 | 1234567890 26 | michael 27 | 654321 28 | pussy 29 | superman 30 | 1qaz2wsx 31 | 7777777 32 | fuckyou 33 | 121212 34 | 000000 35 | qazwsx 36 | 123qwe 37 | killer 38 | trustno1 39 | jordan 40 | jennifer 41 | zxcvbnm 42 | asdfgh 43 | hunter 44 | buster 45 | soccer 46 | harley 47 | batman 48 | andrew 49 | tigger 50 | sunshine 51 | iloveyou 52 | fuckme 53 | 2000 54 | charlie 55 | robert 56 | thomas 57 | hockey 58 | ranger 59 | daniel 60 | starwars 61 | klaster 62 | 112233 63 | george 64 | asshole 65 | computer 66 | michelle 67 | jessica 68 | pepper 69 | 1111 70 | zxcvbn 71 | 555555 72 | 11111111 73 | 131313 74 | freedom 75 | 777777 76 | pass 77 | fuck 78 | maggie 79 | 159753 80 | aaaaaa 81 | ginger 82 | princess 83 | joshua 84 | cheese 85 | amanda 86 | summer 87 | love 88 | ashley 89 | 6969 90 | nicole 91 | chelsea 92 | biteme 93 | matthew 94 | access 95 | yankees 96 | 987654321 97 | dallas 98 | austin 99 | thunder 100 | taylor 101 | matrix 102 | minecraft 103 | -------------------------------------------------------------------------------- /code/analysis/passwordsTargeted.csv: -------------------------------------------------------------------------------- 1 | passwordstual 2 | publicwriter123 3 | friendmaker 4 | ilovewriting 5 | onlinedater 6 | graduation 7 | pisces 8 | publisher 9 | atheist 10 | cats123 11 | friends123 12 | sunshine 13 | monkey 14 | 1234567890 15 | 123123 16 | princess 17 | baseball 18 | dragon 19 | football 20 | shadow 21 | michael 22 | soccer 23 | unknown 24 | maggie 25 | 000000 26 | ashley 27 | myspace1 28 | purple 29 | fuckyou 30 | charlie 31 | jordan 32 | hunter 33 | superman 34 | tigger 35 | michelle 36 | buster 37 | pepper 38 | justin 39 | andrew 40 | harley 41 | matthew 42 | bailey 43 | jennifer 44 | samantha 45 | ginger 46 | anthony 47 | qwerty123 48 | qwerty1 49 | peanut 50 | summer 51 | hannah 52 | 654321 53 | michael1 54 | cookie 55 | linkedin 56 | madison 57 | joshua 58 | taylor 59 | whatever 60 | mustang 61 | jessica 62 | qwertyuiop 63 | amanda 64 | jasmine 65 | 123456a 66 | 123abc 67 | brandon 68 | letmein 69 | freedom 70 | basketball 71 | xxx 72 | babygirl 73 | thomas 74 | william 75 | hello 76 | austin 77 | qwe123 78 | 123 79 | jackson 80 | fuckyou1 81 | love 82 | family 83 | yellow 84 | trustno1 85 | robert 86 | jesus1 87 | chicken 88 | jordan23 89 | mickey 90 | diamond 91 | scooter 92 | booboo 93 | welcome 94 | george 95 | smokey 96 | cheese 97 | computer 98 | morgan 99 | nicholas 100 | 1234 101 | iloveyou 102 | -------------------------------------------------------------------------------- /demo/passwords.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openai 3 | from dotenv import load_dotenv 4 | 5 | load_dotenv() 6 | openai.api_key = os.getenv("OPENAI_API_KEY") 7 | 8 | models = { 9 | "100": { 10 | "model": "ada:ft-acm-research-password-team:initial-model-test-2022-04-15-22-39-03", 11 | "stop": "\n\n###\n\n" 12 | }, 13 | "1k": { 14 | "model": "ada:ft-acm-research-password-team:1k-examples-2022-04-16-17-55-28", 15 | "stop": "\n" 16 | }, 17 | "10k": { 18 | "model": "ada:ft-acm-research-password-team:10k-examples-2022-04-16-18-15-21", 19 | "stop": "\n" 20 | } 21 | } 22 | 23 | prompt_stop = '\nPassword: \n###\n' 24 | 25 | def guess(form): 26 | prompt = "" 27 | for key, value in form.items(): 28 | if value != '': 29 | if key == 'realname': 30 | prompt += f"Real name is {value}\n" 31 | if key == 'dob': 32 | prompt += f"Date of Birth is {value}\n" 33 | if key == 'gender': 34 | if value == 'M': 35 | prompt += f"Gender is Male\n" 36 | if value == 'F': 37 | prompt += f"Gender is Female\n" 38 | if key == 'country': 39 | prompt += f"Country is {value}\n" 40 | if key == 'twitterid': 41 | prompt += f"Twitter ID is {value}\n" 42 | if key == 'about': 43 | prompt += f"User information: {value}\n" 44 | if key == 'status': 45 | prompt += f"User status: {value}\n" 46 | 47 | prompt += prompt_stop 48 | 49 | print(prompt) 50 | completion = get_GPT3_completion(prompt) 51 | print(completion) 52 | return completion 53 | 54 | 55 | def get_GPT3_completion(prompt): 56 | response = openai.Completion.create( 57 | model=models['10k']['model'], 58 | prompt=prompt, 59 | max_tokens=32, 60 | temperature=0.8, 61 | stop=models['10k']['stop'] 62 | ) 63 | return response['choices'][0]['text'] 64 | -------------------------------------------------------------------------------- /demo/static/scripts/main.js: -------------------------------------------------------------------------------- 1 | $("#reset").on("click", e => { 2 | // By default, resetting would bring back the example values 3 | // We want to make the fields empty instead 4 | e.preventDefault(); 5 | $("#name").val(""); 6 | $("#info").val(""); 7 | }); 8 | 9 | $("#guess").on("click", e => { 10 | e.preventDefault(); 11 | 12 | // Get password guesses 13 | let data = new FormData(); 14 | data.append("realname", $("#realname").val()); 15 | data.append("username", $("#username").val()); 16 | data.append("dob", $("#dob").val()); 17 | data.append("gender", $("#gender").val()); 18 | data.append("country", $("#country").val()); 19 | data.append("twitterid", $("#twitterid").val()); 20 | data.append("about", $("#about").val()); 21 | data.append("status", $("#status").val()); 22 | 23 | const $results_ul = $("#results ul").empty(); 24 | for (let i = 0; i < 5; i++) { 25 | fetch("/guess", { 26 | method: "POST", 27 | body: data, 28 | }) 29 | .then(response => response.json()) 30 | .then(guess => { 31 | console.log(guess); 32 | $results_ul.append(`
  • ${guess}
  • `); 33 | }) 34 | .catch(console.error); 35 | } 36 | 37 | // Run animations if the results element isn't visible yet 38 | const $results = $("#results"); 39 | if ($results.css("display") === "none") { 40 | $("form").addClass("slide"); 41 | $results.show(); 42 | setTimeout(function () { return $("form").removeClass("slide"); }, 1000); 43 | } 44 | if (window.innerWidth <= 1200) 45 | document.querySelector("#results").scrollIntoView(); 46 | }); 47 | 48 | // Themes 49 | function reorder_theme_icons() { 50 | $("header div").append($("#system")) 51 | .append($("#dark")) 52 | .append($("#light")) 53 | .append($("header button.active")); 54 | } 55 | 56 | reorder_theme_icons(); 57 | 58 | $("header div button").on("click", function() { 59 | if ($(this).parent().hasClass("open")) { 60 | $("header div button").removeClass("active"); 61 | $(this).addClass("active"); 62 | if (this.id === "system") { 63 | // Delete the cookie 64 | document.cookie = "theme=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; 65 | $("body").attr("class", ""); 66 | } else { 67 | document.cookie = "theme=" + this.id + "; SameSite=Lax;"; 68 | $("body").attr("class", this.id); 69 | } 70 | $(this).parent().append($(this)); 71 | } else { 72 | reorder_theme_icons(); 73 | } 74 | $(this).parent().toggleClass("open"); 75 | }); 76 | 77 | -------------------------------------------------------------------------------- /poster/outline.md: -------------------------------------------------------------------------------- 1 | # poster outline 2 | 3 | ## introduction 4 | 5 | Imagine trying to hack into your friend's social media account by guessing what password they used to secure it. You do some research to come up with likely guesses – say, you discover they have a dog named "Dixie" and attempt to log in using the password {\tt DixieIsTheBest1}. The problem is that this only works if you have the intuition on how humans choose passwords, and the skills to conduct open-source intelligence gathering. 6 | 7 | We refined GPT-3 models on user data from Wattpad's 2020 security breach to generate targeted password guesses \emph{automatically}. This approach combines the vast knowledge of a 350 million parameter–model with the personal information of 1 thousand users, including usernames, phone numbers, and personal descriptions. 8 | 9 | ## methods 10 | 11 | We went through every data leak listed on haveibeenpwned.com and selected a variety of datasets to further examine. In June 2020, Wattpad (an online platform for reading and writing stories) was hacked, and the personal information and passwords of 270 million users were revealed. This data breach is particularly well-suited to our research because it connects unstructured text data (user descriptions and statuses) to corresponding passwords. This kind of data is particularly well-suited for refining a large text transformer like GPT-3, and it's what sets our research apart from a previous study which created a framework for generating targeted guesses using \emph{structured} pieces of user information. The original dataset's passwords were hashed with the bcrypt algorithm, so we used data from the crowdsourced password recovery website Hashmob to match plain text passwords with corresponding user data. 12 | 13 | We refined a version of the GPT-3 text transformer called Ada in three trials by giving it 100, 1000, and 10000 examples. We then tested each 14 | 15 | - why we picked Wattpad leak 16 | - list of leaks on haveibeenpwned 17 | - Hashmob cracked passwords 18 | - SQLite to align the data 19 | - refining Ada on 100, 1000, and 10000 tokens 20 | - refining Curie 21 | - testing with models and most popular passwords 22 | - similarity testing 23 | 24 | ## results 25 | 26 | - similarity curves 27 | - correct guess percentage curves 28 | 29 | ## applications 30 | 31 | - analyze security of employee's passwords 32 | - crack more passwords from a data leak 33 | - analyze security of individual passwords, say when registering for an account 34 | 35 | ## moving forward 36 | 37 | - [depending on what the data looks like] we could scale up the model to train on Curie or Davinci 38 | - or to save on costs for more power, refactor the project to use the open-source alternative GPT-J 39 | - more analysis 40 | 41 | ## references 42 | 43 | - https://blog.eleuther.ai/gpt3-model-sizes/ 44 | - https://hashmob.net/hashlists/info/4364-Wattpad.com%20bcrypt 45 | -------------------------------------------------------------------------------- /demo/static/styles/main.css: -------------------------------------------------------------------------------- 1 | @media(prefers-color-scheme: dark){:root{--background: #212128;--background-dark: #18181c;--foreground: white;--accent: #c8e0f4;--shadow: rgba(15, 15, 15, .5)}}@media(prefers-color-scheme: light){:root{--background: #F8FFFA;--background-dark: #EFF6FF;--foreground: black;--accent: #a9d2f3;--shadow: rgba(15, 15, 15, .25)}}.dark{--background: #212128;--background-dark: #18181c;--foreground: white;--accent: #c8e0f4;--shadow: rgba(15, 15, 15, .5)}.light{--background: #F8FFFA;--background-dark: #EFF6FF;--foreground: black;--accent: #a9d2f3;--shadow: rgba(15, 15, 15, .25)}@font-face{font-family:"Material Icons";font-style:normal;font-weight:400;src:url(/fonts/MaterialIcons-Round.woff2) format("woff2")}.material-icons{font-family:"Material Icons";font-weight:normal;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-moz-font-feature-settings:"liga";-moz-osx-font-smoothing:grayscale}*{scrollbar-width:thin;scrollbar-color:rgba(0,0,0,0) #323232}*::-webkit-scrollbar{width:8px}*::-webkit-scrollbar-track{background:rgba(0,0,0,0)}*::-webkit-scrollbar-thumb{background-color:#323232;border-radius:20px;border:6px solid rgba(0,0,0,0)}html{scroll-behavior:smooth}body{background-color:var(--background);color:var(--foreground);font-family:sans-serif;text-align:center;margin:0}header{padding:0 2rem 1rem 2rem}header button{appearance:none;background-color:var(--background);border:none;border-radius:50%;color:var(--foreground);display:flex;justify-content:center;place-items:center;width:40px;height:40px;margin:0 5px}header button:hover{background-color:var(--foreground);color:var(--background)}header div{background-color:var(--background);border-radius:5px;cursor:default;display:flex;align-items:center;align-content:center;padding:.25rem;position:absolute;right:1em;top:1em}header div button:not(.active){display:none}header div.open{box-shadow:0 0 4px 2px var(--shadow)}header div.open button{display:flex}main{display:flex;min-height:90vh}form,section{background-color:var(--background-dark);border-radius:10px;box-shadow:0 0 4px 2px var(--shadow);margin:1vh auto;padding:1rem;width:40vw}ul{font-size:1.1rem;overflow-y:auto;height:calc(100% - 5rem);padding:0}ul li{border-bottom:1px solid var(--background);list-style-type:none;padding:.5em .25em;margin:0 2em}#results{display:none}footer{background-color:var(--background-dark);padding:1rem}@media screen and (max-width: 1200px){main{flex-direction:column;height:auto}form,section{height:auto;width:75vw}}@media screen and (min-width: 1201px){.slide{animation-duration:1s;animation-name:slide;position:relative}@keyframes slide{from{right:-25vw}to{right:0}}}#results{animation-name:fade-in;animation-duration:1s}@keyframes fade-in{from{opacity:0}to{opacity:1}}form{display:flex;flex-direction:column}form label{text-align:left}form textarea{resize:none}.form-input{display:flex;flex-direction:column;font-size:1.25em;margin:0 1em;padding:.5em 1em}.grow{flex-grow:1}.grow textarea{flex-grow:1}input,textarea{background-color:var(--background-dark);border:2px solid var(--foreground);border-radius:10px;color:var(--foreground);font-size:1rem;font-family:sans-serif;margin-top:.5em;padding:.5em .75em}.buttons{display:flex;justify-content:space-between;padding:1em 1.75em}button{appearance:none;background-color:var(--accent);color:#000;cursor:pointer;border:none;border-radius:5px;margin:0 1em;padding:.5em 1.5em}button:hover{box-shadow:0 0 4px 2px var(--shadow)}@media screen and (max-width: 450px){form{width:80vw}.form-input{margin:0 .5rem;padding:.5rem .25rem}.buttons{padding:1em .75em}}/*# sourceMappingURL=main.css.map */ 2 | -------------------------------------------------------------------------------- /demo/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | fsociety 14 | 15 | 16 | 17 |
    18 |

    fsociety

    19 |

    Targeted password guesses with machine learning - Demo

    20 |
    21 | 24 | 27 | 30 |
    31 |
    32 |
    33 |
    34 |
    35 | 36 | 37 |
    38 |
    39 | 40 | 41 |
    42 |
    43 | 44 | 45 |
    46 |
    47 | 48 | 49 |
    50 |
    51 | 52 | 53 |
    54 |
    55 | 56 | 57 |
    58 |
    59 | 60 | 61 |
    62 |
    63 | 64 | 66 |
    67 |
    68 | 69 | 70 |
    71 |
    72 |
    73 |

    Guessed Passwords

    74 |
      75 |
      76 |
      77 |
      78 | © 2022 | fsociety 79 |
      80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /code/practice/gpt2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 3, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import torch\n", 10 | "from transformers import GPT2LMHeadModel, GPT2Tokenizer" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 4, 16 | "metadata": {}, 17 | "outputs": [ 18 | { 19 | "name": "stderr", 20 | "output_type": "stream", 21 | "text": [ 22 | "Downloading: 100%|██████████| 0.99M/0.99M [00:00<00:00, 2.49MB/s]\n", 23 | "Downloading: 100%|██████████| 446k/446k [00:00<00:00, 2.28MB/s]\n", 24 | "Downloading: 100%|██████████| 665/665 [00:00<00:00, 166kB/s]\n", 25 | "Downloading: 100%|██████████| 523M/523M [00:41<00:00, 13.2MB/s] \n" 26 | ] 27 | } 28 | ], 29 | "source": [ 30 | "tokenizer = GPT2Tokenizer.from_pretrained('gpt2')\n", 31 | "model = GPT2LMHeadModel.from_pretrained('gpt2')" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 31, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "sequence = (\"\"\"\n", 41 | "User data:\n", 42 | "age: 38\n", 43 | "education: graduated from masters program\n", 44 | "job: None\n", 45 | "orientation: straight\n", 46 | "pets: has cats\n", 47 | "religion: None\n", 48 | "sign: pisces\n", 49 | "keywords: ['pleasantly uncomfortable', 'writing public', 'online dating', 'dating site', 'public text', 'friends', 'people', 'find', 'site makes', 'friend']\n", 50 | "Passwords: public_writer123, Friend_Maker, ilovewriting, onlinedater, \n", 51 | "\"\"\")" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 32, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "\n", 61 | "inputs = tokenizer.encode(sequence, return_tensors='pt')" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 33, 67 | "metadata": {}, 68 | "outputs": [ 69 | { 70 | "name": "stderr", 71 | "output_type": "stream", 72 | "text": [ 73 | "Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.\n" 74 | ] 75 | } 76 | ], 77 | "source": [ 78 | "\n", 79 | "outputs = model.generate(\n", 80 | " inputs, max_length=200, do_sample=True, temperature=2.5\n", 81 | ")" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": 35, 87 | "metadata": {}, 88 | "outputs": [ 89 | { 90 | "name": "stdout", 91 | "output_type": "stream", 92 | "text": [ 93 | "\n", 94 | "User data:\n", 95 | "age: 38\n", 96 | "education: graduated from masters program\n", 97 | "job: None\n", 98 | "orientation: straight\n", 99 | "pets: has cats\n", 100 | "religion: None\n", 101 | "sign: pisces\n", 102 | "keywords: ['pleasantly uncomfortable', 'writing public', 'online dating', 'dating site', 'public text', 'friends', 'people', 'find','site makes', 'friend']\n", 103 | "Passwords: public_writer123, Friend_Maker, ilovewriting, onlinedater, \n", 104 | "Note in screenshots from online sites (the author and photographer work at least two different accounts while uploading to each instance): 'publisher has 'online writing', and 'online living' while uploadtto: 'onlinewriting blog', to get into full time online publication with some type of writing service or project or social media product at a higher subscription and higher fees.'\n", 105 | "What about a 'tapping off time online writing with the other party'.\n", 106 | "Letting go!\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "text = tokenizer.decode(outputs[0], skip_special_tokens=True)\n", 112 | "print(text)" 113 | ] 114 | } 115 | ], 116 | "metadata": { 117 | "interpreter": { 118 | "hash": "2be5faf79681da6f2a61fdfdd5405d65d042280f7fba6178067603e3a2925119" 119 | }, 120 | "kernelspec": { 121 | "display_name": "Python 3.10.2 64-bit", 122 | "language": "python", 123 | "name": "python3" 124 | }, 125 | "language_info": { 126 | "codemirror_mode": { 127 | "name": "ipython", 128 | "version": 3 129 | }, 130 | "file_extension": ".py", 131 | "mimetype": "text/x-python", 132 | "name": "python", 133 | "nbconvert_exporter": "python", 134 | "pygments_lexer": "ipython3", 135 | "version": "3.10.2" 136 | }, 137 | "orig_nbformat": 4 138 | }, 139 | "nbformat": 4, 140 | "nbformat_minor": 2 141 | } 142 | -------------------------------------------------------------------------------- /poster/demo_QR_code.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/practice/openai_practice.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Make sure to have a `.env` file with the contents `OPENAI_API_KEY=`\n", 8 | "\n", 9 | "[OKCupid Dating Site Dataset](https://www.kaggle.com/subhamyadav580/dating-site) (Put this in `/code/input`)" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 84, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import numpy as np # linear algebra\n", 19 | "import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n", 20 | "from dotenv import load_dotenv\n", 21 | "import os\n", 22 | "import openai\n", 23 | "import json\n", 24 | "\n", 25 | "load_dotenv()\n", 26 | "openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n", 27 | "\n", 28 | "def get_response(data):\n", 29 | " # data = json.loads(data)\n", 30 | " prompt_input = \"User data:\\n\"\n", 31 | " for key,value in data.items():\n", 32 | " prompt_input += f\"{key}: {value}\\n\"\n", 33 | " \n", 34 | " prompt_input += \"Generate a list of unique passwords from the data. Each password must have a length greater than 6 characters.\\n\"\n", 35 | " response = openai.Completion.create(\n", 36 | " engine=\"text-ada-001\",\n", 37 | " prompt=prompt_input,\n", 38 | " temperature=0.7,\n", 39 | " max_tokens=64,\n", 40 | " top_p=1,\n", 41 | " frequency_penalty=0,\n", 42 | " presence_penalty=0\n", 43 | " )\n", 44 | " # print(response)\n", 45 | " # print(prompt_input)\n", 46 | " print(prompt_input)\n", 47 | " return response['choices'][0]['text']\n" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 94, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "name": "stdout", 57 | "output_type": "stream", 58 | "text": [ 59 | "User data:\n", 60 | "age: 22\n", 61 | "education: working on college/university\n", 62 | "ethnicity: asian, white\n", 63 | "job: transportation\n", 64 | "location: south san francisco, california\n", 65 | "orientation: straight\n", 66 | "pets: likes dogs and likes cats\n", 67 | "religion: agnosticism and very serious about it\n", 68 | "sign: gemini\n", 69 | "keywords: ['smart guy', 'dumb guy', 'dumbest smart', 'smartest dumb', 'guy', 'love', 'shoes', 'make', 'intellectual', 'good', 'kind', 'dumbest', 'smart', 'smartest', 'dumb', 'game', 'video game', 'love life', 'mine', 'metaphors']\n", 70 | "Generate a list of unique passwords from the data. Each password must have a length greater than 6 characters.\n", 71 | "\n", 72 | "\n", 73 | "1.password1\n", 74 | "2.password2\n", 75 | "3.password3\n", 76 | "4.password4\n", 77 | "5.password5\n", 78 | "6.password6\n" 79 | ] 80 | } 81 | ], 82 | "source": [ 83 | "# Load dataset\n", 84 | "df = pd.read_csv('./input/okcupid_profiles.csv')\n", 85 | "df = df.drop([\"body_type\",\"diet\",\"drinks\",\"drugs\",\"height\",\"income\",\"last_online\",\"offspring\",\"sex\",\"smokes\",\"speaks\",\"status\"], axis=1)\n", 86 | "profile = df.iloc[0].to_json()\n", 87 | "profile_data = json.loads(profile)\n", 88 | "\n", 89 | "\n", 90 | "import yake\n", 91 | "\n", 92 | "data = dict()\n", 93 | "\n", 94 | "combined_essays = \"\"\n", 95 | "for key,value in profile_data.items():\n", 96 | " if key.startswith(\"essay\"):\n", 97 | " if value is not None:\n", 98 | " combined_essays += f\"{value}\\n\" \n", 99 | " else:\n", 100 | " data[key] = value\n", 101 | "\n", 102 | "combined_essays = combined_essays.replace(\"
      \", \"\")\n", 103 | "# print(combined_essays)\n", 104 | "kw_extractor = yake.KeywordExtractor(n=2)\n", 105 | "keywords = [ kw for (kw, score) in kw_extractor.extract_keywords(combined_essays)]\n", 106 | "\n", 107 | "data['keywords'] = keywords\n", 108 | "print(get_response(data))" 109 | ] 110 | } 111 | ], 112 | "metadata": { 113 | "interpreter": { 114 | "hash": "2be5faf79681da6f2a61fdfdd5405d65d042280f7fba6178067603e3a2925119" 115 | }, 116 | "kernelspec": { 117 | "display_name": "Python 3.10.2 64-bit", 118 | "language": "python", 119 | "name": "python3" 120 | }, 121 | "language_info": { 122 | "codemirror_mode": { 123 | "name": "ipython", 124 | "version": 3 125 | }, 126 | "file_extension": ".py", 127 | "mimetype": "text/x-python", 128 | "name": "python", 129 | "nbconvert_exporter": "python", 130 | "pygments_lexer": "ipython3", 131 | "version": "3.10.2" 132 | }, 133 | "orig_nbformat": 4 134 | }, 135 | "nbformat": 4, 136 | "nbformat_minor": 2 137 | } 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Automating Targeted Password Guessing 2 | 3 | *Faculty Advisor: [Dr. Wei Yang](http://youngwei.com)* • *Team Lead: [Roman Hauksson-Neill](https://github.com/romanhn)*\ 4 | *[Aravindan Kasiraman](https://cubetastic33.github.io) • [Bradley Johnson](https://www.linkedin.com/in/bradwj) • [Pranav Nair](https://github.com/pranavn21) • [Sisira Aarukapalli](https://github.com/ccgsisig)*\ 5 | *[ACM Research](https://acmutd.co/research) at the University of Texas at Dallas* 6 | 7 | ![](./poster/poster.png) 8 | 9 | ## Introduction 10 | 11 | Imagine trying to hack into your friend's social media account by guessing what password they used to secure it. You do some research to come up with likely guesses – say, you discover they have a dog named "Dixie" and attempt to log in using the password `DixieIsTheBest1`. The problem is that this only works if you have the intuition on how humans choose passwords, and the skills to conduct open-source intelligence gathering. 12 | 13 | We refined machine learning models on user data from Wattpad's 2020 security breach to generate targeted password guesses **automatically**. This approach combines the vast knowledge of a 350 million parameter–model with the personal information of 10 thousand users, including usernames, phone numbers, and personal descriptions. Despite the small training set size, our model already produces more accurate results than non-personalized guesses. 14 | 15 | ## About 16 | 17 | [ACM Research](https://acmutd.co/research) is a division of the Association of Computing Machinery at the University of Texas at Dallas. Over 10 weeks, six 4-person teams work with a team lead and a faculty advisor on a research project about anything from [phishing email detection](https://github.com/ACM-Research/thephishingproject) to [virtual reality video compression](https://github.com/ACM-Research/vr-user-behavior-clustering). [Applications]([https://acmutd.co/apply/](https://acm-utd.us.auth0.com/u/login?state=hKFo2SBqaVo3aDFHeXlRaUVzd1FKVHh2TGtMUDlyZER0dDExM6Fur3VuaXZlcnNhbC1sb2dpbqN0aWTZIHdNNHUybEZyckF6Y2hKaFpnOGhNVUhmeWJWeklPTUlCo2NpZNkgRnNxalhPRXZURHZUM3d5M09qWkdtYnZLMTVyMmZsTVM)) to participate open each semester. 18 | 19 | ## Methods 20 | 21 | In June 2020, Wattpad (an online platform for reading and writing stories) was hacked, and the personal information and passwords of 270 million users was revealed. This data breach is unique in that it connects unstructured text data (user descriptions and statuses) to corresponding passwords. Other data breaches (such as from the dating websites Mate1.com and Ashley Madison) share this property, but we had trouble ethically accessing them. This kind of data is particularly well-suited for refining a large text transformer like GPT-3, and it's what sets our research apart from a previous study[^1] which created a framework for generating targeted guesses using **structured** pieces of user information. 22 | 23 | The original dataset's passwords were hashed with the bcrypt algorithm, so we used data from the crowdsourced password recovery website Hashmob to match plain text passwords with corresponding user information. 24 | 25 | > ### GPT-3 and Language Modeling 26 | > 27 | > A language model is a machine learning model that can look at part of a sentence and predict the next word. The most famous language models are smartphone keyboards that suggest the next word based on what you've already typed. 28 | > 29 | > GPT-3, or Generative Pre-trained Transformer 3, is an artificial intelligence created by OpenAI in February 2019. GPT-3 can translate text, answer questions, summarizes passages, and generate text output on an incredibly sophisticated level. It comes in multiple versions with varying complexity – we used the smallest model "Ada". 30 | 31 | Using GPT-3's fine-tuning API, we showed a pre-existing text transformer model 10 thousand examples for how to correlate a user's personal information with their password. 32 | 33 | ![](./poster/prompt_diagram.svg) 34 | 35 | ## Results 36 | 37 | ![](./poster/similarity_graph.svg) 38 | 39 | Using targeted guesses greatly increases the likelihood of not only guessing a target's password, but also guessing passwords that are similar to it. We generated 20 guesses each for 1000 user examples to compare our approach with a brute-force, non-targeted method. The **Levenshtein distance algorithm** shows how similar each password guess is to the real user password. In the first figure above, it may seem that the brute-force method produces more similar passwords on average, but our model has a higher density for Levenshtein ratios of 0.7 and above (the more significant range). 40 | 41 | ![](./poster/comparison_graph.svg) 42 | 43 | Not only are the targeted guesses more similar to the target's password, but the model is also able to guess more passwords than brute-forcing, and in significantly fewer tries. The second figure shows that our model is often able to guess the target's password in **fewer than 10 tries**, whereas the brute-forcing method performs less consistently. 44 | 45 | ## Demo 46 | 47 | We created an interactive web demo that shows you what our model thinks your password could be. The back end is built with Flask and directly calls the OpenAI Completion API with our fine-tuned model to generate password guesses based on the inputted personal information. Try it out at [guessmypassword.herokuapp.com](https://guessmypassword.herokuapp.com). 48 | 49 | ![](./poster/demo_screenshot.png) 50 | 51 | ## Conclusion 52 | 53 | Our study reveals both the utility and danger of accessible advanced machine learning models. With our approach, an attacker could automatically attempt to hack into users' accounts more efficiently than with traditional methods, or crack more password hashes from a data leak once brute-force or dictionary attacks reach their effective limit. However, anyone can use this model to see if their passwords are vulnerable, and businesses could run this model on their employees' data to ensure that their company credentials are secure from password guessing attacks. 54 | 55 | ## References 56 | 57 | [^1]: Wang, D., Zhang, Z., Wang, P., Yan, J., Huang, X. (2016). Targeted Online Password Guessing: An Underestimated Threat. 58 | [^2]: Hitaj, B., Gasti, P., Ateniese, G., Perez-Cruz, F. (2019). PassGAN: A Deep Learning Approach for Password Guessing. 59 | [^3]: Melicher, W., Ur, B., Segreti, S., Komanduri, S., Bauer, L., Christin, N., Cranor, L. (2016). Fast, Lean, and Accurate: Modeling Password Guessability Using Neural Networks. 60 | -------------------------------------------------------------------------------- /demo/static/styles/main.scss: -------------------------------------------------------------------------------- 1 | // Themes 2 | 3 | @mixin theme($dark) { 4 | @if $dark { 5 | --background: #212128; 6 | --background-dark: #18181c; 7 | --foreground: white; 8 | --accent: #c8e0f4; 9 | --shadow: rgba(15, 15, 15, .5); 10 | } @else { 11 | --background: #F8FFFA; 12 | --background-dark: #EFF6FF; 13 | --foreground: black; 14 | --accent: #a9d2f3; 15 | --shadow: rgba(15, 15, 15, .25); 16 | } 17 | } 18 | 19 | // System dark theme 20 | @media (prefers-color-scheme: dark) { 21 | :root { 22 | @include theme($dark: true); 23 | } 24 | } 25 | 26 | // System light theme 27 | @media (prefers-color-scheme: light) { 28 | :root { 29 | @include theme($dark: false); 30 | } 31 | } 32 | 33 | // Forced dark theme 34 | .dark { 35 | @include theme($dark: true); 36 | } 37 | 38 | // Forced light theme 39 | .light { 40 | @include theme($dark: false); 41 | } 42 | 43 | 44 | // Material Icons 45 | 46 | @font-face { 47 | font-family: "Material Icons"; 48 | font-style: normal; 49 | font-weight: 400; 50 | src: url(/fonts/MaterialIcons-Round.woff2) format('woff2'); 51 | } 52 | 53 | .material-icons { 54 | font-family: "Material Icons"; 55 | font-weight: normal; 56 | font-style: normal; 57 | font-size: 24px; 58 | line-height: 1; 59 | letter-spacing: normal; 60 | text-transform: none; 61 | display: inline-block; 62 | white-space: nowrap; 63 | word-wrap: normal; 64 | direction: ltr; 65 | -moz-font-feature-settings: "liga"; 66 | -moz-osx-font-smoothing: grayscale; 67 | } 68 | 69 | // Actual styles 70 | 71 | // Scrollbar style 72 | /* Works on Firefox */ 73 | * { 74 | scrollbar-width: thin; 75 | scrollbar-color: rgba(0, 0, 0, 0) rgb(50, 50, 50); 76 | } 77 | 78 | /* Works on Chrome, Edge, and Safari */ 79 | *::-webkit-scrollbar { 80 | width: 8px; 81 | } 82 | 83 | *::-webkit-scrollbar-track { 84 | background: rgba(0, 0, 0, 0); 85 | } 86 | 87 | *::-webkit-scrollbar-thumb { 88 | background-color: rgb(50, 50, 50); 89 | border-radius: 20px; 90 | border: 6px solid rgba(0, 0, 0, 0); 91 | } 92 | 93 | html { 94 | scroll-behavior: smooth; 95 | } 96 | 97 | body { 98 | background-color: var(--background); 99 | color: var(--foreground); 100 | font-family: sans-serif; 101 | text-align: center; 102 | margin: 0; 103 | } 104 | 105 | header { 106 | padding: 0 2rem 1rem 2rem; 107 | 108 | button { 109 | appearance: none; 110 | background-color: var(--background); 111 | border: none; 112 | border-radius: 50%; 113 | color: var(--foreground); 114 | display: flex; 115 | justify-content: center; 116 | place-items: center; 117 | width: 40px; 118 | height: 40px; 119 | margin: 0 5px; 120 | } 121 | 122 | button:hover { 123 | background-color: var(--foreground); 124 | color: var(--background); 125 | } 126 | 127 | div { 128 | background-color: var(--background); 129 | border-radius: 5px; 130 | cursor: default; 131 | display: flex; 132 | align-items: center; 133 | align-content: center; 134 | padding: .25rem; 135 | position: absolute; 136 | right: 1em; 137 | top: 1em; 138 | 139 | button:not(.active) { 140 | display: none; 141 | } 142 | } 143 | 144 | div.open { 145 | box-shadow: 0 0 4px 2px var(--shadow); 146 | 147 | button { 148 | display: flex; 149 | } 150 | } 151 | } 152 | 153 | main { 154 | display: flex; 155 | min-height: calc(90vh); 156 | } 157 | 158 | form, section { 159 | background-color: var(--background-dark); 160 | border-radius: 10px; 161 | box-shadow: 0 0 4px 2px var(--shadow); 162 | margin: 1vh auto; 163 | padding: 1rem; 164 | width: 40vw; 165 | } 166 | 167 | ul { 168 | font-size: 1.1rem; 169 | overflow-y: auto; 170 | height: calc(100% - 5rem); 171 | padding: 0; 172 | 173 | li { 174 | border-bottom: 1px solid var(--background); 175 | list-style-type: none; 176 | padding: 0.5em 0.25em; 177 | margin: 0 2em; 178 | } 179 | } 180 | 181 | #results { 182 | display: none; 183 | } 184 | 185 | footer { 186 | background-color: var(--background-dark); 187 | padding: 1rem; 188 | } 189 | 190 | @media screen and (max-width: 1200px) { 191 | main { 192 | flex-direction: column; 193 | height: auto; 194 | } 195 | 196 | form, section { 197 | height: auto; 198 | width: 75vw; 199 | } 200 | } 201 | 202 | // Animation 203 | 204 | @media screen and (min-width: 1201px) { 205 | .slide { 206 | animation-duration: 1s; 207 | animation-name: slide; 208 | position: relative; 209 | } 210 | 211 | @keyframes slide { 212 | from { 213 | right: -25vw; 214 | } 215 | 216 | to { 217 | right: 0; 218 | } 219 | } 220 | } 221 | 222 | #results { 223 | animation-name: fade-in; 224 | animation-duration: 1s; 225 | } 226 | 227 | @keyframes fade-in { 228 | from { 229 | opacity: 0; 230 | } 231 | 232 | to { 233 | opacity: 1; 234 | } 235 | } 236 | 237 | // Form elements 238 | 239 | form { 240 | display: flex; 241 | flex-direction: column; 242 | 243 | label { 244 | text-align: left; 245 | } 246 | 247 | textarea { 248 | resize: none; 249 | } 250 | } 251 | 252 | .form-input { 253 | display: flex; 254 | flex-direction: column; 255 | font-size: 1.25em; 256 | margin: 0 1em; 257 | padding: 0.5em 1em; 258 | } 259 | 260 | .grow { 261 | flex-grow: 1; 262 | 263 | textarea { 264 | flex-grow: 1; 265 | } 266 | } 267 | 268 | input, textarea { 269 | background-color: var(--background-dark); 270 | border: 2px solid var(--foreground); 271 | border-radius: 10px; 272 | color: var(--foreground); 273 | font-size: 1rem; 274 | font-family: sans-serif; 275 | margin-top: 0.5em; 276 | padding: 0.5em 0.75em; 277 | } 278 | 279 | 280 | .buttons { 281 | display: flex; 282 | justify-content: space-between; 283 | padding: 1em 1.75em; 284 | } 285 | 286 | button { 287 | appearance: none; 288 | background-color: var(--accent); 289 | color: black; 290 | cursor: pointer; 291 | border: none; 292 | border-radius: 5px; 293 | margin: 0 1em; 294 | padding: .5em 1.5em; 295 | } 296 | 297 | button:hover { 298 | box-shadow: 0 0 4px 2px var(--shadow); 299 | } 300 | 301 | @media screen and (max-width: 450px) { 302 | form { 303 | width: 80vw; 304 | } 305 | 306 | .form-input { 307 | margin: 0 .5rem; 308 | padding: 0.5rem 0.25rem; 309 | } 310 | 311 | .buttons { 312 | padding: 1em .75em; 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /poster/poster_backup.tex: -------------------------------------------------------------------------------- 1 | % Gemini theme 2 | % https://github.com/anishathalye/gemini 3 | % 4 | % We try to keep this Overleaf template in sync with the canonical source on 5 | % GitHub, but it's recommended that you obtain the template directly from 6 | % GitHub to ensure that you are using the latest version. 7 | 8 | \documentclass[final]{beamer} 9 | 10 | % ==================== 11 | % Packages 12 | % ==================== 13 | 14 | \usepackage[T1]{fontenc} 15 | \usepackage{xcolor} 16 | \usepackage[size=custom,width=200,height=120,scale=2.0]{beamerposter} 17 | 18 | \usetheme{acm} 19 | \usecolortheme{acm} 20 | \usepackage{graphicx} 21 | \usepackage{booktabs} 22 | \usepackage{tikz} 23 | \usepackage{pgfplots} 24 | \pgfplotsset{compat=1.14} 25 | 26 | % ==================== 27 | % Lengths 28 | % ==================== 29 | 30 | % If you have N columns, choose \sepwidth and \colwidth such that 31 | % (N+1)*\sepwidth + N*\colwidth = \paperwidth 32 | \newlength{\sepwidth} 33 | \newlength{\colwidth} 34 | \setlength{\sepwidth}{0.025\paperwidth} 35 | \setlength{\colwidth}{0.3\paperwidth} 36 | 37 | \newcommand{\separatorcolumn}{\begin{column}{\sepwidth}\end{column}} 38 | 39 | % ==================== 40 | % Title 41 | % ==================== 42 | 43 | \title{Automating Targeted Password Guessing} 44 | 45 | \author{Aravindan Kasiraman \and Bradley Johnson \and Pranav Nair \and Roman Hauksson-Neill \and Sisira Aarukapalli } 46 | 47 | % ==================== 48 | % Footer (optional) 49 | % ==================== 50 | 51 | \footercontent{ 52 | ACM Research Symposium 2022 \hfill 53 | \href{https://github.com/ACM-Research/targeted-password-guesses}{https://github.com/ACM-Research/targeted-password-guesses} 54 | } 55 | % (can be left out to remove footer) 56 | 57 | 58 | % ==================== 59 | % Logo (optional) 60 | % ==================== 61 | 62 | % use this to include logos on the left and/or right side of the header: 63 | \logoright{\includegraphics[height=7cm]{logo_ACM_Research_light.pdf}} 64 | \logoleft{\includegraphics[height=7cm]{logo_UTD.pdf}} 65 | 66 | % ==================== 67 | % Body 68 | % ==================== 69 | 70 | \begin{document} 71 | 72 | \begin{frame}[t] 73 | \begin{columns}[t] 74 | \separatorcolumn 75 | \begin{column}{\colwidth} 76 | 77 | \begin{block}{Introduction} 78 | 79 | Imagine trying to hack into your friend's social media account by guessing what password they used to secure it. You do some research to come up with likely guesses – say, you discover they have a dog named "Dixie" and attempt to log in using the password {\tt DixieIsTheBest1}. The problem is that this only works if you have the intuition on how humans choose passwords, and the skills to conduct open-source intelligence gathering. 80 | 81 | We refined machine learning models on user data from Wattpad's 2020 security breach to generate targeted password guesses \textbf{automatically}. This approach combines the vast knowledge of a 350 million parameter–model with the personal information of 10 thousand users, including usernames, phone numbers, and personal descriptions. Despite the small training set size, our model already produces more accurate results than non-personalized guesses. 82 | 83 | \end{block} 84 | 85 | \begin{block}{Methods} 86 | 87 | In June 2020, Wattpad (an online platform for reading and writing stories) was hacked, and the personal information and passwords of 270 million users was revealed. This data breach is unique in that it connects unstructured text data (user descriptions and statuses) to corresponding passwords. Other data breaches (such as from the dating websites Mate1.com and Ashley Madison) share this property, but we had trouble ethically accessing them. This kind of data is particularly well-suited for refining a large text transformer like GPT-3, and it's what sets our research apart from a previous study [1] which created a framework for generating targeted guesses using \textbf{structured} pieces of user information. 88 | 89 | The original dataset's passwords were hashed with the bcrypt algorithm, so we used data from the crowdsourced password recovery website Hashmob to match plain text passwords with corresponding user information. 90 | 91 | \vspace{12mm} 92 | 93 | \begin{alertblock}{GPT-3 and Language Modeling} 94 | 95 | A language model is a machine learning model that can look at part of a sentence and predict the next word. The most famous language models are smartphone keyboards that suggest the next word based on what you've already typed. 96 | 97 | GPT-3, or Generative Pre-trained Transformer 3, is an artificial intelligence created by OpenAI in February 2019. GPT-3 can translate text, answer questions, summarizes passages, and generate text output on an incredibly sophisticated level. It comes in multiple versions with varying complexity – we used the smallest model "Ada". 98 | 99 | \end{alertblock} 100 | 101 | \end{block} 102 | 103 | \end{column} 104 | 105 | \separatorcolumn 106 | 107 | \begin{column}{\colwidth} 108 | 109 | Using GPT-3's fine-tuning API, we showed a pre-existing text transformer model 10 thousand examples for how to correlate a user's personal information with their password. 110 | 111 | \vspace{12mm} 112 | 113 | \includegraphics[width=\linewidth]{diagram.pdf} 114 | 115 | \vspace{12mm} 116 | 117 | \begin{block}{Results} 118 | 119 | \vspace{12mm} 120 | 121 | \begin{columns} 122 | \begin{column}{0.5\colwidth} 123 | \includegraphics[width=\linewidth]{img/similarity_graph.pdf} 124 | \end{column} 125 | 126 | \begin{column}{0.5\colwidth} 127 | \includegraphics[width=\linewidth]{comparison_graph.pdf} 128 | \end{column} 129 | \end{columns} 130 | 131 | Using targeted guesses greatly increases the likelihood of not only guessing a target's password, but also guessing passwords that are similar to it. We generated 20 guesses each for 1000 user examples to compare our approach with a brute-force, non-targeted method. The \textbf{Levenshtein distance algorithm} shows how similar each password guess is to the real user password. In the first figure above, it may seem that the brute-force method produces more similar passwords on average, but our model has a higher density for Levenshtein ratios of 0.7 and above (the more significant range). 132 | 133 | Not only are the targeted guesses more similar to the target's password, but the model is also able to guess more passwords than brute-forcing, and in significantly fewer tries. The second figure shows that our model is often able to guess the target's password in \textbf{fewer than 10 tries}, whereas the brute-forcing method performs less consistently. 134 | 135 | \end{block} 136 | \end{column} 137 | 138 | \separatorcolumn 139 | 140 | \begin{column}{\colwidth} 141 | 142 | \begin{block}{Demo} 143 | 144 | We created an interactive web demo that shows you what our model thinks your password could be. The back end is built with Flask and directly calls the OpenAI Completion API with our fine-tuned model to generate password guesses based on the inputted personal information. Try it out at {\tt guessmypassword.herokuapp.com}. 145 | 146 | \vspace{12mm} 147 | 148 | \begin{columns} 149 | \begin{column}{0.8\colwidth} 150 | 151 | \includegraphics[width=\linewidth]{demo_screenshot.png} 152 | 153 | \end{column} 154 | 155 | \begin{column}{0.2\colwidth} 156 | 157 | \includegraphics[width=\linewidth]{demo_QR_code.pdf} 158 | 159 | \end{column} 160 | \end{columns} 161 | 162 | \end{block} 163 | 164 | \begin{block}{Conclusion} 165 | 166 | Our study reveals both the utility and danger of accessible advanced machine learning models. With our approach, an attacker could automatically attempt to hack into users' accounts more efficiently than with traditional methods, or crack more password hashes from a data leak once brute-force or dictionary attacks reach their effective limit. However, anyone can use this model to see if their passwords are vulnerable, and businesses could run this model on their employees' data to ensure that their company credentials are secure from password guessing attacks. 167 | 168 | \end{block} 169 | 170 | \begin{block}{References} 171 | 172 | {\small 173 | [1] Wang, D., Zhang, Z., Wang, P., Yan, J., Huang, X. (2016). Targeted Online Password Guessing: An Underestimated Threat. 174 | 175 | [2] Hitaj, B., Gasti, P., Ateniese, G., Perez-Cruz, F. (2019). PassGAN: A Deep Learning Approach for Password Guessing. 176 | 177 | [3] Melicher, W., Ur, B., Segreti, S., Komanduri, S., Bauer, L., Christin, N., Cranor, L. (2016). Fast, Lean, and Accurate: Modeling Password Guessability Using Neural Networks. 178 | } 179 | \end{block} 180 | 181 | \end{column} 182 | 183 | \separatorcolumn 184 | \end{columns} 185 | \end{frame} 186 | 187 | \end{document} 188 | -------------------------------------------------------------------------------- /code/training.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pandas as pd\n", 10 | "import numpy as np\n", 11 | "import sqlite3" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "conn = sqlite3.connect('data/passwords_large.db')\n", 21 | "df = pd.read_sql_query('SELECT * from users', conn)\n", 22 | "df.head()" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "# Add prompt with required values that each row entry has\n", 32 | "df['prompt'] = 'Username is ' + df['name'] + '\\nEmail is ' + df['email'] + '\\n'\n", 33 | "# Add in other column values to prompt if value is not None\n", 34 | "df.loc[df['realname'].notna(), 'prompt'] = df['prompt'] + 'Real name is ' + df['realname'] + '\\n'\n", 35 | "df.loc[df['dob'].notna(), 'prompt'] = df['prompt'] + 'Date of Birth is ' + df['dob'] + '\\n'\n", 36 | "df.loc[df['gender'] == 'F', 'prompt'] = df['prompt'] + 'Gender is Female\\n'\n", 37 | "df.loc[df['gender'] == 'M', 'prompt'] = df['prompt'] + 'Gender is Male\\n'\n", 38 | "df.loc[df['country'].notna(), 'prompt'] = df['prompt'] + 'Country is ' + df['country'] + '\\n'\n", 39 | "df.loc[df['twitterid'].notna(), 'prompt'] = df['prompt'] + 'Twitter ID is ' + df['twitterid'] + '\\n'\n", 40 | "df.loc[df['about'].notna(), 'prompt'] = df['prompt'] + 'User information: ' + df['about'] + '\\n'\n", 41 | "df.loc[df['status'].notna(), 'prompt'] = df['prompt'] + 'User status: ' + df['status'] + '\\n'\n", 42 | "\n", 43 | "df['prompt'] += 'Password: \\n###\\n'\n", 44 | "\n", 45 | "df['completion'] = ' ' + df['password'] + '\\n'" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "# 50-50 train-test split\n", 55 | "train, test = np.split(df, 2)\n", 56 | "train.to_pickle('data/train_dataset.pkl')\n", 57 | "test.to_pickle('data/test_dataset.pkl')" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "# Export fine tuning input to JSONL format\n", 67 | "finetune_input = train[['prompt','completion']].sample(n=10000)\n", 68 | "finetune_input.to_json('data/finetune_input_10k.jsonl', orient='records', lines=True)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "### Testing & Analysis" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "import os\n", 85 | "import openai\n", 86 | "from dotenv import load_dotenv\n", 87 | "\n", 88 | "load_dotenv()\n", 89 | "openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n", 90 | "\n", 91 | "models = {\n", 92 | " \"100\": \"ada:ft-acm-research-password-team:100-examples-2022-04-25-22-50-35\",\n", 93 | " \"1k\": \"ada:ft-acm-research-password-team:1k-examples-2022-04-16-17-55-28\",\n", 94 | " \"10k\": \"ada:ft-acm-research-password-team:10k-examples-2022-04-16-18-15-21\"\n", 95 | "}\n", 96 | "\n", 97 | "def get_GPT3_completion(model, prompt):\n", 98 | " response = openai.Completion.create(\n", 99 | " model=model,\n", 100 | " prompt=prompt,\n", 101 | " max_tokens=32,\n", 102 | " temperature=0.8,\n", 103 | " stop=['\\n']\n", 104 | " )\n", 105 | " return response['choices'][0]['text']" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "import time\n", 115 | "from timeit import default_timer as timer\n", 116 | "from datetime import timedelta\n", 117 | "import Levenshtein\n", 118 | "import difflib" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "sample = test[:1000].copy()\n", 128 | "sample['guesses_model10k'] = 0\n", 129 | "sample['guessed_passwords'] = ''\n", 130 | "sample['levenshtein_similarity'] = 0.0\n", 131 | "sample['difflib_similarity'] = 0.0" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [ 140 | "count = 0\n", 141 | "progress = 10\n", 142 | "max_num_guesses = 20\n", 143 | "\n", 144 | "print(\"Beginning analysis...\")\n", 145 | "start = timer()\n", 146 | "try:\n", 147 | " for i, row in sample.iterrows():\n", 148 | " count += 1\n", 149 | " # call fine tuned model max_num_guesses times and check if it matches the password\n", 150 | " guessed_passwords = ''\n", 151 | " num_guesses = 0\n", 152 | " leven_max_similarity = 0.0\n", 153 | " difflib_max_similarity = 0.0\n", 154 | " for j in range(1,max_num_guesses+1):\n", 155 | " guessed_password = get_GPT3_completion(models[\"10k\"], row['prompt']).lstrip()\n", 156 | " guessed_passwords += guessed_password\n", 157 | "\n", 158 | " # compute how similar the guessed password is to the actual password\n", 159 | " leven_similarity = Levenshtein.ratio(row['password'], guessed_password)\n", 160 | " if leven_similarity > leven_max_similarity:\n", 161 | " leven_max_similarity = leven_similarity\n", 162 | " \n", 163 | " difflib_similarity = difflib.SequenceMatcher(None, row['password'], guessed_password).ratio()\n", 164 | " if difflib_similarity > difflib_max_similarity:\n", 165 | " difflib_max_similarity = difflib_similarity\n", 166 | " \n", 167 | " # store number of guesses it took to guess the correct password\n", 168 | " if guessed_password == row['password']:\n", 169 | " num_guesses = j\n", 170 | " print(f\"Successfully guessed password of row {count} / 1000 [index {i}] in {num_guesses} tries\\n\")\n", 171 | " break\n", 172 | " \n", 173 | " # append comma to all except last guessed password in the list\n", 174 | " if j < max_num_guesses:\n", 175 | " guessed_passwords += ','\n", 176 | " \n", 177 | " # update row in dataframe\n", 178 | " sample.loc[i, ['guesses_model10k', 'guessed_passwords', 'levenshtein_similarity', 'difflib_similarity']] = num_guesses, guessed_passwords, leven_max_similarity, difflib_max_similarity\n", 179 | " if count % progress == 0:\n", 180 | " now = timer()\n", 181 | " print(f\"[{timedelta(seconds=now-start)}] Finished processing row {count} / 1000\\nActual password: {row['password']} [Levenshtein Similarity: {leven_max_similarity:.2f}] [DiffLib Similarity: {difflib_max_similarity:.2f}]\\nGuessed passwords: {guessed_passwords}\\n\")\n", 182 | "except:\n", 183 | " print('*** Ran into an error')\n", 184 | "finally:\n", 185 | " end = timer()\n", 186 | " print(f\"Analysis Completed. Total time elapsed: {timedelta(seconds=end-start)}\")\n", 187 | " # export to pickle file\n", 188 | " sample.to_pickle(f\"output/analysis_{time.strftime('%b_%d_%Y_%H-%M-%S', time.gmtime(time.time()))}.pkl\")" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": null, 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "data = pd.read_pickle('output/analysis_Apr_26_2022_03-29-11.pkl')\n", 198 | "password_list = np.loadtxt('data/top10k_passwords.txt', dtype='str')\n" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": null, 204 | "metadata": {}, 205 | "outputs": [], 206 | "source": [ 207 | "data['guesses_top100'] = 0\n", 208 | "data['top100_levenshtein_similarity'] = 0.0\n", 209 | "data['top100_difflib_similarity'] = 0.0\n", 210 | "start = timer() \n", 211 | "\n", 212 | "for i, row in data.iterrows():\n", 213 | " num_guesses = 0\n", 214 | " leven_max_similarity = 0.0\n", 215 | " difflib_max_similarity = 0.0\n", 216 | " for j, password in enumerate(password_list[:100]):\n", 217 | " # compute how similar the guessed password is to the actual password\n", 218 | " leven_similarity = Levenshtein.ratio(row['password'], password)\n", 219 | " if leven_similarity > leven_max_similarity:\n", 220 | " leven_max_similarity = leven_similarity\n", 221 | " \n", 222 | " difflib_similarity = difflib.SequenceMatcher(None, row['password'], password).ratio()\n", 223 | " if difflib_similarity > difflib_max_similarity:\n", 224 | " difflib_max_similarity = difflib_similarity\n", 225 | " \n", 226 | " # store number of guesses it took to guess the correct password\n", 227 | " if password == row['password']:\n", 228 | " num_guesses = j+1\n", 229 | " break\n", 230 | "\n", 231 | " # update row in dataframe\n", 232 | " data.loc[i, ['guesses_top100', 'top100_levenshtein_similarity', 'top100_difflib_similarity']] = num_guesses, leven_max_similarity, difflib_max_similarity\n", 233 | " \n", 234 | "\n", 235 | "end = timer()\n", 236 | "print(timedelta(seconds=end-start))\n", 237 | "filename = f\"output/analysis_{time.strftime('%b_%d_%Y_%H-%M-%S', time.gmtime(time.time()))}_top100list.pkl\"\n", 238 | "print(f'Exported as {filename}')\n", 239 | "data.to_pickle(filename)\n" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": {}, 245 | "source": [ 246 | "### Timing how long it takes to send 20 API Requests\n", 247 | "average API request time = 16.208506 seconds / 100 = 1.621 seconds per request" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": {}, 254 | "outputs": [], 255 | "source": [ 256 | "from timeit import default_timer as timer\n", 257 | "from datetime import timedelta\n", 258 | "start = timer()\n", 259 | "n = 100\n", 260 | "row = sample.iloc[0]\n", 261 | "\n", 262 | "for i in range(0, n):\n", 263 | " guessed_password = get_GPT3_completion(row['prompt'])\n", 264 | "end = timer()\n", 265 | "print(timedelta(seconds=end-start))\n" 266 | ] 267 | }, 268 | { 269 | "cell_type": "code", 270 | "execution_count": null, 271 | "metadata": {}, 272 | "outputs": [], 273 | "source": [ 274 | "password_list = np.loadtxt('data/top10k_passwords.txt', dtype='str')\n", 275 | "sample = df.sample(1000)\n", 276 | "row = sample.iloc[0]\n", 277 | "start = timer() \n", 278 | "for i, password in enumerate(password_list):\n", 279 | " if row['password'] == password:\n", 280 | " pass\n", 281 | "\n", 282 | "end = timer()\n", 283 | "print(timedelta(seconds=end-start))\n" 284 | ] 285 | } 286 | ], 287 | "metadata": { 288 | "interpreter": { 289 | "hash": "2be5faf79681da6f2a61fdfdd5405d65d042280f7fba6178067603e3a2925119" 290 | }, 291 | "kernelspec": { 292 | "display_name": "Python 3.10.2 64-bit", 293 | "language": "python", 294 | "name": "python3" 295 | }, 296 | "language_info": { 297 | "codemirror_mode": { 298 | "name": "ipython", 299 | "version": 3 300 | }, 301 | "file_extension": ".py", 302 | "mimetype": "text/x-python", 303 | "name": "python", 304 | "nbconvert_exporter": "python", 305 | "pygments_lexer": "ipython3", 306 | "version": "3.10.2" 307 | }, 308 | "orig_nbformat": 4 309 | }, 310 | "nbformat": 4, 311 | "nbformat_minor": 2 312 | } 313 | -------------------------------------------------------------------------------- /demo/static/scripts/cash.min.js: -------------------------------------------------------------------------------- 1 | /* MIT https://github.com/fabiospampinato/cash */ 2 | (function(){ 3 | var aa={"class":"className",contenteditable:"contentEditable","for":"htmlFor",readonly:"readOnly",maxlength:"maxLength",tabindex:"tabIndex",colspan:"colSpan",rowspan:"rowSpan",usemap:"useMap"};function ba(a,b){try{return a(b)}catch(c){return b}} 4 | var e=document,k=window,ca=e.documentElement,p=e.createElement.bind(e),da=p("div"),q=p("table"),ea=p("tbody"),ha=p("tr"),v=Array.isArray,x=Array.prototype,ia=x.concat,y=x.filter,ja=x.indexOf,ka=x.map,la=x.push,ma=x.slice,z=x.some,na=x.splice,oa=/^#(?:[\w-]|\\.|[^\x00-\xa0])*$/,pa=/^\.(?:[\w-]|\\.|[^\x00-\xa0])*$/,qa=/<.+>/,ra=/^\w+$/; 5 | function A(a,b){var c=!!b&&11===b.nodeType;return a&&(c||B(b)||C(b))?!c&&pa.test(a)?b.getElementsByClassName(a.slice(1)):!c&&ra.test(a)?b.getElementsByTagName(a):b.querySelectorAll(a):[]} 6 | var D=function(){function a(b,c){if(b){if(b instanceof D)return b;var d=b;if(G(b)){if(d=(c instanceof D?c[0]:c)||e,d=oa.test(b)&&"getElementById"in d?d.getElementById(b.slice(1)):qa.test(b)?sa(b):A(b,d),!d)return}else if(H(b))return this.ready(b);if(d.nodeType||d===k)d=[d];this.length=d.length;b=0;for(c=this.length;ba?a+this.length:a]};I.eq=function(a){return J(this.get(a))};I.first=function(){return this.eq(0)};I.last=function(){return this.eq(-1)};function M(a,b,c){if(c)for(c=a.length;c--&&!1!==b.call(a[c],c,a[c]););else if(wa(a)){var d=Object.keys(a);c=0;for(var f=d.length;carguments.length?this[0]&&this[0][a]:this.each(function(d,f){f[a]=b});for(var c in a)this.prop(c,a[c]);return this}};I.removeProp=function(a){return this.each(function(b,c){delete c[aa[a]||a]})}; 11 | function N(){for(var a=[],b=0;barguments.length){if(!this[0]||!C(this[0]))return;var c=this[0].getAttribute(a);return null===c?void 0:c}return void 0===b?this:null===b?this.removeAttr(a):this.each(function(d,f){C(f)&&f.setAttribute(a,b)})}for(c in a)this.attr(c,a[c]);return this}}; 14 | I.toggleClass=function(a,b){var c=Q(a),d=void 0!==b;return this.each(function(f,g){C(g)&&M(c,function(h,m){d?b?g.classList.add(m):g.classList.remove(m):g.classList.toggle(m)})})};I.addClass=function(a){return this.toggleClass(a,!0)};I.removeClass=function(a){return arguments.length?this.toggleClass(a,!1):this.attr("class","")}; 15 | function R(a,b,c,d){for(var f=[],g=H(b),h=d&&O(d),m=0,l=a.length;marguments.length)return this[0]&&T(this[0],a,c);if(!a)return this;b=Ea(a,b,c);return this.each(function(f,g){C(g)&&(c?g.style.setProperty(a,b):g.style[a]=b)})}for(var d in a)this.css(d,a[d]);return this};var Fa=/^\s+|\s+$/;function Ga(a,b){a=a.dataset[b]||a.dataset[K(b)];return Fa.test(a)?a:ba(JSON.parse,a)} 19 | I.data=function(a,b){if(!a){if(!this[0])return;var c={},d;for(d in this[0].dataset)c[d]=Ga(this[0],d);return c}if(G(a))return 2>arguments.length?this[0]&&Ga(this[0],a):void 0===b?this:this.each(function(f,g){f=b;f=ba(JSON.stringify,f);g.dataset[K(a)]=f});for(d in a)this.data(d,a[d]);return this};function Ha(a,b){var c=a.documentElement;return Math.max(a.body["scroll"+b],c["scroll"+b],a.body["offset"+b],c["offset"+b],c["client"+b])} 20 | function Ia(a,b){return V(a,"border"+(b?"Left":"Top")+"Width")+V(a,"padding"+(b?"Left":"Top"))+V(a,"padding"+(b?"Right":"Bottom"))+V(a,"border"+(b?"Right":"Bottom")+"Width")} 21 | M([!0,!1],function(a,b){M(["Width","Height"],function(c,d){I[(b?"outer":"inner")+d]=function(f){if(this[0])return L(this[0])?b?this[0]["inner"+d]:this[0].document.documentElement["client"+d]:B(this[0])?Ha(this[0],d):this[0][(b?"offset":"client")+d]+(f&&b?V(this[0],"margin"+(c?"Top":"Left"))+V(this[0],"margin"+(c?"Bottom":"Right")):0)}})}); 22 | M(["Width","Height"],function(a,b){var c=b.toLowerCase();I[c]=function(d){if(!this[0])return void 0===d?void 0:this;if(!arguments.length)return L(this[0])?this[0].document.documentElement["client"+b]:B(this[0])?Ha(this[0],b):this[0].getBoundingClientRect()[c]-Ia(this[0],!a);var f=parseInt(d,10);return this.each(function(g,h){C(h)&&(g=T(h,"boxSizing"),h.style[c]=Ea(c,f+("border-box"===g?Ia(h,!a):0)))})}});var Ja={}; 23 | I.toggle=function(a){return this.each(function(b,c){if(C(c))if(void 0===a?"none"===T(c,"display"):a){if(c.style.display=c.___cd||"","none"===T(c,"display")){b=c.style;c=c.tagName;if(Ja[c])c=Ja[c];else{var d=p(c);e.body.insertBefore(d,null);var f=T(d,"display");e.body.removeChild(d);c=Ja[c]="none"!==f?f:"block"}b.display=c}}else c.___cd=T(c,"display"),c.style.display="none"})};I.hide=function(){return this.toggle(!1)};I.show=function(){return this.toggle(!0)}; 24 | function Ka(a,b){return!b||!z.call(b,function(c){return 0>a.indexOf(c)})}var W={focus:"focusin",blur:"focusout"},X={mouseenter:"mouseover",mouseleave:"mouseout"},La=/^(mouse|pointer|contextmenu|drag|drop|click|dblclick)/i;function Ma(a,b,c,d,f){var g=a.___ce=a.___ce||{};g[b]=g[b]||[];g[b].push([c,d,f]);a.addEventListener(b,f)}function Na(a){a=a.split(".");return[a[0],a.slice(1).sort()]} 25 | function Y(a,b,c,d,f){var g=a.___ce=a.___ce||{};if(b)g[b]&&(g[b]=g[b].filter(function(h){var m=h[0],l=h[1];h=h[2];if(f&&h.guid!==f.guid||!Ka(m,c)||d&&d!==l)return!0;a.removeEventListener(b,h)}));else for(b in g)Y(a,b,c,d,f)} 26 | I.off=function(a,b,c){var d=this;if(void 0===a)this.each(function(g,h){(C(h)||B(h)||L(h))&&Y(h)});else if(G(a))H(b)&&(c=b,b=""),M(Q(a),function(g,h){g=Na(h);h=g[0];var m=g[1],l=X[h]||W[h]||h;d.each(function(u,w){(C(w)||B(w)||L(w))&&Y(w,l,m,b,c)})});else for(var f in a)this.off(f,a[f]);return this}; 27 | I.on=function(a,b,c,d,f){var g=this;if(!G(a)){for(var h in a)this.on(h,b,c,a[h],f);return this}G(b)||(void 0!==b&&null!==b&&(void 0!==c&&(d=c),c=b),b="");H(d)||(d=c,c=void 0);if(!d)return this;M(Q(a),function(m,l){m=Na(l);l=m[0];var u=m[1],w=X[l]||W[l]||l,U=l in X,E=l in W;w&&g.each(function(t,n){if(C(n)||B(n)||L(n))t=function Ra(r){if(r.target["___i"+r.type])return r.stopImmediatePropagation();if(!r.namespace||Ka(u,r.namespace.split(".")))if(b||!(E&&(r.target!==n||r.___ot===w)||U&&r.relatedTarget&& 28 | n.contains(r.relatedTarget))){var fa=n;if(b){for(var F=r.target;!ua(F,b);){if(F===n)return;F=F.parentNode;if(!F)return}fa=F}Object.defineProperty(r,"currentTarget",{configurable:!0,get:function(){return fa}});Object.defineProperty(r,"delegateTarget",{configurable:!0,get:function(){return n}});Object.defineProperty(r,"data",{configurable:!0,get:function(){return c}});F=d.call(fa,r,r.___td);f&&Y(n,w,u,b,Ra);!1===F&&(r.preventDefault(),r.stopPropagation())}},t.guid=d.guid=d.guid||J.guid++,Ma(n,w,u,b, 29 | t)})});return this};I.one=function(a,b,c,d){return this.on(a,b,c,d,!0)};I.ready=function(a){function b(){return setTimeout(a,0,J)}"loading"!==e.readyState?b():e.addEventListener("DOMContentLoaded",b);return this}; 30 | I.trigger=function(a,b){if(G(a)){var c=Na(a),d=c[0];c=c[1];var f=X[d]||W[d]||d;if(!f)return this;var g=La.test(f)?"MouseEvents":"HTMLEvents";a=e.createEvent(g);a.initEvent(f,!0,!0);a.namespace=c.join(".");a.___ot=d}a.___td=b;var h=a.___ot in W;return this.each(function(m,l){h&&H(l[a.___ot])&&(l["___i"+a.type]=!0,l[a.___ot](),l["___i"+a.type]=!1);l.dispatchEvent(a)})}; 31 | function Oa(a){return a.multiple&&a.options?R(y.call(a.options,function(b){return b.selected&&!b.disabled&&!b.parentNode.disabled}),"value"):a.value||""}var Pa=/%20/g,Qa=/\r?\n/g,Sa=/file|reset|submit|button|image/i,Ta=/radio|checkbox/i; 32 | I.serialize=function(){var a="";this.each(function(b,c){M(c.elements||[c],function(d,f){f.disabled||!f.name||"FIELDSET"===f.tagName||Sa.test(f.type)||Ta.test(f.type)&&!f.checked||(d=Oa(f),void 0!==d&&(d=v(d)?d:[d],M(d,function(g,h){g=a;h="&"+encodeURIComponent(f.name)+"="+encodeURIComponent(h.replace(Qa,"\r\n")).replace(Pa,"+");a=g+h})))})});return a.slice(1)}; 33 | I.val=function(a){return arguments.length?this.each(function(b,c){if((b=c.multiple&&c.options)||Ta.test(c.type)){var d=v(a)?ka.call(a,String):null===a?[]:[String(a)];b?M(c.options,function(f,g){g.selected=0<=d.indexOf(g.value)},!0):c.checked=0<=d.indexOf(c.value)}else c.value=void 0===a||null===a?"":a}):this[0]&&Oa(this[0])};I.clone=function(){return this.map(function(a,b){return b.cloneNode(!0)})};I.detach=function(a){P(this,a).each(function(b,c){c.parentNode&&c.parentNode.removeChild(c)});return this}; 34 | var Ua=/^\s*<(\w+)[^>]*>/,Va=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,Wa={"*":da,tr:ea,td:ha,th:ha,thead:q,tbody:q,tfoot:q};function sa(a){if(!G(a))return[];if(Va.test(a))return[p(RegExp.$1)];var b=Ua.test(a)&&RegExp.$1;b=Wa[b]||Wa["*"];b.innerHTML=a;return J(b.childNodes).detach().get()}J.parseHTML=sa;I.empty=function(){return this.each(function(a,b){for(;b.firstChild;)b.removeChild(b.firstChild)})}; 35 | I.html=function(a){return arguments.length?void 0===a?this:this.each(function(b,c){C(c)&&(c.innerHTML=a)}):this[0]&&this[0].innerHTML};I.remove=function(a){P(this,a).detach().off();return this};I.text=function(a){return void 0===a?this[0]?this[0].textContent:"":this.each(function(b,c){C(c)&&(c.textContent=a)})};I.unwrap=function(){this.parent().each(function(a,b){"BODY"!==b.tagName&&(a=J(b),a.replaceWith(a.children()))});return this}; 36 | I.offset=function(){var a=this[0];if(a)return a=a.getBoundingClientRect(),{top:a.top+k.pageYOffset,left:a.left+k.pageXOffset}};I.offsetParent=function(){return this.map(function(a,b){for(a=b.offsetParent;a&&"static"===T(a,"position");)a=a.offsetParent;return a||ca})}; 37 | I.position=function(){var a=this[0];if(a){var b="fixed"===T(a,"position"),c=b?a.getBoundingClientRect():this.offset();if(!b){var d=a.ownerDocument;for(b=a.offsetParent||d.documentElement;(b===d.body||b===d.documentElement)&&"static"===T(b,"position");)b=b.parentNode;b!==a&&C(b)&&(d=J(b).offset(),c.top-=d.top+V(b,"borderTopWidth"),c.left-=d.left+V(b,"borderLeftWidth"))}return{top:c.top-V(a,"marginTop"),left:c.left-V(a,"marginLeft")}}}; 38 | I.children=function(a){return P(J(S(R(this,function(b){return b.children}))),a)};I.contents=function(){return J(S(R(this,function(a){return"IFRAME"===a.tagName?[a.contentDocument]:"TEMPLATE"===a.tagName?a.content.childNodes:a.childNodes})))};I.find=function(a){return J(S(R(this,function(b){return A(a,b)})))};var Xa=/^\s*\s*$/g,Ya=/^$|^module$|\/(java|ecma)script/i,Za=["type","src","nonce","noModule"]; 39 | function $a(a,b){a=J(a);a.filter("script").add(a.find("script")).each(function(c,d){if(Ya.test(d.type)&&ca.contains(d)){var f=p("script");f.text=d.textContent.replace(Xa,"");M(Za,function(g,h){d[h]&&(f[h]=d[h])});b.head.insertBefore(f,null);b.head.removeChild(f)}})} 40 | function Z(a,b,c,d,f,g,h,m){M(a,function(l,u){M(J(u),function(w,U){M(J(b),function(E,t){var n=c?t:U;E=c?w:E;t=c?U:t;n=E?n.cloneNode(!0):n;E=!E;f?t.insertBefore(n,d?t.firstChild:null):"HTML"===t.nodeName?t.parentNode.replaceChild(n,t):t.parentNode.insertBefore(n,d?t:t.nextSibling);E&&$a(n,t.ownerDocument)},m)},h)},g);return b}I.after=function(){return Z(arguments,this,!1,!1,!1,!0,!0)};I.append=function(){return Z(arguments,this,!1,!1,!0)};I.appendTo=function(a){return Z(arguments,this,!0,!1,!0)}; 41 | I.before=function(){return Z(arguments,this,!1,!0)};I.insertAfter=function(a){return Z(arguments,this,!0,!1,!1,!1,!1,!0)};I.insertBefore=function(a){return Z(arguments,this,!0,!0)};I.prepend=function(){return Z(arguments,this,!1,!0,!0,!0,!0)};I.prependTo=function(a){return Z(arguments,this,!0,!0,!0,!1,!1,!0)};I.replaceWith=function(a){return this.before(a).remove()};I.replaceAll=function(a){J(a).replaceWith(this);return this}; 42 | I.wrapAll=function(a){a=J(a);for(var b=a[0];b.children.length;)b=b.firstElementChild;this.first().before(a);return this.appendTo(b)};I.wrap=function(a){return this.each(function(b,c){var d=J(a)[0];J(c).wrapAll(b?d.cloneNode(!0):d)})};I.wrapInner=function(a){return this.each(function(b,c){b=J(c);c=b.contents();c.length?c.wrapAll(a):b.append(a)})};I.has=function(a){var b=G(a)?function(c,d){return A(a,d).length}:function(c,d){return d.contains(a)};return this.filter(b)}; 43 | I.is=function(a){var b=O(a);return z.call(this,function(c,d){return b.call(c,d,c)})};I.next=function(a,b,c){return P(J(S(R(this,"nextElementSibling",b,c))),a)};I.nextAll=function(a){return this.next(a,!0)};I.nextUntil=function(a,b){return this.next(b,!0,a)};I.not=function(a){var b=O(a);return this.filter(function(c,d){return(!G(a)||C(d))&&!b.call(d,c,d)})};I.parent=function(a){return P(J(S(R(this,"parentNode"))),a)}; 44 | I.index=function(a){var b=a?J(a)[0]:this[0];a=a?this:J(b).parent().children();return ja.call(a,b)};I.closest=function(a){var b=this.filter(a);if(b.length)return b;var c=this.parent();return c.length?c.closest(a):b};I.parents=function(a,b){return P(J(S(R(this,"parentElement",!0,b))),a)};I.parentsUntil=function(a,b){return this.parents(b,a)};I.prev=function(a,b,c){return P(J(S(R(this,"previousElementSibling",b,c))),a)};I.prevAll=function(a){return this.prev(a,!0)}; 45 | I.prevUntil=function(a,b){return this.prev(b,!0,a)};I.siblings=function(a){return P(J(S(R(this,function(b){return J(b).parent().children().not(b)}))),a)};"undefined"!==typeof exports?module.exports=J:k.cash=k.$=J; 46 | })(); 47 | -------------------------------------------------------------------------------- /poster/prompt_diagram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
      Real name is Jane Doe
      Date of Birth is 1994-08-23
      Gender is Female
      Country is US
      Twitter ID is janedoe_rocks
      User information: Age 25, lives in a single apartment in New Hampshire. Works as an accountant in Goldman Sachs. Loves anime, favorites are evangelion and higurashi. Parties a lot. Best friends are Katie and Lara. Hangs out with them basically every night, and sometimes they watch anime together. Huge cat person; owns like 12 cats. The oldest, Jane, has been with her for over 6 years now.
      User status: Currently chilling in the Maldives on vacation. Love the beach!

      Password:
      Real name is Jane Doe...
      {"prompt":"____", "completion":"____"}
      {"prompt":"____", "completion":"____"}
      {"prompt":"____", "completion":"____"}
      {"prompt":"____", "completion":"____"}
      {"prompt":"____", "completion":"____...
      OpenAI
      Finetuning API
      OpenAI...
      Prompt/Completion Pairs from Leaked Dataset
      Prompt/Completion Pairs from Leaked Dataset
      Finetuned
       GPT-3 Model
      Finetuned...
      Example Prompt Input
      Example Prompt Input
      janedoe94
      janedoe94
      lara_1234
      lara_1234
      ilovecats23
      ilovecats23
      Jane1994
      Jane1994
      Password Completions
      Password Completions
      Viewer does not support full SVG 1.1
      -------------------------------------------------------------------------------- /code/analysis/checkPasswords.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 3, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pandas as pd\n", 10 | "import matplotlib.pyplot as plt\n", 11 | "\n", 12 | "topPassMatch = []\n", 13 | "targetedPassMatch = []\n", 14 | "crackedTop =0\n", 15 | "topTries = 0\n", 16 | "crackedTargeted = 0\n", 17 | "targetedTries = 0\n" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 5, 23 | "metadata": { 24 | "tags": [ 25 | "outputPrepend" 26 | ] 27 | }, 28 | "outputs": [ 29 | { 30 | "name": "stdout", 31 | "output_type": "stream", 32 | "text": [ 33 | "Error while deleting file topPassMatch.csv\n", 34 | "Error while deleting file targetedPassMatch.csv\n" 35 | ] 36 | } 37 | ], 38 | "source": [ 39 | "df = pd.read_csv('users.csv')\n", 40 | "dfTop100 = pd.read_csv('passwordsList100.csv')\n", 41 | "dfTargeted = pd.read_csv('passwordsTargeted.csv')\n", 42 | "\n", 43 | "\n", 44 | "iterator = 1\n", 45 | "\n", 46 | "for index, row in df.iterrows():\n", 47 | " iterator +=1\n", 48 | " #print(\"Entering row \", iterator, \" \", row[1])\n", 49 | " topTries, targetedTries = 0, 0\n", 50 | "\n", 51 | " for index2, row2 in dfTop100.iterrows():\n", 52 | " topTries += 1\n", 53 | " if row[1] == row2[0]:\n", 54 | " #print(\"MATCH FOUND \", row[1])\n", 55 | " crackedTop+=1\n", 56 | " if ([row[1], topTries]) not in topPassMatch:\n", 57 | " topPassMatch.append([row[1], topTries]) \n", 58 | " topTries = 0\n", 59 | " continue\n", 60 | "\n", 61 | " for index3, row3 in dfTargeted.iterrows(): # Nededs to be changed, this is for testing only, needs actual 100 passwords\n", 62 | " targetedTries += 1\n", 63 | " if row[1] == row3[0]:\n", 64 | " #print(\"MATCH FOUND \", row[1])\n", 65 | " crackedTargeted+=1\n", 66 | " if ([row[1], targetedTries]) not in targetedPassMatch:\n", 67 | " targetedPassMatch.append([row[1], targetedTries])\n", 68 | " targetedTries = 0\n", 69 | " continue\n", 70 | "\n", 71 | "try:\n", 72 | " os.remove('topPassMatch.csv')\n", 73 | "except:\n", 74 | " print(\"Error while deleting file \", 'topPassMatch.csv')\n", 75 | "\n", 76 | "try:\n", 77 | " os.remove('targetedPassMatch.csv')\n", 78 | "except:\n", 79 | " print(\"Error while deleting file \", 'targetedPassMatch.csv')\n", 80 | "\n", 81 | "dfTargetedPassMatch = pd.DataFrame(targetedPassMatch, columns=['Password', 'Number of Tries'])\n", 82 | "dfTopPassMatch = pd.DataFrame(topPassMatch, columns=['Password', 'Number of Tries'])\n", 83 | "\n", 84 | "dfTargetedPassMatch.to_csv('targetedPassMatch.csv', index=False)\n", 85 | "dfTopPassMatch.to_csv('topPassMatch.csv', index=False)\n" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 6, 91 | "metadata": {}, 92 | "outputs": [ 93 | { 94 | "data": { 95 | "image/png": "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pMtJlSxO6eiyWON8vgBJ65NuYy4bEQs6ujxtIeke4KKIuKy56T7SzSIZSOoraet862Q94Fukb3dm1glJ2iffnluZdCX0h86QoCRtJ+lj+XbfwaRb3n9paT4nqY++7qQaUvNIVcRvpqTWDMysQxxFevQynfSc52sdW5xWW4/0KOC/pC/Ln8/PIZtVU7f7zMzMinwlZWZmNatTNm642mqrxaBBgzq6GGZmncrkyZP/ExF9OrocbdEpk9SgQYO47777OroYZmadiqS2tszS4Xy7z8zMapaTlJmZ1SwnKTMzq1lOUmZmVrOcpMzMrGY5SZmZWc1ykjIzs5rlJGVmZjWrU/6Y18zq0xlLdOz64Z3WTNulr776KjvtlDqgffnll+natSt9+qTGGiZNmkT37t3bFOuJJ57g0EMP5f777+ess87ixBNPXDTuL3/5C6NGjWLhwoUcfvjhjB6d+gt97bXX2H///ZkxYwaDBg3ihhtuYOWVV27ranZqTlJWitacPJo7IVTLkHMa66V8seknTm+nklhns+qqq/Lggw8CcPrpp9OrV68lEktbrbLKKlxwwQWMHz9+ieELFy7kmGOO4bbbbqN///6MGDGCkSNHssEGGzBmzBh22mknRo8ezZgxYxgzZgw//vGPP8RadT6+3Wdm1kq33347m222GRtvvDGHHXYY77yTOpYdNGgQJ510EltssQVbbLEFTz311AfmXX311RkxYgTdunVbYvikSZNYZ511GDx4MN27d+eAAw7g5ptvBuDmm2/m4IMPBuDggw/+QIKrB05SZmat8Pbbb3PIIYdw/fXX88gjj7BgwQJ+9atfLRrfu3dvJk2axLHHHssJJ5zQ6uW++OKLrLXWWove9+/fnxdffBGAV155hb59+wLQt29fZs2aVc7KdCJOUmZmrbBw4ULWXntt1l13XSBd2dx1112Lxh944IGL/t99992tXm5jffqp5GdvnZmTlJlZK/Ts2bPZ8cXE0pYk079/f55//vlF71944QX69esHwBprrMHMmanz2pkzZ7L66qu3pcgfCU5SZmat8PbbbzNjxoxFz5uuuuoqtttuu0Xjr7/++kX/P/nJT7Z6uSNGjGDatGk888wzvPvuu4wbN46RI0cCMHLkSK644goArrjiCvbaa6+yVqfTcO0+M+s0OqKGaIMePXpw2WWXsd9++7FgwQJGjBjB0UcfvWj8O++8w5Zbbsn777/Pdddd94H5X375ZYYPH87cuXPp0qUL559/Po899hi9e/fmF7/4BbvuuisLFy7ksMMOY8MNNwRg9OjRfOELX2Ds2LEMGDCAG2+8sd3Wt1aosfuhtW748OHhTg9ri6ugWz1r6Ih1tdVW6+iiNEvS5IgY3tHlaAvf7jMzs5rl231mZh/SjBkzOroIH1m+kjIzs5rlJGVmZjXLScrMzGqWk5SZmdUsV5wws06jpZ8UtFVzP0Eou6uO5syZM4drr72Wr3/9622ar4zW2Wudk5SZWSOWtquOBQsWsMwybTu1zpkzhwsvvLDNSaoe+HafmVkr/eY3v2HEiBFsuummfO5zn+PNN98E4JBDDuGb3/wmO+ywAyeddBLTp09nq622YsSIEZx66qn06tVr0TLOPvtsRowYwSabbMJpp50GpJYlpk+fztChQ/n2t7/d5HQAZ511Fuuttx4777wzU6dObce17xi+kjIza6V9992XI444AoBTTjmFsWPHctxxxwHw5JNP8re//Y2uXbuy5557MmrUKA488EAuuuiiRfNPmDCBadOmMWnSJCKCkSNHctdddzFmzBimTJmy6Mqtqel69uzJuHHjeOCBB1iwYAHDhg1j8803b/ft0J6cpMzMWmnKlCmccsopzJkzh/nz57PrrrsuGrfffvvRtWtXAO6+++5FHRR+8YtfXHSbcMKECUyYMIHNNtsMgPnz5zNt2jQGDBiwRJympps3bx777LMPyy+/PMCihmg/ypykzMxa6ZBDDmH8+PFsuummXH755dx5552LxrXUlQekvqNOPvlkjjrqqCWGV7ZY0dR0559/ft31NVUTz6QkfUPSo5KmSLpOUo+OLpOZWaV58+bRt29f3nvvPa655pomp9tqq6347W9/C8C4ceMWDd9111259NJLmT9/PpB65Z01axYrrLAC8+bNa3G6bbfdlt///ve89dZbzJs3jz/84Q/VWM2a0uFXUpLWBI4HNoiItyTdABwAXN6hBTOzmtPRrdafeeaZbLnllgwcOJCNN954icRSdP7553PQQQdx7rnn8pnPfIYVV1wRgF122YXHH398UX9TvXr14uqrr2bIkCFsvfXWbLTRRuy+++6cffbZjU43bNgw9t9/f4YOHcrAgQPZZptt2mfFO1CHd9WRk9S/gU2BucB44IKImNDUPO6q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", 96 | "text/plain": [ 97 | "
      " 98 | ] 99 | }, 100 | "metadata": { 101 | "needs_background": "light" 102 | }, 103 | "output_type": "display_data" 104 | } 105 | ], 106 | "source": [ 107 | "targPlotX = []\n", 108 | "targPlotY = []\n", 109 | "topPlotX = []\n", 110 | "topPlotY = []\n", 111 | "\n", 112 | "import numpy as np\n", 113 | "\n", 114 | "for tries in range(11):\n", 115 | " count = 0\n", 116 | " for passwd in targetedPassMatch:\n", 117 | " if passwd[1] in range(tries*10, tries*10+10):\n", 118 | " count += 1 # increase amount of passwd guessed for that specific number of guesses\n", 119 | " \n", 120 | " #print(\"Targ: \", tries*10, \" \", count)\n", 121 | " targPlotX.append(tries*10)\n", 122 | " targPlotY.append(count)\n", 123 | " count = 0\n", 124 | "\n", 125 | " for passwd in topPassMatch:\n", 126 | " if passwd[1] in range(tries*10, tries*10+10):\n", 127 | " count += 1 # increase amount of passwd guessed for that specific number of guesses\n", 128 | "\n", 129 | " #print(\"Top: \", tries*10, \" \", count)\n", 130 | " topPlotX.append(tries*10)\n", 131 | " topPlotY.append(count)\n", 132 | "\n", 133 | "width = 3\n", 134 | "plt.xlabel(\"Number of Guesses\")\n", 135 | "plt.ylabel(\"Number of Cracked Passwords\")\n", 136 | "plt.xticks(np.arange(0,101,10))\n", 137 | "plt.yticks(np.arange(0,11,2))\n", 138 | "plt.title(\"Comparision of Targeted and Top-100 bruteforce password guessing\")\n", 139 | "plt.bar(np.arange(0,101,10)-1, topPlotY, width=width, color=\"maroon\", label=\"Top 100\")\n", 140 | "plt.bar(np.arange(0,101,10)+2, targPlotY, width=width, color=\"forestgreen\", label=\"Targeted\")\n", 141 | "plt.legend(frameon=False)\n", 142 | "plt.show()\n", 143 | "\n", 144 | "#print(targPlot, '\\n',topPlot)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [] 153 | } 154 | ], 155 | "metadata": { 156 | "kernelspec": { 157 | "display_name": "Python 3 (ipykernel)", 158 | "name": "python3" 159 | }, 160 | "language_info": { 161 | "codemirror_mode": { 162 | "name": "ipython", 163 | "version": 3 164 | }, 165 | "file_extension": ".py", 166 | "mimetype": "text/x-python", 167 | "name": "python", 168 | "nbconvert_exporter": "python", 169 | "pygments_lexer": "ipython3", 170 | "version": "3.9.7" 171 | }, 172 | "orig_nbformat": 2 173 | }, 174 | "nbformat": 4, 175 | "nbformat_minor": 2 176 | } 177 | -------------------------------------------------------------------------------- /poster/similarity_graph.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.00.20.40.60.81.0Levenshtein Distance Ratio01234DensitySimilarity Between Guessed Passwords and Actual PasswordsGPT-3 ModelTop 100 Passwords 797 | -------------------------------------------------------------------------------- /code/analysis.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 115, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pandas as pd\n", 10 | "import numpy as np\n", 11 | "import seaborn as sns\n", 12 | "import matplotlib.pyplot as plt" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "data = pd.read_pickle('output/analysis_Apr_26_2022_03-32-37_top100list.pkl')\n", 22 | "data.head()" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 129, 28 | "metadata": {}, 29 | "outputs": [ 30 | { 31 | "data": { 32 | "text/plain": [ 33 | "" 34 | ] 35 | }, 36 | "execution_count": 129, 37 | "metadata": {}, 38 | "output_type": "execute_result" 39 | }, 40 | { 41 | "data": { 42 | "image/png": "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", 43 | "text/plain": [ 44 | "
      " 45 | ] 46 | }, 47 | "metadata": { 48 | "needs_background": "light" 49 | }, 50 | "output_type": "display_data" 51 | } 52 | ], 53 | "source": [ 54 | "sns.histplot(data['levenshtein_similarity'], color='red')\n", 55 | "sns.histplot(data['difflib_similarity'])" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 166, 61 | "metadata": {}, 62 | "outputs": [ 63 | { 64 | "name": "stderr", 65 | "output_type": "stream", 66 | "text": [ 67 | "C:\\Python310\\lib\\site-packages\\seaborn\\distributions.py:2619: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).\n", 68 | " warnings.warn(msg, FutureWarning)\n", 69 | "C:\\Python310\\lib\\site-packages\\seaborn\\distributions.py:2619: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).\n", 70 | " warnings.warn(msg, FutureWarning)\n" 71 | ] 72 | }, 73 | { 74 | "data": { 75 | "text/plain": [ 76 | "Text(0.5, 0, 'Levenshtein Distance Ratio')" 77 | ] 78 | }, 79 | "execution_count": 166, 80 | "metadata": {}, 81 | "output_type": "execute_result" 82 | }, 83 | { 84 | "data": { 85 | "image/png": "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", 86 | "text/plain": [ 87 | "
      " 88 | ] 89 | }, 90 | "metadata": { 91 | "needs_background": "light" 92 | }, 93 | "output_type": "display_data" 94 | } 95 | ], 96 | "source": [ 97 | "sns.distplot(data['levenshtein_similarity'], label='GPT-3 Model')\n", 98 | "sns.distplot(data['top100_levenshtein_similarity'], label='Top 100 Passwords')\n", 99 | "plt.title('Similarity Between Guessed Passwords and Actual Passwords')\n", 100 | "plt.legend(frameon=False)\n", 101 | "plt.xlabel('Levenshtein Distance Ratio')" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 167, 107 | "metadata": {}, 108 | "outputs": [ 109 | { 110 | "data": { 111 | "image/png": "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3qHbokWL6s+ffPIJZlbjcOuvvz7bbrtt9SMIR48ezU9+8vULv+fOncuAAQPo0aMHAwcO5J133gFgzpw57Lzzzmy//fZccMEFq4zz8ssvp1+/fvTo0YOLLrqopHilMpTwRCQV06ZNo3fv3iUNu3jxYl566aWyjr6uu+46tthiC84991yuueaagsMNGTKEUaNGMW/ePBo1akT79u2r+51++ukcffTRTJ48mcMPP5wzzjgDgDPPPJNTTz2VKVOmsOmmm1YPP3bsWGbOnMmECROoqqpi0qRJjB8/vuSYpX4p4YnIt8Jpp51Gz5496devX3W35557jl69erHnnnsybNiwshLeaaedxltvvcWIESOqz9HVZO+99+aJJ55g1KhR/PSnP12l34svvshhhx0GwJFHHsnzzz8PwAsvvMChhx5a3T1n7NixjB07ll69etG7d29mzJjBzJkzS45Z6pcuWhGRVHTv3p2//e1v1d+vu+46PvzwQ/r27VvdrX///jz66KO1jutXv/pV9bm4qqqqVfoNGTKEU08t/DLspk2b0qdPH6644gqmT5/OI488UlL8NTWTujvnn38+J598cknjkMrSEZ6IpGLAgAGsWLGC66+/vrrbp59+ulrjuuSSS6ovZgFWOap67LHH2GqrrYqW/8UvfsGIESNo06bNKt2///3vM2rUKADuvvtu+vfvD8Auu+yySvecvfbai7/+9a/VV2O+9957LFy4cLWmSeqejvBEBCjtNoK6ZGY89NBDDB06lMsuu4x27drRvHlzRowYscbjvvbaa3nyySdp0qQJrVu35o477ig6fPfu3WtsLv3zn//Msccey+WXX067du247bbbALj66qs57LDDGDFiBIMHD64efs899+T1119n5513BsKtCCNHjmTjjTde42mSNWfunnYM9aZv376+ui+ATd6OUOkdgYhImsxskrv3rX3ItYuaNEVEJBOU8EREJBOU8EREJBOU8EREJBOU8EREJBOU8EREJBN0H56IBMNb1vH4Pi7ae/HixQwcOBCADz74gEaNGtGuXTsAJkyYQNOmTcuqbsaMGRx77LG8+uqrXHLJJZx99tnV/f75z39y5plnsnLlSk444QSGDRsGhIdADxkyhMWLF9OnTx/uuuuub9R7++23c84559ChQwc+//xzhg4dyoknnlhWbJV0zDHHsO+++3LwwQenHcq3jo7wRCQVG220UfXTUU455RSGDh1a/b3cZAfQpk0brrnmmlUSHcDKlSs57bTTePzxx5k+fTr33nsv06dPB+C8885j6NChzJo1i9atW3PrrbfWOO6f/vSnVFVVMW7cOH75y1+yYMGC8ie4Hnz55Zdph7BWUcITkW+Np556il69erH99ttz3HHH8dlnnwHQpUsXzj33XLbffnt23HHHGl8TtPHGG9OvXz+aNGmySvcJEyaw5ZZbsvnmm9O0aVOGDBnCww8/jLvz9NNPVx8JHX300Tz00ENF49t4443ZYostePvttzn11FPp27cv3bt3X+U1QMOGDaNbt2706NGjOvnef//9bLfddvTs2ZNdd90VgEGDBjF58mQAevXqxcUXXwzAhRdeyM0334y7c84557Dddtux/fbbM3r0aADGjRtH//792X///enWrRvuzs9+9jO22WYbfvjDH67yKLOaYskyNWmKyLfCihUrOOaYY3jqqafYeuutOeqoo7j++us566yzAGjZsiVTpkzhzjvv5KyzzirpodIQnmfZsWPH6u+bbbYZL7/8MosXL6ZVq1Y0bty4uvt7771XdFyzZ89m9uzZbLnlllxyySW0adOGlStXMnDgQCZPnkyHDh148MEHmTFjBmbGkiVLALj44ov517/+RYcOHaq79e/fn+eee47OnTvTuHFjXnjhBSC8IeKGG25gzJgxVFVV8dprr/Hhhx/Sr1+/6mT56quvMnXqVLp27cqYMWN44403mD59OgsWLKBbt24cd9xxLF68uMZYskxHeCLyrbBy5Uq6du3K1ltvDYQjruS75HKv4zn00EN58cUXKxrb6NGj2WGHHTj00EO58cYbadOmDffddx+9e/emV69eTJs2jenTp9OyZUuaNWvG8ccfz5gxY1h//fWB8LDpY445hptvvpmVK1cCIeGNHz+eF154gUGDBrF8+XI+/fRT5syZwzbbbMPzzz/PoYceSqNGjdhkk03YbbfdeOWVVwDYcccd6dq1KwDjx4+vHq59+/YMGDAAoGAsWaaEJyJrheTreAq9wbwmHTp0YN68edXf3333XTp06MBGG23EkiVLqs+D5brXJHcO7+WXX+bAAw9kzpw5/PGPf+Spp55i8uTJDBo0iBUrVtC4cWMmTJjAwQcfzKOPPsree+8NwA033MDvfvc75s2bR58+fVi8eDH9+vVj4sSJPPfcc+y666706tWLm2++mT59+tQ6Tc2bN691mEKxZNlalfDMbKiZTTOzqWZ2r5k1SzsmEakbjRo1Yu7cudXn5+666y5222236v65c1ijR4+ufhtBKfr168fMmTOZM2cOn3/+OaNGjWL//ffHzNhjjz144IEHALjjjjtWefNBMUuXLqV58+a0bNmSBQsW8PjjjwOwfPlyPv74Y/bZZx/+9Kc/8dprrwHw1ltv8b3vfY+LL76Ydu3aMW/ePJo2bUrHjh25//772Xnnnenfvz9//OMfq5st+/fvz+jRo1m5ciWLFi1i/Pjx7Ljjjt+IZdddd60ebv78+TzzzDNFY8myteYcnpl1AM4Aurn7/8zsPmAIcHuqgYk0FLXcRlDfmjVrxm233cYhhxzCl19+Sb9+/TjllFOq+3/00Uf06NGDddddl3vvvfcb5T/44AP69u3L0qVLWWeddbjqqquYPn06LVq04Nprr2WvvfZi5cqVHHfccdWvAhoxYgRDhgzhggsuoFevXhx//PElxdqzZ0969erFd7/7XTp27Mguu+wCwLJlyxg8eDArVqzA3bnyyisBOOecc5g5cybuzsCBA+nZsycQktpTTz3FeuutR//+/Xn33Xer37l34IEH8uKLL9KzZ0/MjMsuu4zvfOc7zJgxY5VYDjzwQJ5++mm6detGp06dqn8MFIoly9aa1wPFhPcS0BNYCjwEXOPuYwuV0euBRBqGLl26MHHiRNq2bZt2KJmg1wOlzN3fA/4IvAPMBz6uKdmZ2UlmNtHMJi5atKjSYYqIyLfUWpPwzKw1MBjoCrQHmpvZEfnDuftN7t7X3fvmntogImu3uXPn6uhO1lgqCc/MzjSzFhbcamavmtmetRT7ITDH3Re5+xfAGOD79R+tiIg0BGkd4R3n7kuBPYHWwJHApbWUeQfYyczWt3BN8kDg9foNU0REGoq0El7uJpp9gLvcfVqiW43c/WXgAeBVYAoh9pvqM0gREWk40rotYZKZjSWcjzvfzDYEvqqtkLtfBFxU23AiIiL50kp4xwM7ALPd/VMz2wg4NqVYREQkAyqa8Mysd16nzct5RJCIiMjqqvQR3hXxfzOgDzCZcO6uBzARKP15QSIiImWo6EUr7r6Hu+9BuHG8T7xfrg/QCyj+Xg4REZE1kNZVmtu4+5TcF3efCmybUiwiIpIBaV20MsXMbgFGxu+HE5o3RURE6kVaCe8Y4FTgzPh9PHB9SrGIiEgGVDzhmVkj4PF4Lu9Pla5fRESyqeLn8Nx9JfCVmbWsdN0iIpJdaTVpLiecx3sC+CTX0d3PSCkeERFp4NJKeGPin4iISEWkkvDc/Q4zawpsHTu9EV/5IyIiUi9SSXhmtjtwBzCX8KSVjmZ2tLuPTyMeERFp+NJq0rwC2NPd3wAws62BewmPGxMREalzaT1ppUku2QG4+5tAk5RiERGRDEjrCG9iDU9amZhSLCIikgFpJbxTgdOA3G0IzwF/SSkWERHJgLQS3g+A6939ypTqFxGRjEnrHN5RwGtm9pKZXW5m+5lZ65RiERGRDEjrPryjAcysPXAwcB3QPq14RESk4UvrPrwjgP7A9sCHwLWE83giIiL1Iq0jqquAt4AbgGfcfW5KcYiISEakcg7P3dsCxwHNgEvMbIKZ3ZVGLCIikg2pJDwzawF0AjoDXYCWwFdpxCIiItmQVpPm84m/a9393ZTiEBGRjEjrKs0euc9mto6ZtXD3pWnEIiIi2ZBWk+Y9ZtbCzJoDU4HpZnZOGrGIiEg2pHXjebd4RHcA8DjQFTgypVhERCQDUntbgpk1ISS8R+LLXz2lWEREJAPSSng3El7+2hwYb2adAZ3DExGRepPWRSvXANckOr1tZnukEYuIiGRDWhetnBkvWjEzu9XMXgUGpBGLiIhkQ1pNmsfFi1b2BFoTLli5NKVYREQkA9JKeBb/7wPc5e7TEt1ERETqXFoJb5KZjSUkvH+Z2Ybo0WIiIlKP0nq02PHADsBsd//UzDYCjk0pFhERyYC0rtL8yszmAFubWbM0YhARkWxJ6wWwJwBnApsBVcBOwIvUcqWmmbUCbgG2I9yofpy7v1ifsYqISMOQ1jm8M4F+wNvuvgfQC1hSQrmrgX+6+3eBnsDr9RahiIg0KGmdw1vh7ivMDDNb191nmNk2xQqYWUtgV+AYAHf/HPi8/kMVEZGGIK0jvHdj8+RDwBNm9jDwdi1lugKLgNvM7D9mdkt828IqzOwkM5toZhMXLVpU13GLiMhaKq2Ed6K7L3H34cCvgVsJD5IupjHQG7je3XsBnwDD8gdy95vcva+7923Xrl3dRi0iImutiiY8M9vPzBYBk83sXTP7vrs/6+6PxCbKYt4F3nX3l+P3BwgJUEREpFaVPsK7BOjv7u2BHwN/KLWgu38AzEuc6xsITK/7EEVEpCGq9EUrX7r7DAB3fzk+YaUcpwN3m1lTYDa6WV1EREpU6YS3sZn9vNB3d7+yWGF3rwL61lNsIiLSgFU64d0MbFjku4iISL2oaMJz999Usj4REZGctG5LEBERqSglPBERyQQlPBERyYSKnsPLu0LzG2q7SlNERGR1VfoqzdwVmdsQ3pbwSPy+HzChwrGIiEiGpHKVppmNB3q7+7L4fTjwWCVjERGRbEnrHN4mrPpqn89jNxERkXqR1vvw7gQmmNmD8fsBwB0pxSIiIhmQSsJz90vM7HGgf+x0rLv/J41YREQkG9K8LWF9YKm7X014IWzXFGMREZEGLpWEZ2YXAecB58dOTYCRacQiIiLZkNYR3oHA/oS3luPu76OHSIuISD1KK+F97u4OOICZNU8pDhERyYi0Et59ZnYj0MrMTgSeBG5JKRYREcmAtG5LuAL4IbCU8NSVC4HxKcUiIiIZkFbCu9XdjwOeADCzDYB/AANTikdERBq4tJo03zOzvwCYWWtgLLpKU0RE6lEqCc/dfw0sN7MbCMnuCne/LY1YREQkGyr9eqCDEl9fBn5NeEuCm9lB7j6mkvGIiEh2VPoc3n553/9DuOl8P8ItCkp4IiJSLyr9eqBjK1mfiIhITlqPFrvDzFolvrc2s7+mEYuIiGRDWldp9nD3Jbkv7v4R0CulWEREJAPSSnjrxNsRADCzNqR3T6CIiGRAmk9aedHM7gcMOBi4JKVYREQkA9J6AeydZjYJ2CN2Osjdp6cRi4iIZENqzYjuPs3MFgHNAMysk7u/k1Y8IiLSsKV1leb+ZjYTmAM8C8wFHk8jFhERyYa0Llr5LbAT8Ka7dyU8NPqllGIREZEMSCvhfeHuiwlXa67j7s8AfVOKRUREMiCtc3hL4iuBxgN3m9lC4JOUYhERkQxI6whvMPApMBT4J/AW33zOpoiISJ2p+BGemTUCHnX3PYCvgDsqHYOIiGRPxY/w3H0l8JWZtax03SIikl1pncNbDkwxsydInLtz9zNSikdERBq4tBLeGFbz3XexSXQi8J6771unUYmISINV6TeetwPaufsded27AwtLHM2ZwOtAizoOT0REGrBKn8P7M9C2hu5tgKtrK2xmmwGDgFvqOC4REWngKt2kuaW7j8/v6O7Pmdn1JZS/CjgX2LDQAGZ2EnASQKdOnVYzzFV1GfZY9ee5lw6qk3GKiEhlVfoIr2CiApoUK2hm+wIL3X1SseHc/SZ37+vufdu1a7c6MYqISANU6YQ3y8z2ye9oZj8CZtdSdhdgfzObC4wCBpjZyLoPUUREGqJKN2meBTxmZj8BckdqfYGdgaJXXLr7+cD5AGa2O3C2ux9RX4GKiEjDUtEjPHefCWxPeCVQl/j3LNDD3d+sZCwiIpItFb8Pz90/A25bw3GMA8bVRTwiIpINaT08WkREpKKU8EREJBMqmvDM7Kn4f0Ql6xUREan0ObxNzez7hNsLRgGW7Onur1Y4HhERyYhKJ7wLgV8DmwFX5vVzYECF4xERkYyoaMJz9weAB8zs1+7+20rWLSIi2ZbK64Hc/bdmtj+wa+w0zt0fTSMWERHJhlSu0jSzPxBe8zM9/p1pZr9PIxYREcmGtF4AOwjYwd2/AjCzO4D/AL9MKR4REWng0rwPr1Xic8u0ghARkWxI6wjvD8B/zOwZwq0JuwLDUopFREQyIK2LVu41s3FAv9jpPHf/II1YREQkG9I6wsPd5wOPpFW/iIhki56lKSIimaCEJyIimVDxhGdmjcxsRqXrFRGRbKt4wnP3lcAbZtap0nWLiEh2pXXRSmtgmplNAD7JdXT3/VOK5xvmNjus+nOXFfd8/XnYYzUPf+mgeo9JRERWX1oJ79cp1SsiIhmV1n14z5pZZ2Ard3/SzNYHGqURi4iIZENaD48+EXgAuDF26gA8lEYsIiKSDWndlnAasAuwFMDdZwIbpxSLiIhkQFoJ7zN3/zz3xcwaE954LiIiUi/SSnjPmtkvgfXM7P+A+4G/pxSLiIhkQFoJbxiwCJgCnAz8A7ggpVhERCQD0rpK86v40teXCU2Zb7i7mjRFRKTepJLwzGwQcAPwFuF9eF3N7GR3fzyNeEREpOFL68bzK4A93H0WgJltATwGKOGJiEi9SOsc3rJcsotmA8tSikVERDKgokd4ZnZQ/DjRzP4B3Ec4h3cI8EolYxERkWypdJPmfonPC4Dd4udFwHoVjkVERDKkognP3Y+tZH0iIiI5aV2l2RU4HeiSjOHb9HogERFpWNK6SvMh4FbC01W+SikGERHJkLQS3gp3vyalukVEJIPSSnhXm9lFwFjgs1xHd381pXhERKSBSyvhbQ8cCQzg6yZNj99FRETqXFoJ7xBg8+QrgmpjZh2BO4FNCMnxJne/up7iExGRBiatJ61MBVqVWeZL4Bfu3g3YCTjNzLrVdWAiItIwpXWE1wqYYWavsOo5vIK3Jbj7fGB+/LzMzF4HOgDT6zdUERFpCNJKeBetSWEz6wL0IrxeKL/fScBJAJ06dVqTasozvGX1xy4r7ql18LmXDqrPaEREJE9a78N7dnXLmtkGwN+As9x9aQ3jvgm4CaBv3756x56IiADpPWllGeHCE4CmQBPgE3dvUUu5JoRkd7e7j6nfKEVEpCFJ6whvw9xnMzNgMOFClILicLcCr7v7lfUboYiINDRpXaVZzYOHgL1qGXQX4r17ZlYV//ap9wBFRKRBSKtJ86DE13WAvsCKYmXc/XnA6jMuERFpuNK6SjP5XrwvgbmEZk0REZF6kdY5PL0XT0REKqqiCc/MLizS2939txULRkREMqXSR3if1NCtOXA8sBGghCciIvWiognP3a/IfTazDYEzgWOBUcAVhcqJiIisqYqfwzOzNsDPgcOBO4De7v5RpeMQEZFsqfQ5vMuBgwiP/tre3ZdXsn4REcmuSt94/gugPXAB8L6ZLY1/y8zsG8/FFBERqSuVPoeX+pNdREQkm5SAREQkE5TwREQkE5TwREQkE5TwREQkE5TwREQkE5TwREQkE5TwREQkE5TwREQkE9J6AayUqMuwx6o/z710UJ2Pp67GX2eGt8z7/nF6ddcUQ3KYcmNbk7KyZjTvBR3hiYhIRijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJijhiYhIJqxVCc/M9jazN8xslpkNSzseERFZe6w1Cc/MGgHXAT8CugGHmlm3dKMSEZG1xVqT8IAdgVnuPtvdPwdGAYNTjklERNYS5u5px1ASMzsY2NvdT4jfjwS+5+4/yxvuJOCk+HUb4I3VqK4t8OFqhpq1smnWrWleO8qmWbemefV0dvd2aziOb53GaQdQ19z9JuCmNRmHmU10974q++2uW9O8dpRNs25NsyStTU2a7wEdE983i91ERERqtTYlvFeArcysq5k1BYYAj6Qck4iIrCXWmiZNd//SzH4G/AtoBPzV3afVU3Vr0iSatbJp1q1pXjvKplm3plmqrTUXrYiIiKyJtalJU0REZLUp4YmISCYo4SWsyaPLzGyumU0xsyozm1jC8H81s4VmNjXRrY2ZPWFmM+P/1mWUHW5m78X6q8xsnwJlO5rZM2Y23cymmdmZpdZdpGytdZtZMzObYGavxbK/id27mtnLcZ6Pjhck1RR3ofK3m9mcRN07FJnnjczsP2b2aDl1FyhbUr01rRdlLOeaypa0nOOwrczsATObYWavm9nOZdRdU9lSlvM2if5VZrbUzM4qcf0qVLbUdXtoXDemmtm9cZ0pZxnXVL7U5XxmLDfNzM6K3Uqd1zWVLTjNVsa+w4Jr4vRPNrPehaY/E9xdf+E8ZiPgLWBzoCnwGtCtjPJzgbZlDL8r0BuYmuh2GTAsfh4GjCij7HDg7BLq3RToHT9vCLxJeFRbrXUXKVtr3YABG8TPTYCXgZ2A+4AhsfsNwKlllr8dOLjEef5z4B7g0fi9pLoLlC2p3prWizKWc01lS1rOcdg7gBPi56ZAqzLqrqlsyXUntqkPgM6l1lugbCnrVwdgDrBeYtkeU8b6Vah8rcsZ2A6YCqxPuBDwSWDLUqa5SNmC00wZ+w5gH+BxwvazE/ByqcuvIf7pCO9rFX10mbuPB/6b13kwYUdD/H9AGWVLrXe+u78aPy8DXids7LXWXaRsKfW6uy+PX5vEPwcGAA8Uq7eW8iUxs82AQcAt8buVWnd+2TpQ0nJeE2bWkrBjvBXA3T939yWl1F2kbLkGAm+5+9ul1FukbKkaA+uZWWNCAplPicu4QPn3S6x3W0Ii+dTdvwSeBQ6itGkuVLagMvcdg4E74/bzEtDKzDYtcboaHCW8r3UA5iW+v0uJO/PIgbFmNsnC481WxybuPj9+/gDYpMzyP4vNFn8t1HySZGZdgF6Eo6Wy6s4rW1LdFpoFq4CFwBOEI+olcUOHWuZ5fnl3z9V9Saz7T2a2boHiVwHnAl/F7xuVUXd+2ZxS6q1pvSh1Xhdap0pZzl2BRcBtFppibzGz5iXWXahsqXXnDAHuLXOaaypba73u/h7wR+AdQqL7GJhEicu4pvLuPjb2rm05TwX6m9lGZrY+4aiqY4nTXKhsrdOcp1Bda7pfa1CU8OrOD9y9N+FtDqeZ2a5rMjIP7RHl3DNyPbAFsANhg72i2MBmtgHwN+Asd19aTt01lC2pbndf6e47EJ6SsyPw3donq3B5M9sOOD+Opx/QBjivhnj3BRa6+6Ry6qulbK31RkXXi1rmdU1lS13OjQnNXte7ey/gE0JTVyl1Fypb8joWz5XtD9yf36+E9Su/bK31xoQwmJCs2wPNgb0L1VFKeTM7ghKWs7u/DowAxgL/BKqAlXnD1DjNRcqWtT2XUpco4SWt0aPL4i9E3H0h8CBhh16uBbnmhvh/YRn1L4gJ4Svg5mL1m1kTQsK6293HlFN3TWXLqTsOvwR4BtiZ0MSSewBCSfM8UX7v2Mzq7v4ZcFuBuncB9jezuYSm6gHA1SXW/Y2yZjayxHoLrRclzeuaypYxr98F3k0cBT9ASGKl1F1j2TKX84+AV919Qfxezrq9StkS6/0hMMfdF7n7F8AYwrIrdf2qqfz3y1jOt7p7H3ffFfiIcH671OX8jbLlblNF6tIjGROU8L622o8uM7PmZrZh7jOwJ6GpolyPAEfHz0cDD5daMK9d/sBC9cdzV7cCr7v7leXUXahsKXWbWTszaxU/rwf8H+Ec4DPAwcXqLVJ+RmIjN8J5i2/U7e7nu/tm7t6FsFyfdvfDS6m7QNkjSqm3yHpRyryusWypy9ndPwDmmdk2sdNAYHopdRcqW2rd0aGs2iRZzrq9StkS630H2MnM1o/LJDe9Ja1fBcq/Xspyjv03jv87Ec7B3UOJ01xT2TLnNUXqegQ4yoKdCE2182saQSb4t+DKmW/LH6H9/E3CuaVflVFuc8JVna8B00opS9ig5wNfEH5RH084r/QUMJNwtVabMsreBUwBJhNW8k0LlP0BobljMqH5pCpOd611Fylba91AD+A/cZipwIWJeTcBmEVowlq3QNyFyj8d654KjCReyVlkvu/O11dallR3gbK11ltovShxXhcqW9JyjsPuAEyMwz4EtC5jHaupbKnrWHNgMdAy0a3UemsqW2q9vwFmxGVyF7BuOcu4QPmS1i/gOUKCfQ0YWOY011S24DRTxr6DcHXmdYR92hSgb6n7tYb4p0eLiYhIJqhJU0REMkEJT0REMkEJT0REMkEJT0REMkEJT0REMkEJT9ZKZuZmdkXi+9lmNryOxn27mR1c+5BrXM8hFt5E8EwN/bYys0fN7K34aLFn1vTpPSJZp4Qna6vPgIPMrG3agSQlnupRiuOBE919j7xxNAMeA25y9y3cvQ9wOuGeMhFZTUp4srb6ErgJGJrfI/8IzcyWx/+7m9mzZvawmc02s0vN7HAL79mbYmZbJEbzQzObaGZvxudp5h5efbmZvWLhob4nJ8b7nJk9QriBOD+eQ+P4p5rZiNjtQsKN/Lea2eV5RQ4HXnT36if9uPtUd789lh1uZmcnxj/VwsO8MbMj4vRUmdmNMeZGcZ5MjXEMjcOeYeHdhpPNbFTs1tzCw4onWHhw9ODYvXtivJPNbKtSFpLIt0k5v0ZFvm2uAyab2WVllOlJeCXLf4HZwC3uvqOFl9meDpwVh+tCeH7hFsAzZrYlcBTh0Uz9LDw1/wUzyz1RvzewnbvPSVZmZu0JDwfuQ3hO4lgzO8DdLzazAYR3nuW/MLg78GoZ05Sra1vgp8Au7v6Fmf2FkDynAR3cfbs4XKtYZBjQ1d0/S3T7FeHxacfFbhPM7EngFOBqd7/bwqP3GpUbn0jadIQnay0Pb2q4EzijjGKveHgg8GeExy3lEtYUQpLLuc/dv3L3mYTE+F3C8yyPsvCKopcJj3PKHelMyE92UT9gnIeHEn8J3E1411zJzOzBeHQ2ppZBBxIS6ysxxoGEZtDZwOZm9mcz2xvIvR1jMnC3hbcC5F6hsycwLJYfBzQDOgEvAr80s/OAzu7+v3KmQeTbQAlP1nZXEc6FNU90+5K4bpvZOoQ3dud8lvj8VeL7V6za4pH/zD0nPJfwdHffIf519a/fmfbJmkxEnmmEI8ZQsfuBhLdvt4mdqqcvahb/G3BHIr5t3H24u39EOLIdRzhSy73IdhDhKLk3IUk2juP4cWIcndz9dXe/h/DKnv8B/4hHpyJrFSU8Wau5+3+B+whJL2cu4UgHwk66yWqM+hAzWyee19sceAP4F3CqhVckYWZb29cvRi1kArCbmbU1s0aENwE8W0uZe4BdzGz/RLf1E5/nEhOimfUmvMMNwsODD048fb+NmXWOF/as4+5/Ay4AescfAh3d/RnCO95aAhvEaTzdzCyOo1f8vzkw292vITyJv0ct0yDyraNzeNIQXAH8LPH9ZuBhM3uN8FLN1Tn6eoeQrFoAp7j7CjO7hdDs+WpMCIsIr4wpyN3nm9kwwmtqDHjM3Yu+9snd/xcvlLnSzK4CFgDLgN/FQf5GaFqdRmhafTOWm25mFxDOE65DeJr+aYSjsttiNwgvNW0EjDSzljGua9x9iZn9lnDUPDkOPwfYF/gJcKSZfUF4o/bvi02DyLeR3pYgIiKZoCZNERHJBCU8ERHJBCU8ERHJBCU8ERHJBCU8ERHJBCU8ERHJBCU8ERHJhP8PbEbw5vmgFQYAAAAASUVORK5CYII=", 112 | "text/plain": [ 113 | "
      " 114 | ] 115 | }, 116 | "metadata": { 117 | "needs_background": "light" 118 | }, 119 | "output_type": "display_data" 120 | } 121 | ], 122 | "source": [ 123 | "# num cracked passwords vs num guesses\n", 124 | "modelY = []\n", 125 | "top100Y = []\n", 126 | "\n", 127 | "n = 100\n", 128 | "for i in range(1,n+1):\n", 129 | " modelY.append(len(data[data['guesses_model10k'] == i]))\n", 130 | " top100Y.append(len(data[data['guesses_top100'] == i]))\n", 131 | "\n", 132 | "plt.title(\"Comparison of GPT-3 Model and Top-100 Bruteforce Password Guessing\")\n", 133 | "plt.xlabel(\"Number of Guesses\")\n", 134 | "plt.ylabel(\"Number of Cracked Passwords\")\n", 135 | "width = 1\n", 136 | "plt.xticks(np.arange(0,n+1,5))\n", 137 | "# plt.yticks(np.arange(0,50,2))\n", 138 | "plt.bar(np.arange(1,n+1,1), modelY, width=width, label=\"GPT-3 Model\")\n", 139 | "plt.bar(np.arange(1,n+1,1), top100Y, width=width, label=\"Top 100 Passwords\")\n", 140 | "plt.legend(frameon=False)\n", 141 | "plt.show()" 142 | ] 143 | } 144 | ], 145 | "metadata": { 146 | "interpreter": { 147 | "hash": "2be5faf79681da6f2a61fdfdd5405d65d042280f7fba6178067603e3a2925119" 148 | }, 149 | "kernelspec": { 150 | "display_name": "Python 3.10.2 64-bit", 151 | "language": "python", 152 | "name": "python3" 153 | }, 154 | "language_info": { 155 | "codemirror_mode": { 156 | "name": "ipython", 157 | "version": 3 158 | }, 159 | "file_extension": ".py", 160 | "mimetype": "text/x-python", 161 | "name": "python", 162 | "nbconvert_exporter": "python", 163 | "pygments_lexer": "ipython3", 164 | "version": "3.10.2" 165 | }, 166 | "orig_nbformat": 4 167 | }, 168 | "nbformat": 4, 169 | "nbformat_minor": 2 170 | } 171 | --------------------------------------------------------------------------------