Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

uinmyn 0.07

4 views
Skip to first unread message

StealthMonger

unread,
Mar 28, 2011, 5:12:35 PM3/28/11
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

The Internet is even more powerful at protecting privacy than it is
at destroying it.

--- StealthMonger


... for low-latency systems like Tor, end-to-end traffic
correlation attacks [8, 21, 31] allow an attacker who can observe
both ends of a communication to correlate packet timing and volume,
quickly linking the initiator to her destination.

--- http://tor.eff.org/cvs/tor/doc/design-paper/challenges.pdf


Long, random latency is part of the price of Internet anonymity.

--- StealthMonger

_ ____ ____ ______
_ _|_|_ __ _ __ __ __ __ _ __ / _ \/ _ \\___ |
| | | | | '_ \| '_ \'_ \\ \/ /| '_ \ | | | | | | | / /
| |_| | | | | | | | | | |\ / | | | | | |_| | |_| | / /
\__,|_|_|_| |_|_| |_| |_|/ / |_| |_| \____(_)___/ /_/
/_/

__________________________________________
| |
| |
| IS THIS ANONYMOUS BROWSING, OR WHAT?! |
| |
|__________________________________________|

N.B.: Replace occurrences of "<AT>" with "@" in all email addresses!

The url<AT>is-not-my.name Internet page fetcher [1] allows the reading
of Internet content with strong anonymity. An encrypted request is
sent through a chain of anonymizing remailers and 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 user, or with other requests.

Here are some scripts to facilitate use of url<AT>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 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 the requester's site of
who accessed the pages.

Also provided here 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].

Return codes from uinmyn-do-aam-article.py are 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

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<AT>nym.mixmin.net?subject=send%20index.html).
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.

INSTALLATION

Have python, gnupg, and mixmaster installed.
Have public key '94F204C28BF00937EFC85D1AFF4DB66014D0C447' 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 anonymity. It
can't be done with TOR or any other low-latency method.

EXAMPLE

Typing

uinmyn-fetch-body.py db | mixmaster url<AT>is-not-my.name
http://www.banana.mixmin.net
^D

will send a request for http://www.banana.mixmin.net. 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/

BUGS

Encryption/hsub keys are exposed briefly during a.a.m. processing.

CHANGE LOG

0.07

Use long keyid, not send<AT>is-not-my.name, to identify encryption
key, foiling fake key postings. Contributed by Steve Crook.

Use Python's internal encode('base64') instead of imported Base64
to encode the random key. Contributed by Steve Crook.

Use Python "%"-style string substitution for type conversion and
tidier code (yet to be finished). Contributed by Steve Crook.

Support hsub's ranging from 48 to 80 chars in length. Contributed
by Steve Crook.

Systematically code all email addresses to avert Google corruption
of its archived version of this posting.

0.06

Add time-stamps to database entries to facilitate removal of old,
stale entries.

Changed slogan from "Is this anonymous surfing, or what?".

Documentation improvements.

0.05

Quote URL in uinmyn-do-aam-article.py against shell interpretation.

0.04

Did TODO item:
Use PIPE for the gpg stdin in uinmyn-do-aam-article.py.
(eliminating previous stupid size limit).

0.03

Add "decode=True" in uinmyn-to-wwwoffle-cache.py to capture coded
files, such as .pdfs.

Change the www.bananasplit.info reference to www.banana.mixmin.net.

0.02

Add a script to enter gotten pages into a local browser-accessible
cache.

Improvements to the documentation.


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<AT>is-not-my.name, and writes it to standard output.

from os import urandom
import sys, os, time
import pprint
from subprocess import Popen, PIPE

UINMYN_PENDING_REQUESTS = sys.argv[1]
NYMSERV_KEY = '94F204C28BF00937EFC85D1AFF4DB66014D0C447'

# same key for both encryption and hsub:
key = urandom(15).encode('base64').rstrip()

gpgcmd = 'gpg --armor --encrypt --recipient %s ' % NYMSERV_KEY
gpgopts = '--trust-model always --no-emit-version --batch'
gpgproc = Popen(gpgcmd + gpgopts, shell=True, stdin=PIPE)
gpgproc.stdin.write("KEY %s\n" % key)

urls = [time.time()] # time-tag precedes the urls in the db entry
for line in sys.stdin.readlines():
urls.append(line.rstrip())
gpgproc.stdin.write('SOURCE %s\n' % line.rstrip())

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, PIPE

UINMYN_PENDING_REQUESTS = sys.argv[1]

posting = email.message_from_file(sys.stdin)

# Abort if Subject doesn't exist, otherwise get its length
if 'Subject' in posting:
sublen = len(posting['Subject'])
else:
# No Subject, no hSub.
sys.exit(1)

# hSubs must fall within the length criteria
if sublen < 48 or sublen > 80:
sys.exit(1)

try:
iv = posting['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():
hsub = (iv + sha256(iv + key).digest()).encode('hex')[:sublen]
if posting['Subject'] == hsub:
# Doing part of the job in shell:
gpgproc = Popen('mkfifo $HOME/passwdf ; (echo ' + key + ' > $HOME/passwdf &); gpg --passphrase-fd 3 3<$HOME/passwdf --trust-model always --batch 2>/dev/null ; rm $HOME/passwdf', stdin=PIPE, shell=True)
gpgproc.stdin.write(posting.get_payload())
# 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<AT>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<AT>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(decode=True))
p.stdin.close()
p.wait()
8<--------8<--------8<--------8<--------8<--------8<--------8<--------

-- StealthMonger <StealthMonger<AT>nym.mixmin.net>
Long, random latency is part of the price of Internet anonymity.

stealthmail: Hide whether you're doing email, or when, or with whom.
mailto:stealthsuite<AT>nym.mixmin.net?subject=send%20index.html

Key: mailto:stealthsuite<AT>nym.mixmin.net?subject=send%20stealthmonger-key

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.8+ <http://mailcrypt.sourceforge.net/>

iEYEARECAAYFAk2PgRAACgkQDkU5rhlDCl4fmACgoPV2Kj2VyNvrV57GIifI0CbU
osQAoMN+QMjE6T8If+qjFvZAacb82DVP
=WtPJ
-----END PGP SIGNATURE-----

0 new messages