{"id":37773736,"url":"https://github.com/scottvr/vanissh","last_synced_at":"2026-01-16T14:56:45.098Z","repository":{"id":279098520,"uuid":"937706958","full_name":"scottvr/vanissh","owner":"scottvr","description":"VaniSSH - Vanity SSH public key generator","archived":false,"fork":false,"pushed_at":"2025-07-28T09:56:42.000Z","size":8618,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-28T11:40:37.154Z","etag":null,"topics":["ed25519","keys","rsa","ssh","vanity"],"latest_commit_sha":null,"homepage":"http://blehg.paperclipmaximizer.ai/vanissh/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/scottvr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-23T17:57:16.000Z","updated_at":"2025-07-28T09:56:46.000Z","dependencies_parsed_at":"2025-02-23T19:25:25.862Z","dependency_job_id":"69332f85-23b0-4efe-9a20-e80789e7a153","html_url":"https://github.com/scottvr/vanissh","commit_stats":null,"previous_names":["scottvr/vanissh"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/scottvr/vanissh","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottvr%2Fvanissh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottvr%2Fvanissh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottvr%2Fvanissh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottvr%2Fvanissh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scottvr","download_url":"https://codeload.github.com/scottvr/vanissh/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scottvr%2Fvanissh/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28479405,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ed25519","keys","rsa","ssh","vanity"],"created_at":"2026-01-16T14:56:44.601Z","updated_at":"2026-01-16T14:56:45.090Z","avatar_url":"https://github.com/scottvr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VANISSH - Vanity SSH key generator\n\n![If they can't tell how l33t you are by having a vanity public key, make it explicit](https://github.com/scottvr/vanissh/raw/f1cad4023864831e3ea8e4a099ee30525ce34f23/vanisshex.png)\n\n## on the origin of vanissh\nI was importing some public keys into an authorized_keys file manually for a small side project and noticed that about half of them were rsa2048 and the rest were ed25519, and that the Base64-encoded ed25519 keys were much shorter in length than the RSA keys, and then realized I knew nothing about the current state of recommended keysize and cipher and thought I should take a moment to learn. \n\nA quick search lead me to [Brandon Checketts' blog](https://www.brandonchecketts.com/archives/ssh-ed25519-key-best-practices-for-2025) page on the topic (in which he pokes a little fun about his *older* version of a similar article ranking highly with the search engines, making him apparently feel somewhat obligated to write an updated version of an \"SSH Key Best Practices\" post.) It's a good read and touches on things like \"department keys\", key rotation, and some other good stuff; check it out.\n\nBut the reason I am mentioning his blog post is that near the bottom of his article he writes:\n\u003eObsessive/Compulsive Tip\nThis may be taking it too far, but I like to have a memorable few digits at the end of the key so that I can confirm the key got copied correctly. One of my keys ends in 7srus, so I think of it as my “7’s ‘R’ Us” key. You can do that over and over again until you find a key that you like with this one-liner:\n```bash\nrm newkey; rm newkey.pub; ssh-keygen -t ed25519 -f ./newkey -C \"brandon+2025@roundsphere.com\" -N ''; cat newkey.pub;\n```\n\u003eThat creates a key without a passphrase, so you can do it over and over quickly until you find a public key that you “like”. Then protect it with a passphrase with the command\n```bash\nssh-keygen -p -f newkey\n```\n\u003eAnd obviously, then you rename it from newkey and to newkey.pub a more meaningful name.\n\nI chuckled at the notion of running the command over and over again until you get a key that you \"like\", but it brought forth vague impressions of BTC vanity addresses, intentional hash collisions and the like. My first fully-realized thought immediately upon reading it though was \"oh no.. that should be automated in a loop. And those *memorable few digits* should be *specified beforehand* and then checked for, and when found the loop should exit, and rename your file for you.\"\n\nSo naturally a tool started taking shape in my mind that would take a string, or perhaps a wordlist, and maybe even allow the user to specify where they would like to see the string... hmmm.\n\n# Usage\n\n```bash\nusage: vanissh.py [-h] [-e email/comment] [-ap vanity_str] [-sp vanity_str]\n                  [-ep vanity_str] [-ca] [-cs] [-ce] [-rp vanity_str] [-O]\n                  [-st {0.0,1.0}] [-pl {0,22} | -ps vanity_str] [-ui] [-pc]\n                  [-t {ed25519,rsa}] [-b bits] [-n numproc] [-l logfile]\n```\n# Options\n\n```bash\noptional arguments:\n  -h, --help            show this help message and exit\n  -e email/comment, --email email/comment\n                        Email address for key comment\n  -n numproc, --processes numproc\n                        Number of worker processes to use\n  -l logfile, --logfile logfile\n                        Output file for generation results (JSON)\n\nVanity Pattern options:\n  -ap vanity_str, --anywhere-pattern vanity_str\n                        Pattern to match anywhere in the key\n  -sp vanity_str, --start-pattern vanity_str\n                        Pattern that must match at start of key\n  -ep vanity_str, --end-pattern vanity_str\n                        Pattern that must match at end of key\n  -ca, --case-sensitive-anywhere\n                        Make anywhere patterns case-sensitive\n  -cs, --case-sensitive-start\n                        Make start patterns case-sensitive\n  -ce, --case-sensitive-end\n                        Make end patterns case-sensitive\n\nRSA Vanity Injection:\n  -rp vanity_str, --rsa-vanity vanity_str\n                        Generate RSA key with specific vanity text injected at\n                        start of key\n  -O, --optimize        Suggest optimized variations of the vanity text for\n                        faster generation\n  -st {0.0,1.0}, --similarity {0.0,1.0}\n                        Minimum visual similarity for optimized variations\n                        (0.0-1.0)\n\nPalindrome options:\n  -pl {0,22}, --palindrome-length {0,22}\n                        Generate any palindrome of this total length\n  -ps vanity_str, --palindrome-start vanity_str\n                        Generate a palindrome starting with these characters\n  -ui, --use-free-i     Use the guaranteed \"I\" character as part of the\n                        palindrome\n  -pc, --palindrome-case-sensitive\n                        Make palindrome matching case-sensitive\n\nKey Generation options:\n  -t {ed25519,rsa}, --key-type {ed25519,rsa}\n                        Type of key to generate\n  -b bits, --key-bits bits\n                        Bits for RSA key (ignored for ed25519)\n\n```\n# Examples\n\nYou may wonder about the awkwardly-specific command-line arguments relating to the pattern you'd like to see, so I'll explain simply that they are there to enable flexibility on a single command invocation, in order to save time by increasing the chances *something* will match that you'll be pleased with. (Though there's still room for improvement such as allowing for ANDing multiple arguments or negative patterns. Of course, if you're determined enough since your patterns can be a valid regex, you can roll your own ANDing and negatives and anything else your regex-fu might enable.)\n\n## This example below is a way to generate a public key that matches\n- any of \"31337\", \"leet\", \"l33t\", \"elite\" anywhere in the key's Base64-encoded string OR\n- \"el8\" either as the first or last three characters of the key's Base64-encoded string\nwhichever comes first.*\n```bash\npython src/vanissh.py -e you@example.com \\\n    -ap \"31337|leet|l33t|elite\" \\\n    -ep \"el8\" \\\n    -sp \"el8\"\n```\n\n## Mix and match with position-specific case sensitivity (again, regex could handle this for you if you care to roll your own)\n```bash\npython src/vanissh.py -e you@example.com \\\n    -ap \"l33t|elite\" -ca \\\n    -ep \"cool\" \\\n    -sp \"HACK\" -cs\n```\n\n## Multiple patterns per position\n```bash\npython src/vanissh.py -e you@example.com \\\n    -ap \"l33t\" -ap \"elite\" \\\n    -ep \"er\" -ep \"or\" \\\n    -xp \"ABCD\"\n```\nand again, since it's all \"OR\" logic of terms at this point, the first example with the pipe-separated terms would be another way to accomplish the same.\nAlso, with the power of regex you could do something like this:\n`-ap \"(.)(.)(.).?\\3\\2\\1\"` and be assured that, given enough time, you'd have an ssh public key that contained a palindrome! (continue that up to \\22 (so you'll have a total of 44 characters after the Base64-encoded ssh-ed25519 prefix) and your entire public key is a palindrome! Maybe that's something to tackle in the \"stuff I learned\" section when we talk about probabilities.\n## EDIT\nWhere there was just the above silly-but-true comment about palindromes, there is now a built-in palindromic keyfinder. \nJust playin' around on an old i5 laptop:\n```bash\n(.venv) C:\\Users\\scottvr\\source\\vanissh\u003epython src\\vanissh.py  -e ia.mamai@iamam.ai --palindrome-length 7\nGenerated palindrome pattern: (.)(.)(.)(.)\\3\\2\\1\nStarting generation with 4 processes...\n\nGeneration Results:\nFound matching key in 13.66 seconds\nTotal attempts: 513\nKeys per second: 37.56\nKeys per second per worker: 9.39\n\nCPU Frequency (MHz):\n  Min: 2400\n  Max: 2400\n  Avg: 2400\n\nMatching Key:\nPublic key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICZKa/n6RbGXwMwXGdNiUUiB2gc8t1SC\nnCBHf1YTgoBa meem@ten.net\nMatched pattern 'GXwMwXG' at position (34, 41)\nFound by worker 2 (PID: 9780)\n```\nlulz. It doesn't look like much hiding in the key but you gotta admit that \n### GXwMwXG\nlooks pretty cool on its own.\n\nThe new options are, btw:\n```\nPalindrome options:\n  --palindrome-length PALINDROME_LENGTH\n                        Generate any palindrome of this total length\n  --palindrome-start PALINDROME_START\n                        Generate a palindrome starting with these characters\n  --use-free-i          Use the guaranteed \"I\" character as part of the\n                        palindrome\n```\nok.. back to what you were reading before...\n----\n\n*there is a bit of post-match checking for  magic that occurs in the unlikely event that you specified a pattern in such a way where say a five-letter pattern is specified as well as a three-letter pattern that is found within that longer pattern. If it is about to declare a winning three-letter pattern, it will check just in case you get lucky and alert you if surrounding characters mean you also matched the five-letter pattern. I'm working on allowing the known characters of the pre-amble (I'll talk about this in a later section) to be checked in the event you have a `start` or `anywhere` pattern where the \"AI\" at the start of the Base64-encoded 32-byte key of your new ed25519 key can be used to save two characters of generation. A FREE 'i' or FREE 'AI' even!\n\n# some output examples\n```bash\n# python src/vanissh.py -e foo@bar.baz -ap 13\nStarting benchmark with 1 processes...\n\nBenchmark Results:\nFound matching key in 0.56 seconds\nTotal attempts: 96\nKeys per second: 170.31\nKeys per second per worker: 170.31\n\nCPU Frequency (MHz):\n  Min: 2300\n  Max: 2300\n  Avg: 2300\n\nMatching Key:\nPublic key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILEYnLgpraYTF/Wq+zxSs+fpuOfxSwJ9krpfext13uzX foo@bar.baz\nMatched pattern '13' at position (63, 65)\nFound by worker 0 (PID: 28494)\n```\n\nHere's an example of searching for a three-letter pattern:\n```bash\nFound matching key in 12.18 seconds after 1974 attempts!\nKey files saved as: /home/scottvr/ssh-key-mem/memorable_key_1740283444\nPublic key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINEl80DxH5FI+IMP2Xdf4AHu8I/YZ209Vf+5Dstd4YXf foo@bar.baz\nMatched pattern 'El8' at position (26, 29)\n```\n\nThat didn't take long at all. It was quite surprising to me.\n\nOf course, the more characters in your pattern and the more constraints you specify (position, case-sensitivity) the longer the average time for you to generate a winning vanity key will be.\n\nBut, that's an average, over time, given enough generations.. I'm not a statistician and *I* know why*; perhaps you will all soon know why as well as I try to explain some things. (*know why I am not a statistician, that is.) \n\n\n## Some Thoughts and Learnings along the way.\n\nThese examples above are output from running vanissh on a very old T2.micro instance, and its single core generates, then does the strings matching, etc consistently at a rate of about 170 keys/second.\nThe tool has benchmarking code, but I've yet to run it on any other machines as I still haven't even finished this initial documentation. \n\nBut something occurred to me, that seemed obvious and intuitive at first: \"Hey, an RSA key has a lot more Base64-encoded text; it's much longer - surely that would vastly increase our chances of finding an \"anywhere\" match and thus speed this sucker up. I should add rsa2048 support\"\n\nI did add the support. But what I did not consider before trying was that (although I having added support for both types of key to have been worthwhile, inasmuch as this tool is worth any while at least) an RSA key takes a substantially greater amount of time to generate than the ed25519 keys do.\n\nThe public key format shows the modulus (n) of the RSA key pair, but finding specific patterns in that modulus isn't as simple as generating new keys rapidly because:\n\nEach RSA key generation requires finding large prime numbers and performing relatively expensive mathematical operations\nED25519 key generation is much faster (often by orders of magnitude)\n\nIn my testing, ED25519 key generation is typically 5-10x faster than RSA-2048 for this purpose. I didn't even try with RSA4096 but I'd imagine the obvious.\n\n----\n### this section is still being written\n\nAccording to [RFC8709](https://datatracker.ietf.org/doc/html/rfc8709):\n```\n4. Public Key Format\nThe \"ssh-ed25519\" key format has the following encoding:\n\nstring\n\"ssh-ed25519\"\nstring\nkey\nHere, 'key' is the 32-octet public key described in [RFC8032](https://datatracker.ietf.org/doc/html/rfc8032), Section 5.1.5.\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscottvr%2Fvanissh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscottvr%2Fvanissh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscottvr%2Fvanissh/lists"}