-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 _ ____ ____ ____ _ _|_|_ __ _ __ __ __ __ _ __ / _ \/ _ \|___ \ | | | | | '_ \| '_ \'_ \\ \/ /| '_ \ | | | | | | | __) | | |_| | | | | | | | | | |\ / | | | | | |_| | |_| |/ __/ \__,|_|_|_| |_|_| |_| |_|/ / |_| |_| \____(_)___/|_____| /_/ Change log Add a script to enter gotten pages into a local browser-accessible cache. Improvements to the documentation. The url@is-not-my.name Internet page fetcher [1] allows an individual to read Internet content with strong anonymity. Content is returned encrypted in Usenet newsgroup alt.anonymous.messages. No one, not even the is-not-my.name administrator, is able to link content being fetched with any particular individual, or with other requests. Here are some scripts to facilitate use of url@is-not-my.name. There are two main scripts: uinmyn-fetch-body.py -- code URLs into a request and save the key uinmyn-do-aam-article.py -- extract pages from returned a.a.m. articles Given a (short) list of URLs, uinmyn-fetch-body.py generates a random key for the encryption and hsub of the reply, saves the key in a local database, and constructs the body of the request, encrypted and ready to send through a remailer chain. Each message from a.a.m. is then fed to uinmyn-do-aam-article.py. If the message matches a key in the database, the key is removed from the database, the decrypted message is saved for further processing, and the script returns with a positive code. Otherwise, the script gives a negative code. The script is therefore useful for procmail, which might be checking the same message for other hits. The following .procmailrc clause sequence will send the decrypted "inner posting" to local-recipient. :0fW | uinmyn-do-aam-article.py /path/to/uinmyn_pending_requests_db :0a ! local-recipient The net effect, if all goes well, is that the pages addressed by URLs submitted to uinmyn-fetch-body.py show up, after privacy-protecting remailer random latencies. No record leaves your site of who accessed the pages. Also provided here is are minor support scripts to list the URLs in a given reply, and to insert page content into the browser-accessible cache provided by wwwoffle [2]. Out of respect for your privacy, uinmyn does not require you to access any web site for its installation or use (though you may if you wish: mailto:stealthsuite@nym.mixmin.net). Everything is right here in this posting. ABOUT THE CODE Succinctness and readability are given priority here over efficiency. If efficiency becomes an issue, there are lots of opportunities here for speedup. These scripts are meant mainly as hints for you to adapt to the needs of your particular case. But they could be used verbatim if you like the way they are structured. INSTALLATION Have python, gnupg, and mixmaster installed. Have the send@is-not-my.name public key on your gnupg keyring. Copy the scripts from below to somewhere on your executables path. Of course, you are taking a full feed of a.a.m at all times without interruption, separating wheat from chaff only after it's all behind closed doors. Otherwise, the world is informed about which articles you find interesting. Remember, long random latency is part of the price of untraceability. It can't be done with TOR or any other low-latency method. EXAMPLE Typing uinmyn-fetch-body.py db | mixmaster url@is-not-my.name http://www.bananasplit.info ^D will send a request for http://www.bananasplit.info. The key is added to db, which need not have existed beforehand. (It's plain ASCII, so you can look at it to better understand what's happening.) Later, in a directory full of fresh a.a.m articles, the command for f in *; do uinmyn-do-aam-article.py db < $f >> mbox; done will append the requested content to mbox if it has arrived. FOOTNOTES [1] http://www.is-not-my.name [2] World Wide Web OFFline Explorer http://www.gedanken.demon.co.uk/wwwoffle/ TODO Use PIPE for the gpg stdin in uinmyn-do-aam-article.py. BUGS Encryption/hsub keys are exposed briefly during a.a.m. processing. Here are the scripts. 8<--------8<--------8<--------8<--------8<--------8<--------8<-------- #! /usr/bin/python # SYNOPSIS # uinmyn-fetch-body.py <pending-requests-dict> # DESCRIPTION # Reads URLs from standard input, one per line, generates a fresh # random key to encrypt the reply and for its hsub, adds the key and # the requested URLs to pending-requests-dict (creating it anew if # it doesn't exist), constructs and encrypts a request for # url@is-not-my.name, and writes it to standard output. from os import urandom from base64 import standard_b64encode import sys, os import pprint from subprocess import Popen, PIPE UINMYN_PENDING_REQUESTS = sys.argv[1] # same key for both encryption and hsub: key = standard_b64encode(urandom(15)) gpgproc = Popen('gpg -e -a -r send@is-not-my.name --trust-model always --no-emit-version --batch', shell=True, stdin=PIPE) gpgproc.stdin.write("KEY " + key + '\n') urls = [] for line in sys.stdin.readlines(): urls.append(line.rstrip()) gpgproc.stdin.write('SOURCE ' + line.rstrip() + '\n') gpgproc.stdin.close() # Not dealt with here: Mutually exclusive access to the # UINMYN_PENDING_REQUESTS database, as would be required if request # issuance might be concurrent with a.a.m. processing. if os.path.isfile(UINMYN_PENDING_REQUESTS): execfile(UINMYN_PENDING_REQUESTS) else: uinmyn_pending_requests = {} uinmyn_pending_requests[key] = urls new_upr_fd = open(UINMYN_PENDING_REQUESTS, 'w') new_upr_fd.write('uinmyn_pending_requests =\\\n') pprint.pprint(uinmyn_pending_requests,stream=new_upr_fd) 8<--------8<--------8<--------8<--------8<--------8<--------8<-------- #! /usr/bin/python # SYNOPSIS # uinmyn-do-aam-article.py <pending-requests-dict> # DESCRIPTION # Reads an article from standard input. If its Subject: might be an # hsub, check it against each key in pending-requests-dict in turn. # If a hit is found, decrypt the inner posting and write it to # standard output. import sys, os from hashlib import sha256 import email import pprint from subprocess import Popen UINMYN_PENDING_REQUESTS = sys.argv[1] posting = email.message_from_file(sys.stdin) subject = posting.get('Subject') try: iv = subject[:16].decode('hex') except TypeError: sys.exit(1) # Not dealt with here: Mutually exclusive access to the # UINMYN_PENDING_REQUESTS database, as would be required if request # issuance might be concurrent with a.a.m. processing. if os.path.isfile(UINMYN_PENDING_REQUESTS): execfile(UINMYN_PENDING_REQUESTS) else: uinmyn_pending_requests = {} for key, urls in uinmyn_pending_requests.iteritems(): if subject == (iv+sha256(iv+key).digest()).encode('hex')[:48]: # Doing part of the job in shell: gpgproc = Popen('mkfifo $HOME/passwdf ; (echo ' + key + ' > $HOME/passwdf &); echo "' + posting.get_payload() + '" | gpg --passphrase-fd 3 3<$HOME/passwdf --trust-model always --batch 2>/dev/null ; rm $HOME/passwdf', shell=True) # Other processing that could be done here: # Deal with discrepancies between requested and obtained URL lists. # Save the used key in an archive, rather than losing it forever. del uinmyn_pending_requests[key] new_upr_fd = open(UINMYN_PENDING_REQUESTS, 'w') new_upr_fd.write('uinmyn_pending_requests =\\\n') pprint.pprint(uinmyn_pending_requests,stream=new_upr_fd) sys.exit(0) sys.exit(1) 8<--------8<--------8<--------8<--------8<--------8<--------8<-------- #! /usr/bin/python # SYNOPSIS # uinmyn-list-gotten-urls.py # DESCRIPTION # List the URLs in the url@is-not-my.name "inner mail" on standard # input together with the sizes of the fetched pages. import sys, email pages = email.message_from_file(sys.stdin) for page in pages.get_payload(): print(page.get('Content-Description') + ', size = ' + repr(len(page.get_payload()))) 8<--------8<--------8<--------8<--------8<--------8<--------8<-------- #! /usr/bin/python # SYNOPSIS # uinmyn-to-wwwoffle-cache.py # DESCRIPTION # Given a (decrypted) url@is-not-my.name "inner posting", enter each # page that it contains into the wwwoffle cache, overlaying any # previous content having matching URLs. import sys, os, email from subprocess import Popen, PIPE pages = email.message_from_file(sys.stdin) for page in pages.get_payload(): p = Popen('wwwoffle-write ' + page.get('Content-Description'), stdin=PIPE, shell=True) p.stdin.write('HTTP/1.0 200 OK\n') p.stdin.write('Content-Type: ' + page.get('Content-Type') + '\n\n') p.stdin.write(page.get_payload()) p.stdin.close() p.wait() 8<--------8<--------8<--------8<--------8<--------8<--------8<-------- -- StealthMonger <StealthMonger@nym.mixmin.net> -- stealthmail: Scripts to hide whether you're doing email, or when, or with whom. mailto:stealthsuite@nym.mixmin.net Finger for key. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Processed by Mailcrypt 3.5.8+ <http://mailcrypt.sourceforge.net/> iEYEARECAAYFAkw1r8oACgkQDkU5rhlDCl7XWACeLJfrjxtSr023Kmjb0hV+l41L wikAoKy/jf7ANoeXaTaf7ZmVbBBP4ljE =Z3n5 -----END PGP SIGNATURE-----