<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: cryptography</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/cryptography.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-11-25T18:32:23+00:00</updated><author><name>Simon Willison</name></author><entry><title>Constant-time support lands in LLVM: Protecting cryptographic code at the compiler level</title><link href="https://simonwillison.net/2025/Nov/25/constant-time-support-lands-in-llvm/#atom-tag" rel="alternate"/><published>2025-11-25T18:32:23+00:00</published><updated>2025-11-25T18:32:23+00:00</updated><id>https://simonwillison.net/2025/Nov/25/constant-time-support-lands-in-llvm/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.trailofbits.com/2025/11/25/constant-time-support-lands-in-llvm-protecting-cryptographic-code-at-the-compiler-level/"&gt;Constant-time support lands in LLVM: Protecting cryptographic code at the compiler level&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Substantial LLVM contribution from Trail of Bits. Timing attacks against cryptography algorithms are a gnarly problem: if an attacker can precisely time a cryptographic algorithm they can often derive details of the key based on how long it takes to execute.&lt;/p&gt;
&lt;p&gt;Cryptography implementers know this and deliberately use constant-time comparisons to avoid these attacks... but sometimes an optimizing compiler will undermine these measures and reintroduce timing vulnerabilities.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Trail of Bits has developed constant-time coding support for LLVM 21, providing developers with compiler-level guarantees that their cryptographic implementations remain secure against branching-related timing attacks. This work introduces the &lt;code&gt;__builtin_ct_select&lt;/code&gt; family of intrinsics and supporting infrastructure that prevents the Clang compiler, and potentially other compilers built with LLVM, from inadvertently breaking carefully crafted constant-time code.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/occlzx/constant_time_support_lands_llvm"&gt;Lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llvm"&gt;llvm&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="cryptography"/><category term="llvm"/></entry><entry><title>Claude Code Can Debug Low-level Cryptography</title><link href="https://simonwillison.net/2025/Nov/1/claude-code-cryptography/#atom-tag" rel="alternate"/><published>2025-11-01T22:26:43+00:00</published><updated>2025-11-01T22:26:43+00:00</updated><id>https://simonwillison.net/2025/Nov/1/claude-code-cryptography/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://words.filippo.io/claude-debugging/"&gt;Claude Code Can Debug Low-level Cryptography&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Go cryptography author Filippo Valsorda reports on some very positive results applying Claude Code to the challenge of implementing novel cryptography algorithms. After Claude was able to resolve a "fairly complex low-level bug" in fresh code he tried it against two other examples and got positive results both time.&lt;/p&gt;
&lt;p&gt;Filippo isn't directly using Claude's solutions to the bugs, but is finding it useful for tracking down the cause and saving him a solid amount of debugging work:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Three out of three one-shot debugging hits with no help is &lt;em&gt;extremely impressive&lt;/em&gt;. Importantly, there is no need to trust the LLM or review its output when its job is just saving me an hour or two by telling me where the bug is, for me to reason about it and fix it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using coding agents in this way may represent a useful entrypoint for LLM-skeptics who wouldn't &lt;em&gt;dream&lt;/em&gt; of letting an autocomplete-machine writing code on their behalf.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=45784179"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/go"&gt;go&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/filippo-valsorda"&gt;filippo-valsorda&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="go"/><category term="security"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="filippo-valsorda"/><category term="coding-agents"/><category term="claude-code"/></entry><entry><title>Encryption At Rest: Whose Threat Model Is It Anyway?</title><link href="https://simonwillison.net/2024/Jun/4/encryption-at-rest/#atom-tag" rel="alternate"/><published>2024-06-04T13:17:34+00:00</published><updated>2024-06-04T13:17:34+00:00</updated><id>https://simonwillison.net/2024/Jun/4/encryption-at-rest/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://scottarc.blog/2024/06/02/encryption-at-rest-whose-threat-model-is-it-anyway/"&gt;Encryption At Rest: Whose Threat Model Is It Anyway?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Security engineer Scott Arciszewski talks through the challenges of building a useful encryption-at-rest system for hosted software. Encryption at rest on a hard drive protects against physical access to the powered-down disk and little else. To implement encryption at rest in a multi-tenant SaaS system - such that even individuals with insider access  (like access to the underlying database) are unable to read other user's data, is a whole lot more complicated.&lt;/p&gt;
&lt;p&gt;Consider an attacker, Bob, with database access:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here’s the stupid simple attack that works in far too many cases: Bob copies Alice’s encrypted data, and overwrites his records in the database, then accesses the insurance provider’s web app [using his own account].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fix for this is to "use the AAD mechanism (part of the standard AEAD interface) to bind a ciphertext to its context." Python's cryptography package &lt;a href="https://cryptography.io/en/latest/hazmat/primitives/aead/"&gt;covers Authenticated Encryption with Associated Data&lt;/a&gt; as part of its "hazardous materials" advanced modules.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=40573211"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/encryption"&gt;encryption&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="encryption"/><category term="python"/><category term="security"/></entry><entry><title>Quoting John Gruber</title><link href="https://simonwillison.net/2023/Aug/24/john-gruber/#atom-tag" rel="alternate"/><published>2023-08-24T06:16:18+00:00</published><updated>2023-08-24T06:16:18+00:00</updated><id>https://simonwillison.net/2023/Aug/24/john-gruber/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://daringfireball.net/2023/08/kouvakas_uk_surveillance"&gt;&lt;p&gt;And the notion that security updates, for every user in the world, would need the approval of the U.K. Home Office just to make sure the patches weren’t closing vulnerabilities that the government itself is exploiting — it boggles the mind. Even if the U.K. were the only country in the world to pass such a law, it would be madness, but what happens when other countries follow?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://daringfireball.net/2023/08/kouvakas_uk_surveillance"&gt;John Gruber&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/john-gruber"&gt;john-gruber&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/law"&gt;law&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/uk"&gt;uk&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/uklaw"&gt;uklaw&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="john-gruber"/><category term="law"/><category term="uk"/><category term="uklaw"/></entry><entry><title>Over-engineering Secret Santa with Python cryptography and Datasette</title><link href="https://simonwillison.net/2022/Dec/11/over-engineering-secret-santa/#atom-tag" rel="alternate"/><published>2022-12-11T02:03:39+00:00</published><updated>2022-12-11T02:03:39+00:00</updated><id>https://simonwillison.net/2022/Dec/11/over-engineering-secret-santa/#atom-tag</id><summary type="html">
    &lt;p&gt;We're doing a family &lt;a href="https://en.wikipedia.org/wiki/Secret_Santa"&gt;Secret Santa&lt;/a&gt; this year, and we needed a way to randomly assign people to each other without anyone knowing who was assigned to who.&lt;/p&gt;
&lt;p&gt;I offered to write some software! (Maybe "insisted" is more accurate)&lt;/p&gt;
&lt;p&gt;I've been wanting an excuse to write something fun involving Python's &lt;a href="https://cryptography.io/en/latest/"&gt;cryptography&lt;/a&gt; library for years. The problem is that I'm too responsible/cowardly to ignore the many warnings to only use the "hazardous materials" area of that library if you know exactly what you're doing.&lt;/p&gt;
&lt;p&gt;A secret santa is the &lt;em&gt;perfect&lt;/em&gt; low stakes project to ignore those warnings and play with something fun.&lt;/p&gt;
&lt;h4&gt;My requirements&lt;/h4&gt;
&lt;p&gt;I have six participants. Each participant needs to know who they are to buy a gift for - with no way of finding out any of the other gift pairings.&lt;/p&gt;
&lt;p&gt;As the administrator of the system I must not be able to figure out the pairings either.&lt;/p&gt;
&lt;p&gt;I don't want to use email or logins or anything like that - I just want to be able to share a link in the family WhatsApp group and have everyone use the same interface to get their pairing.&lt;/p&gt;
&lt;h4&gt;How it works&lt;/h4&gt;
&lt;p&gt;Here's the scheme I came up with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each participant gets a password generated for them. This happens on demand when they click a button - with an honour system not to click someone else's button (easily detected since each button can only be clicked once). If someone DOES click someone else's button we can reset the entire system and start again.&lt;/li&gt;
&lt;li&gt;Their password is generated for them - it's three random words, for example "squirrel copper sailboat". I expect most people to take a screenshot with their phone to record it.&lt;/li&gt;
&lt;li&gt;Behind the scenes, each user has a RSA public/private key generated for them. The private key is encrypted using their new password, then both keys are stored in the database. The password itself is NOT stored.&lt;/li&gt;
&lt;li&gt;Once every user has generated and recorded their password, we can execute the Secret Santa assignments. This shuffles the participants and then assigns each person to the person after them in the list. It then uses their public keys to encrypt a message telling them who they should buy a gift for.&lt;/li&gt;
&lt;li&gt;Those encrypted messages are stored in the database too.&lt;/li&gt;
&lt;li&gt;Finally, each user can return to the site and enter their password to decrypt and view their message.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here's an animated GIF demo:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2022/secret-santa.gif" alt="Animated GIF showing the plugin in action - the user adds three names, then gets the password for their account - then hits the assign button and uses their password to find out who they have been assigned" style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;h4&gt;Building it as a Datasette plugin&lt;/h4&gt;
&lt;p&gt;This is a tiny app with a very small amount of persistence needed, so I decided to build it as a Datasette plugin on top of a couple of SQLite database tables.&lt;/p&gt;
&lt;p&gt;In addition to giving me an excuse to try something new with my &lt;a href="https://datasette.io/"&gt;main project&lt;/a&gt;, this should also hopefully make it easy to deploy.&lt;/p&gt;
&lt;p&gt;Most of the code is in the &lt;a href="https://github.com/simonw/datasette-secret-santa/blob/main/datasette_secret_santa/__init__.py"&gt;datasette_secret_santa/__init__.py&lt;/a&gt; file. I used a number of different &lt;a href="https://docs.datasette.io/en/stable/plugin_hooks.html"&gt;plugin hooks&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;startup()&lt;/code&gt; to create the database tables it needs when the server first starts (if they do not exist already)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;canned_queries()&lt;/code&gt; to add a canned SQL query for creating new Secret Santa groups, to save me from needing to build a custom UI for that&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;register_routes()&lt;/code&gt; to register five new custom pages within Datasette&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;extra_template_vars()&lt;/code&gt; to make an extra context variable available on the Datasette homepage, which is rendered using a custom template&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are the routes:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-en"&gt;@&lt;span class="pl-s1"&gt;hookimpl&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;register_routes&lt;/span&gt;():
    &lt;span class="pl-k"&gt;return&lt;/span&gt; [
        (&lt;span class="pl-s"&gt;r"^/secret-santa/(?P&amp;lt;slug&amp;gt;[^/]+)$"&lt;/span&gt;, &lt;span class="pl-s1"&gt;secret_santa&lt;/span&gt;),
        (&lt;span class="pl-s"&gt;r"^/secret-santa/(?P&amp;lt;slug&amp;gt;[^/]+)/add$"&lt;/span&gt;, &lt;span class="pl-s1"&gt;add_participant&lt;/span&gt;),
        (&lt;span class="pl-s"&gt;r"^/secret-santa/(?P&amp;lt;slug&amp;gt;[^/]+)/assign$"&lt;/span&gt;, &lt;span class="pl-s1"&gt;assign_participants&lt;/span&gt;),
        (&lt;span class="pl-s"&gt;r"^/secret-santa/(?P&amp;lt;slug&amp;gt;[^/]+)/set-password/(?P&amp;lt;id&amp;gt;\d+)$"&lt;/span&gt;, &lt;span class="pl-s1"&gt;set_password&lt;/span&gt;),
        (&lt;span class="pl-s"&gt;r"^/secret-santa/(?P&amp;lt;slug&amp;gt;[^/]+)/reveal/(?P&amp;lt;id&amp;gt;\d+)$"&lt;/span&gt;, &lt;span class="pl-s1"&gt;reveal&lt;/span&gt;),
    ]&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/secret-santa/{slug}&lt;/code&gt; is the main page for a Secret Santa group. It shows a list of participants and a form to add a new participant.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/secret-santa/{slug}/add&lt;/code&gt; is the endpoint for a form that adds a new participant.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/secret-santa/{slug}/set-password/{id}&lt;/code&gt; is the page that lets a user generate and retrieve their password.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/secret-santa/{slug}/reveal/{id}&lt;/code&gt; is the page where a user enters their password to reveal their Secret Santa assignment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/secret-santa/{slug}/assign&lt;/code&gt; is the endpoint that does the work of assigning participants to each other, and generating and saving encrypted message for each of them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;The cryptography&lt;/h4&gt;
&lt;p&gt;The earlier warning holds firm here: I am not a cryptographer. I'm just having fun. You should not imitate any of the code I wrote here without thoroughly reviewing it with someone who knows what they're doing.&lt;/p&gt;
&lt;p&gt;(I also used ChatGPT to write my first drafts of it, as &lt;a href="https://github.com/simonw/datasette-secret-santa/issues/1#issuecomment-1345348032"&gt;described in this issue&lt;/a&gt;. Trusting cryptographic code generated by a large language model is a particularly bad idea!)&lt;/p&gt;
&lt;p&gt;Disclaimers out of the way, here's &lt;a href="https://github.com/simonw/datasette-secret-santa/blob/18995be276a0fff99cf2f788cc15ac409465231d/datasette_secret_santa/__init__.py#L246-L280"&gt;the code&lt;/a&gt; I wrote to generate and store the RSA keys:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;async&lt;/span&gt; &lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;generate_password_and_keys_for_user&lt;/span&gt;(&lt;span class="pl-s1"&gt;db&lt;/span&gt;, &lt;span class="pl-s1"&gt;participant_id&lt;/span&gt;):
    &lt;span class="pl-s1"&gt;password&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;" "&lt;/span&gt;.&lt;span class="pl-en"&gt;join&lt;/span&gt;(&lt;span class="pl-s1"&gt;random&lt;/span&gt;.&lt;span class="pl-en"&gt;sample&lt;/span&gt;(&lt;span class="pl-s1"&gt;words&lt;/span&gt;, &lt;span class="pl-c1"&gt;3&lt;/span&gt;))

    &lt;span class="pl-s1"&gt;private_key&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;rsa&lt;/span&gt;.&lt;span class="pl-en"&gt;generate_private_key&lt;/span&gt;(&lt;span class="pl-s1"&gt;public_exponent&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;65537&lt;/span&gt;, &lt;span class="pl-s1"&gt;key_size&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;2048&lt;/span&gt;)
    &lt;span class="pl-s1"&gt;public_key&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;private_key&lt;/span&gt;.&lt;span class="pl-en"&gt;public_key&lt;/span&gt;()

    &lt;span class="pl-c"&gt;# Serialize the keys for storage&lt;/span&gt;
    &lt;span class="pl-s1"&gt;private_key_serialized&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;private_key&lt;/span&gt;.&lt;span class="pl-en"&gt;private_bytes&lt;/span&gt;(
        &lt;span class="pl-s1"&gt;encoding&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;serialization&lt;/span&gt;.&lt;span class="pl-v"&gt;Encoding&lt;/span&gt;.&lt;span class="pl-v"&gt;PEM&lt;/span&gt;,
        &lt;span class="pl-s1"&gt;format&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;serialization&lt;/span&gt;.&lt;span class="pl-v"&gt;PrivateFormat&lt;/span&gt;.&lt;span class="pl-v"&gt;PKCS8&lt;/span&gt;,
        &lt;span class="pl-s1"&gt;encryption_algorithm&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;serialization&lt;/span&gt;.&lt;span class="pl-v"&gt;BestAvailableEncryption&lt;/span&gt;(
            &lt;span class="pl-s1"&gt;password&lt;/span&gt;.&lt;span class="pl-en"&gt;encode&lt;/span&gt;(&lt;span class="pl-s"&gt;"utf-8"&lt;/span&gt;)
        ),
    ).&lt;span class="pl-en"&gt;decode&lt;/span&gt;(&lt;span class="pl-s"&gt;"utf-8"&lt;/span&gt;)
    &lt;span class="pl-s1"&gt;public_key_serialized&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;public_key&lt;/span&gt;.&lt;span class="pl-en"&gt;public_bytes&lt;/span&gt;(
        &lt;span class="pl-s1"&gt;encoding&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;serialization&lt;/span&gt;.&lt;span class="pl-v"&gt;Encoding&lt;/span&gt;.&lt;span class="pl-v"&gt;PEM&lt;/span&gt;,
        &lt;span class="pl-s1"&gt;format&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;serialization&lt;/span&gt;.&lt;span class="pl-v"&gt;PublicFormat&lt;/span&gt;.&lt;span class="pl-v"&gt;SubjectPublicKeyInfo&lt;/span&gt;,
    ).&lt;span class="pl-en"&gt;decode&lt;/span&gt;(&lt;span class="pl-s"&gt;"utf-8"&lt;/span&gt;)

    &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-s1"&gt;db&lt;/span&gt;.&lt;span class="pl-en"&gt;execute_write&lt;/span&gt;(
        &lt;span class="pl-s"&gt;"""&lt;/span&gt;
&lt;span class="pl-s"&gt;        update secret_santa_participants&lt;/span&gt;
&lt;span class="pl-s"&gt;        set&lt;/span&gt;
&lt;span class="pl-s"&gt;            password_issued_at = datetime('now'),&lt;/span&gt;
&lt;span class="pl-s"&gt;            public_key = :public_key,&lt;/span&gt;
&lt;span class="pl-s"&gt;            private_key = :private_key&lt;/span&gt;
&lt;span class="pl-s"&gt;        where id = :id&lt;/span&gt;
&lt;span class="pl-s"&gt;        """&lt;/span&gt;,
        {
            &lt;span class="pl-s"&gt;"id"&lt;/span&gt;: &lt;span class="pl-s1"&gt;participant_id&lt;/span&gt;,
            &lt;span class="pl-s"&gt;"public_key"&lt;/span&gt;: &lt;span class="pl-s1"&gt;public_key_serialized&lt;/span&gt;,
            &lt;span class="pl-s"&gt;"private_key"&lt;/span&gt;: &lt;span class="pl-s1"&gt;private_key_serialized&lt;/span&gt;,
        },
    )
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;password&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, it uses &lt;code&gt;rsa.generate_private_key()&lt;/code&gt; from the &lt;a href="https://cryptography.io/en/latest/"&gt;PyCA cryptography library&lt;/a&gt; to generate the public and private keys.&lt;/p&gt;
&lt;p&gt;The options &lt;code&gt;public_exponent=65537, key_size=2048&lt;/code&gt; are recommended by the &lt;a href="https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/#cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key"&gt; generate_private_key() documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It then serializes them to PEM format strings that can be stored in the database.&lt;/p&gt;
&lt;p&gt;The private key is serialized after being encrypted using the randomly generated password for that user. This produces a string that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had originally come up with &lt;a href="https://github.com/simonw/datasette-secret-santa/blob/cef3aed7afa523dc07190e7d735e46ecd61e4f5e/datasette_secret_santa/__init__.py#L269-L279"&gt;my own scheme for this&lt;/a&gt;, involving AES encryption and a key derived from a hash of the raw password (which I planned to later run through &lt;code&gt;bcrypt&lt;/code&gt; a few hundred thousand times) - I was very happy when &lt;a href="https://github.com/simonw/datasette-secret-santa/issues/3"&gt;I realized&lt;/a&gt; that there was a standard way to do this already.&lt;/p&gt;
&lt;p&gt;The code that then assigns the participants and generates their encrypted messages looks &lt;a href="https://github.com/simonw/datasette-secret-santa/blob/18995be276a0fff99cf2f788cc15ac409465231d/datasette_secret_santa/__init__.py#L311-L339"&gt;like this&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;# Assign participants&lt;/span&gt;
&lt;span class="pl-s1"&gt;random&lt;/span&gt;.&lt;span class="pl-en"&gt;shuffle&lt;/span&gt;(&lt;span class="pl-s1"&gt;participants&lt;/span&gt;)
&lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-s1"&gt;i&lt;/span&gt;, &lt;span class="pl-s1"&gt;participant&lt;/span&gt; &lt;span class="pl-c1"&gt;in&lt;/span&gt; &lt;span class="pl-en"&gt;enumerate&lt;/span&gt;(&lt;span class="pl-s1"&gt;participants&lt;/span&gt;):
    &lt;span class="pl-s1"&gt;assigned&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;participants&lt;/span&gt;[(&lt;span class="pl-s1"&gt;i&lt;/span&gt; &lt;span class="pl-c1"&gt;+&lt;/span&gt; &lt;span class="pl-c1"&gt;1&lt;/span&gt;) &lt;span class="pl-c1"&gt;%&lt;/span&gt; &lt;span class="pl-en"&gt;len&lt;/span&gt;(&lt;span class="pl-s1"&gt;participants&lt;/span&gt;)]
    &lt;span class="pl-s1"&gt;message&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"You should buy a gift for {}"&lt;/span&gt;.&lt;span class="pl-en"&gt;format&lt;/span&gt;(&lt;span class="pl-s1"&gt;assigned&lt;/span&gt;[&lt;span class="pl-s"&gt;"name"&lt;/span&gt;])
    &lt;span class="pl-c"&gt;# Encrypt the message with their public key&lt;/span&gt;
    &lt;span class="pl-s1"&gt;public_key&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;serialization&lt;/span&gt;.&lt;span class="pl-en"&gt;load_pem_public_key&lt;/span&gt;(
        &lt;span class="pl-s1"&gt;participant&lt;/span&gt;[&lt;span class="pl-s"&gt;"public_key"&lt;/span&gt;].&lt;span class="pl-en"&gt;encode&lt;/span&gt;(&lt;span class="pl-s"&gt;"utf-8"&lt;/span&gt;), &lt;span class="pl-s1"&gt;backend&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-en"&gt;default_backend&lt;/span&gt;()
    )
    &lt;span class="pl-s1"&gt;secret_message_encrypted&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;public_key&lt;/span&gt;.&lt;span class="pl-en"&gt;encrypt&lt;/span&gt;(
        &lt;span class="pl-s1"&gt;message&lt;/span&gt;.&lt;span class="pl-en"&gt;encode&lt;/span&gt;(&lt;span class="pl-s"&gt;"utf-8"&lt;/span&gt;),
        &lt;span class="pl-s1"&gt;padding&lt;/span&gt;.&lt;span class="pl-v"&gt;OAEP&lt;/span&gt;(
            &lt;span class="pl-s1"&gt;mgf&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;padding&lt;/span&gt;.&lt;span class="pl-v"&gt;MGF1&lt;/span&gt;(&lt;span class="pl-s1"&gt;algorithm&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;hashes&lt;/span&gt;.&lt;span class="pl-v"&gt;SHA256&lt;/span&gt;()),
            &lt;span class="pl-s1"&gt;algorithm&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;hashes&lt;/span&gt;.&lt;span class="pl-v"&gt;SHA256&lt;/span&gt;(),
            &lt;span class="pl-s1"&gt;label&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;None&lt;/span&gt;,
        ),
    )
    &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-s1"&gt;db&lt;/span&gt;.&lt;span class="pl-en"&gt;execute_write&lt;/span&gt;(
        &lt;span class="pl-s"&gt;"""&lt;/span&gt;
&lt;span class="pl-s"&gt;        update secret_santa_participants&lt;/span&gt;
&lt;span class="pl-s"&gt;        set secret_message_encrypted = :secret_message_encrypted&lt;/span&gt;
&lt;span class="pl-s"&gt;        where id = :id&lt;/span&gt;
&lt;span class="pl-s"&gt;        """&lt;/span&gt;,
        {
            &lt;span class="pl-s"&gt;"id"&lt;/span&gt;: &lt;span class="pl-s1"&gt;participant&lt;/span&gt;[&lt;span class="pl-s"&gt;"id"&lt;/span&gt;],
            &lt;span class="pl-s"&gt;"secret_message_encrypted"&lt;/span&gt;: &lt;span class="pl-s1"&gt;secret_message_encrypted&lt;/span&gt;,
        },
    )&lt;/pre&gt;
&lt;p&gt;And finally, the code that &lt;a href="https://github.com/simonw/datasette-secret-santa/blob/18995be276a0fff99cf2f788cc15ac409465231d/datasette_secret_santa/__init__.py#L201-L220"&gt;decrypts the message&lt;/a&gt; when the user provides their password again:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;data&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-s1"&gt;request&lt;/span&gt;.&lt;span class="pl-en"&gt;post_vars&lt;/span&gt;()
&lt;span class="pl-s1"&gt;password&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;data&lt;/span&gt;.&lt;span class="pl-en"&gt;get&lt;/span&gt;(&lt;span class="pl-s"&gt;"password"&lt;/span&gt;, &lt;span class="pl-s"&gt;""&lt;/span&gt;).&lt;span class="pl-en"&gt;strip&lt;/span&gt;()
&lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-c1"&gt;not&lt;/span&gt; &lt;span class="pl-s1"&gt;password&lt;/span&gt;:
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;_error&lt;/span&gt;(
        &lt;span class="pl-s1"&gt;datasette&lt;/span&gt;, &lt;span class="pl-s1"&gt;request&lt;/span&gt;, &lt;span class="pl-s"&gt;"Please provide a password"&lt;/span&gt;, &lt;span class="pl-s1"&gt;status&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;400&lt;/span&gt;
    )
&lt;span class="pl-c"&gt;# Decrypt the private key with the password&lt;/span&gt;
&lt;span class="pl-k"&gt;try&lt;/span&gt;:
    &lt;span class="pl-s1"&gt;private_key&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;decrypt_private_key_for_user&lt;/span&gt;(&lt;span class="pl-s1"&gt;participant&lt;/span&gt;, &lt;span class="pl-s1"&gt;password&lt;/span&gt;)
&lt;span class="pl-k"&gt;except&lt;/span&gt; &lt;span class="pl-v"&gt;ValueError&lt;/span&gt;:
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;_error&lt;/span&gt;(&lt;span class="pl-s1"&gt;datasette&lt;/span&gt;, &lt;span class="pl-s1"&gt;request&lt;/span&gt;, &lt;span class="pl-s"&gt;"Incorrect password"&lt;/span&gt;, &lt;span class="pl-s1"&gt;status&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;400&lt;/span&gt;)
&lt;span class="pl-c"&gt;# Decrypt the secret message with the private key&lt;/span&gt;
&lt;span class="pl-s1"&gt;decrypted_message&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;private_key&lt;/span&gt;.&lt;span class="pl-en"&gt;decrypt&lt;/span&gt;(
    &lt;span class="pl-s1"&gt;participant&lt;/span&gt;[&lt;span class="pl-s"&gt;"secret_message_encrypted"&lt;/span&gt;],
    &lt;span class="pl-s1"&gt;padding&lt;/span&gt;.&lt;span class="pl-v"&gt;OAEP&lt;/span&gt;(
        &lt;span class="pl-s1"&gt;mgf&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;padding&lt;/span&gt;.&lt;span class="pl-v"&gt;MGF1&lt;/span&gt;(&lt;span class="pl-s1"&gt;algorithm&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;hashes&lt;/span&gt;.&lt;span class="pl-v"&gt;SHA256&lt;/span&gt;()),
        &lt;span class="pl-s1"&gt;algorithm&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;hashes&lt;/span&gt;.&lt;span class="pl-v"&gt;SHA256&lt;/span&gt;(),
        &lt;span class="pl-s1"&gt;label&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;None&lt;/span&gt;,
    ),
).&lt;span class="pl-en"&gt;decode&lt;/span&gt;(&lt;span class="pl-s"&gt;"utf-8"&lt;/span&gt;)&lt;/pre&gt;
&lt;h3&gt;And some snowflakes&lt;/h3&gt;
&lt;p&gt;I spent all of five minutes on the visual design for it - the main feature of which is a thick red top border on body followed by a thinner white border to make it look like its wearing a Santa hat.&lt;/p&gt;
&lt;p&gt;I did add some animated snowflakes though! I used &lt;a href="https://github.com/natbat/CSS-Snow"&gt;this script&lt;/a&gt; Natalie Downe built back in 2010. It works great!&lt;/p&gt;
&lt;h4&gt;Deploying it on Glitch&lt;/h4&gt;
&lt;p&gt;This kind of project is a really great fit for &lt;a href="https://glitch.com/"&gt;Glitch&lt;/a&gt;, which offers free hosting with persistent file storage - perfect for SQLite - provided you don't mind your projects going to sleep in between bouts of activity (unless you pay to "boost" them). A Secret Santa app is a perfect fit for this sort of hosting.&lt;/p&gt;
&lt;p&gt;(You can &lt;a href="https://glitch.com/~datasette-secret-santa"&gt;remix my project&lt;/a&gt; to get your own copy of the app (with your own database) by clicking the "Remix" button.)&lt;/p&gt;
&lt;p&gt;Since I had &lt;a href="https://pypi.org/project/datasette-secret-santa"&gt;shipped the plugin&lt;/a&gt; up to PyPI already, deploying it on Glitch was a matter of creating a new project there containing this single &lt;code&gt;glitch.json&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight highlight-source-json"&gt;&lt;pre&gt;{
  &lt;span class="pl-ent"&gt;"install"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;pip3 install --user datasette datasette-secret-santa -U&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"start"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;datasette --create .data/santa.db -p 3000&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This causes Glitch to install both &lt;code&gt;datasette&lt;/code&gt; and &lt;code&gt;datasette-secret-santa&lt;/code&gt; when the project first launches. It then starts the Datasette server running like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;datasette --create .data/santa.db -p 3000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;--create&lt;/code&gt; flag tells Datasette to create a new SQLite database if one doesn't already exist at that path. &lt;code&gt;.data/&lt;/code&gt; is a &lt;a href="https://glitch.happyfox.com/kb/article/22-do-you-have-built-in-persistence-or-a-database/"&gt;special directory&lt;/a&gt; on Glitch that won't have its contents automatically tracked using their version control.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-p 3000&lt;/code&gt; flag tells the server to listen on port 3000, which is the Glitch default - traffic to the subdomain for the app will automatically be routed to that port.&lt;/p&gt;
&lt;h4&gt;And the database is public&lt;/h4&gt;
&lt;p&gt;Here's a slightly surprising thing about this: the SQLite table containing all of the data - including the public keys and encrypted private keys - is visible for anyone with access to the instance to see!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://datasette-secret-santa.glitch.me/santa/secret_santa_participants"&gt;Here's that table&lt;/a&gt; for a demo I deployed on Glitch.&lt;/p&gt;
&lt;p&gt;Once again, I am by no means a cryptography expert, and this isn't something I would tolerate for any other application. But with the risk profile involved in a secret santa I think this is OK. I'm pretty sure you could brute force decrypt the private keys if you really wanted to, so it's a good thing they're not being used for anything else!&lt;/p&gt;
&lt;p&gt;(This is also one of the reasons I didn't let users pick their own passwords - by assigning generated passwords I can be 100% sure I don't accidentally end up holding onto an encrypted copy of a credential that could be used for anything else.)&lt;/p&gt;
&lt;h4&gt;Self-contained apps as plugins&lt;/h4&gt;
&lt;p&gt;Something I find interesting about this project is that it demonstrates how a Datasette plugin can be used to provide a full, self-contained app.&lt;/p&gt;
&lt;p&gt;I think this is a powerful pattern. It's a neat way to take advantage of the tools I've built to help make Datasette easy to deploy - not just on Glitch but &lt;a href="https://simonwillison.net/2022/Feb/15/fly-volumes/"&gt;on platforms like Fly&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;This is my first time using Datasette in this way and I found it to be a pleasantly productive way of building and deploying this kind of personal tool. I'm looking forward to trying this approach out for other projects in the future.&lt;/p&gt;
&lt;p&gt;And if you know cryptography and can spot any glaring (or subtle) holes in the way my system works, please &lt;a href="https://github.com/simonw/datasette-secret-santa/issues/new"&gt;open an issue&lt;/a&gt; and let me know!&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/glitch"&gt;glitch&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cryptography"/><category term="glitch"/><category term="projects"/><category term="datasette"/><category term="chatgpt"/><category term="llms"/><category term="ai-assisted-programming"/></entry><entry><title>Ok Google: please publish your DKIM secret keys</title><link href="https://simonwillison.net/2020/Nov/16/dkim/#atom-tag" rel="alternate"/><published>2020-11-16T22:02:58+00:00</published><updated>2020-11-16T22:02:58+00:00</updated><id>https://simonwillison.net/2020/Nov/16/dkim/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.cryptographyengineering.com/2020/11/16/ok-google-please-publish-your-dkim-secret-keys/amp/?__twitter_impression=true"&gt;Ok Google: please publish your DKIM secret keys&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The DKIM standard allows email providers such as Gmail to include cryptographic headers that protect against spoofing, proving that an email was sent by a specific host and has not been tampered with. But it has an unintended side effect: if someone’s email is leaked (as happened to John Podesta in 2016) DKIM headers can be used to prove the validity of the leaked emails. This makes DKIM an enabling factor for blackmail and other security breach related crimes.&lt;/p&gt;

&lt;p&gt;Matthew Green proposes a neat solution: providers like Gmail should rotate their DKIM keys frequently and publish the PRIVATE key after rotation. By enabling spoofing of past email headers they would provide deniability for victims of leaks, fixing this unintended consequence of the DKIM standard.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/matthew_d_green/status/1328371955150573568"&gt;@matthew_d_green&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/email"&gt;email&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="email"/><category term="security"/></entry><entry><title>Looking back at the Snowden revelations</title><link href="https://simonwillison.net/2019/Sep/25/looking-back-at-the-snowden-revelations/#atom-tag" rel="alternate"/><published>2019-09-25T05:48:39+00:00</published><updated>2019-09-25T05:48:39+00:00</updated><id>https://simonwillison.net/2019/Sep/25/looking-back-at-the-snowden-revelations/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.cryptographyengineering.com/2019/09/24/looking-back-at-the-snowden-revelations/"&gt;Looking back at the Snowden revelations&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Six years on from the Snowden revelations, crypto researcher Matthew Green reviews their impact and reminds us what we learned. Really interesting.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/matthew_d_green/status/1176617952076079109"&gt;@matthew_d_green&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="security"/></entry><entry><title>Verified cryptography for Firefox 57</title><link href="https://simonwillison.net/2017/Nov/16/verified-cryptography-for-firefox-57/#atom-tag" rel="alternate"/><published>2017-11-16T14:26:41+00:00</published><updated>2017-11-16T14:26:41+00:00</updated><id>https://simonwillison.net/2017/Nov/16/verified-cryptography-for-firefox-57/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.mozilla.org/security/2017/09/13/verified-cryptography-firefox-57/"&gt;Verified cryptography for Firefox 57&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Mozilla just became the first browser vendor to ship a formally verified crypto implementation.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/ttaubert/status/930463415558201349"&gt;Tim Taubert&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/firefox"&gt;firefox&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mozilla"&gt;mozilla&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="firefox"/><category term="mozilla"/></entry><entry><title>doc/beatings.txt</title><link href="https://simonwillison.net/2010/May/24/beatings/#atom-tag" rel="alternate"/><published>2010-05-24T14:17:00+00:00</published><updated>2010-05-24T14:17:00+00:00</updated><id>https://simonwillison.net/2010/May/24/beatings/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://iq.org/~proff/marutukku.org/current/src/doc/beatings.txt"&gt;doc/beatings.txt&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Rubberhose is a disk encryption system developed by the founder of Wikileaks that implements deniable cryptography—different keys reveal different parts of the encrypted data, and it is impossible to prove that all of the keys have been divulged. Here, Julian Assange explains how this works with a scenario involving Alice and the Rubber-hose-squad.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="http://iq.org/~proff/marutukku.org/"&gt;Rubberhose cryptographically deniable transparent disk encryption system&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/wikileaks"&gt;wikileaks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/recovered"&gt;recovered&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coercion"&gt;coercion&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/julian-assange"&gt;julian-assange&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rubberhose"&gt;rubberhose&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="wikileaks"/><category term="recovered"/><category term="coercion"/><category term="julian-assange"/><category term="rubberhose"/></entry><entry><title>Don't Hash Secrets</title><link href="https://simonwillison.net/2010/Jan/24/benlog/#atom-tag" rel="alternate"/><published>2010-01-24T13:30:58+00:00</published><updated>2010-01-24T13:30:58+00:00</updated><id>https://simonwillison.net/2010/Jan/24/benlog/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://benlog.com/articles/2008/06/19/dont-hash-secrets/"&gt;Don&amp;#x27;t Hash Secrets&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
A well written explanation from 2008 of why you must use hmac instead of raw SHA-1 when hashing against a secret.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hmac"&gt;hmac&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sha1"&gt;sha1&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/signing"&gt;signing&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="hmac"/><category term="security"/><category term="sha1"/><category term="signing"/></entry><entry><title>Timing attack in Google Keyczar library</title><link href="https://simonwillison.net/2010/Jan/4/timing/#atom-tag" rel="alternate"/><published>2010-01-04T15:23:32+00:00</published><updated>2010-01-04T15:23:32+00:00</updated><id>https://simonwillison.net/2010/Jan/4/timing/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/"&gt;Timing attack in Google Keyczar library&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
An issue I also need to fix in the proposed Django signing code. If you’re comparing two strings in crypto (e.g. seeing if the provided signature matches the expected signature) you need to use a timing independent string comparison function or you risk leaking information. This kind of thing is exactly why I want an audited signing module in Django rather than leaving developers to figure it out on their own.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/keyczar"&gt;keyczar&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/signing"&gt;signing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/timing-attack"&gt;timing-attack&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="django"/><category term="keyczar"/><category term="python"/><category term="security"/><category term="signing"/><category term="timing-attack"/></entry><entry><title>Design and code review requested for Django string signing / signed cookies</title><link href="https://simonwillison.net/2010/Jan/4/codereview/#atom-tag" rel="alternate"/><published>2010-01-04T13:24:50+00:00</published><updated>2010-01-04T13:24:50+00:00</updated><id>https://simonwillison.net/2010/Jan/4/codereview/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/297e8b22006f7f3a"&gt;Design and code review requested for Django string signing / signed cookies&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Do you know your way around web app security and cryptography (in particular signing things using hmac and sha1)? We’d appreciate your help reviewing the usage of these concepts in Django’s proposed string signing and signed cookie implementations.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/code-review"&gt;code-review&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hashing"&gt;hashing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hmac"&gt;hmac&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sha1"&gt;sha1&lt;/a&gt;&lt;/p&gt;



</summary><category term="code-review"/><category term="cryptography"/><category term="django"/><category term="hashing"/><category term="hmac"/><category term="python"/><category term="security"/><category term="sha1"/></entry><entry><title>Intercepting Predator Video</title><link href="https://simonwillison.net/2009/Dec/24/schneier/#atom-tag" rel="alternate"/><published>2009-12-24T21:26:26+00:00</published><updated>2009-12-24T21:26:26+00:00</updated><id>https://simonwillison.net/2009/Dec/24/schneier/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.schneier.com/blog/archives/2009/12/intercepting_pr.html"&gt;Intercepting Predator Video&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Bruce Schneier’s take on the unencrypted Predator UAV story. A fascinating discussion of key management and the non-technical side of cryptography.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/bruce-schneier"&gt;bruce-schneier&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/drones"&gt;drones&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/military"&gt;military&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nsa"&gt;nsa&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="bruce-schneier"/><category term="cryptography"/><category term="drones"/><category term="military"/><category term="nsa"/><category term="security"/></entry><entry><title>Notes from the No Lone Zone</title><link href="https://simonwillison.net/2009/Dec/16/titans/#atom-tag" rel="alternate"/><published>2009-12-16T10:02:38+00:00</published><updated>2009-12-16T10:02:38+00:00</updated><id>https://simonwillison.net/2009/Dec/16/titans/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.crypto.com/blog/titans/"&gt;Notes from the No Lone Zone&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
A computer scientist with a background in cryptography visits a Titan II ICBM launch complex.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/coldwar"&gt;coldwar&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/history"&gt;history&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/icbm"&gt;icbm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="coldwar"/><category term="cryptography"/><category term="history"/><category term="icbm"/><category term="security"/></entry><entry><title>openstreetmap genuine advantage</title><link href="https://simonwillison.net/2009/Sep/29/crypto/#atom-tag" rel="alternate"/><published>2009-09-29T09:49:52+00:00</published><updated>2009-09-29T09:49:52+00:00</updated><id>https://simonwillison.net/2009/Sep/29/crypto/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://mike.teczno.com/notes/gosm.html"&gt;openstreetmap genuine advantage&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The OpenStreetMap data model (points, ways and relations, all allowing arbitrary key/value tags) is a real thing of beauty—simple to understand but almost infinitely extensible. Mike Migurski’s latest project adds PGP signing to OpenStreetMap, allowing organisations (such as local government) to add a signature to a way (a sequence of points) and a subset of its tags, then write that signature in to a new tag on the object.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/geospatial"&gt;geospatial&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mapping"&gt;mapping&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/michal-migurski"&gt;michal-migurski&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openstreetmap"&gt;openstreetmap&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pgp"&gt;pgp&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="geospatial"/><category term="mapping"/><category term="michal-migurski"/><category term="openstreetmap"/><category term="pgp"/></entry><entry><title>Django ponies: Proposals for Django 1.2</title><link href="https://simonwillison.net/2009/Sep/28/ponies/#atom-tag" rel="alternate"/><published>2009-09-28T23:32:04+00:00</published><updated>2009-09-28T23:32:04+00:00</updated><id>https://simonwillison.net/2009/Sep/28/ponies/#atom-tag</id><summary type="html">
    &lt;p&gt;I've decided to step up my involvement in Django development in the run-up to Django 1.2, so I'm currently going through several years worth of accumulated pony requests figuring out which ones are worth advocating for. I'm also ensuring I have the code to back them up - my innocent &lt;a href="http://code.djangoproject.com/wiki/AutoEscaping"&gt;AutoEscaping proposal&lt;/a&gt; a few years ago resulted in an enormous amount of work by Malcolm and I don't think he'd appreciate a repeat performance.&lt;/p&gt;

&lt;p&gt;I'm not a big fan of branches when it comes to exploratory development - they're fine for doing the final implementation once an approach has been agreed, but I don't think they are a very effective way of discussing proposals. I'd much rather see working code in a separate application - that way I can try it out with an existing project without needing to switch to a new Django branch. Keeping code out of a branch also means people can start using it for real development work, making the API much easier to evaluate. Most of my proposals here have accompanying applications on GitHub.&lt;/p&gt;

&lt;p&gt;I've recently got in to the habit of including an "examples" directory with each of my experimental applications. This is a full Django project (with settings.py, urls.py and manage.py files) which serves two purposes. Firstly, it allows developers to run the application's unit tests without needing to install it in to their own pre-configured project, simply by changing in to the examples directory and running &lt;samp&gt;./manage.py test&lt;/samp&gt;. Secondly, it gives me somewhere to put demonstration code that can be viewed in a browser using the runserver command - a further way of making the code easier to evaluate. &lt;a href="http://github.com/simonw/django-safeform"&gt;django-safeform&lt;/a&gt; is a good example of this pattern.&lt;/p&gt;

&lt;p&gt;Here's my current list of ponies, in rough order of priority.&lt;/p&gt;

&lt;h4&gt;Signing and signed cookies&lt;/h4&gt;

&lt;p&gt;Signing strings to ensure they have not yet been tampered with is a crucial technique in web application security. As with all cryptography, it's also surprisingly difficult to do correctly. &lt;a href="http://vnhacker.blogspot.com/2009/09/flickrs-api-signature-forgery.html"&gt;A vulnerability in the signing implementation&lt;/a&gt; used to protect the Flickr API was revealed just today.&lt;/p&gt;

&lt;p&gt;One of the many uses of signed strings is to implement signed cookies. Signed cookies are fantastically powerful - they allow you to send cookies safe in the knowledge that your user will not be able to alter them without you knowing. This dramatically reduces the need for sessions - most web apps use sessions for security rather than for storing large amounts of data, so moving that "logged in user ID" value to a signed cookie eliminates the need for session storage entirely, saving a round-trip to persistent storage on every request.&lt;/p&gt;

&lt;p&gt;This has particularly useful implications for scaling - you can push your shared secret out to all of your front end web servers and scale horizontally, with no need for shared session storage just to handle simple authentication and "You are logged in as X" messages.&lt;/p&gt;

&lt;p&gt;The latest version of my &lt;a href="http://github.com/simonw/django-openid"&gt;django-openid&lt;/a&gt; library uses signed cookies to store the OpenID you log in with, removing the need to configure Django's session storage. I've extracted that code in to &lt;a href="http://github.com/simonw/django-signed"&gt;django-signed&lt;/a&gt;, which I hope to evolve in to something suitable for inclusion in &lt;samp&gt;django.utils&lt;/samp&gt;.&lt;/p&gt;

&lt;p&gt;Please note that django-signed has not yet been vetted by cryptography specialists, something I plan to fix before proposing it for final inclusion in core.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://github.com/simonw/django-signed"&gt;django-signed&lt;/a&gt; on GitHub&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://code.djangoproject.com/wiki/Signing"&gt;Details of the Signing proposal&lt;/a&gt; on the Django wiki&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/133509246caf1d91"&gt;Signing discussion&lt;/a&gt; on the django-developers mailing list&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Improved CSRF support&lt;/h4&gt;

&lt;p&gt;This is mainly Luke Plant's pony, but I'm very keen to see it happen. Django has shipped with CSRF protection for &lt;a href="http://code.djangoproject.com/changeset/2868"&gt;more than three years now&lt;/a&gt;, but the approach (using middleware to rewrite form HTML) is relatively crude and, crucially, the protection isn't turned on by default. Hint: if you aren't 100% positive you are protected against &lt;a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery"&gt;CSRF&lt;/a&gt;, you should probably go and turn it on.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://bitbucket.org/spookylukey/django-trunk-lukeplant/src/05f0530f3207/django/contrib/csrf/"&gt;Luke's approach&lt;/a&gt; is an iterative improvement - a template tag (with a dependency on RequestContext) is used to output the hidden CSRF field, with middleware used to set the cookie and perform the extra validation. I experimented at length with an alternative solution based around extending Django's form framework to treat CSRF as just another aspect of validation - you can see the result in my &lt;a href="http://github.com/simonw/django-safeform"&gt;django-safeform&lt;/a&gt; project. My approach avoids middleware and template tags in favour of a view decorator to set the cookie and a class decorator to add a CSRF check to the form itself.&lt;/p&gt;

&lt;p&gt;While my approach works, the effort involved in upgrading existing code to it is substantial, compared to a much easier upgrade path for Luke's middleware + template tag approach. The biggest advantage of safeform is that it allows CSRF failure messages to be shown inline on the form, without losing the user's submission - the middleware check means showing errors as a full page without redisplaying the form. It looks like it should be possible to bring that aspect of safeform back to the middleware approach, and I plan to put together a patch for that over the next few days.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Luke's &lt;a href="http://bitbucket.org/spookylukey/django-trunk-lukeplant/src/05f0530f3207/django/contrib/csrf/"&gt;CSRF branch&lt;/a&gt; on bitbucket&lt;/li&gt;
    &lt;li&gt;My &lt;a href="http://github.com/simonw/django-signed"&gt;django-safeform&lt;/a&gt; on GitHub&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://code.djangoproject.com/wiki/CsrfProtection"&gt;Details of the CSRF proposal&lt;/a&gt; on the Django wiki&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/3d2dc750082103dc"&gt;CSRF discussion&lt;/a&gt; on the django-developers mailing list&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Better support for outputting HTML&lt;/h4&gt;

&lt;p&gt;This is a major pet peeve of mine. Django's form framework is excellent - one of the best features of the framework. There's just one thing that bugs me about it - it outputs full form widgets (for &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt; and the like) so that it can include the previous value when redisplaying a form during validation, but it does so using XHTML syntax.&lt;/p&gt;

&lt;p&gt;I have a strong preference for an HTML 4.01 strict doctype, and all those &amp;lt;self-closing-tags /&amp;gt; have been niggling away at me for literally &lt;em&gt;years&lt;/em&gt;. Django bills itself as a framework for "perfectionists with deadlines", so I feel justified in getting wound up out of proportion over this one.&lt;/p&gt;

&lt;p&gt;A year ago I started experimenting with a solution, and came up with &lt;a href="http://github.com/simonw/django-html"&gt;django-html&lt;/a&gt;. It introduces two new Django template tags - &lt;code&gt;{% doctype %}&lt;/code&gt; and &lt;code&gt;{% field %}&lt;/code&gt;. The doctype tag serves two purposes - it outputs a particular doctype (saving you from having to remember the syntax) and it records that doctype in Django's template context object. The field tag is then used to output form fields, but crucially it gets to take the current doctype in to account.&lt;/p&gt;

&lt;p&gt;The field tag can also be used to add extra HTML attributes to form widgets from within the template itself, solving another small frustration about the existing form library. The &lt;a href="http://github.com/simonw/django-html/blob/master/README.rst"&gt;README&lt;/a&gt; describes the new tags in detail.&lt;/p&gt;

&lt;p&gt;The way the tags work is currently a bit of a hack - if merged in to Django core they could be more cleanly implemented by refactoring the form library slightly. This refactoring is currently being discussed on the mailing list.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://github.com/simonw/django-html"&gt;django-html&lt;/a&gt; on GitHub&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/bbf75f0eeaf9fa64"&gt;Improved HTML discussion&lt;/a&gt; on the django-developers mailing list&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Logging&lt;/h4&gt;

&lt;p&gt;This is the only proposal for which I don't yet have any code. I want to add official support for Python's standard logging framework to Django. It's possible to use this at the moment (I've done so on several projects) but it's not at all clear what the best way of doing so is, and Django doesn't use it internally at all. I posted a &lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/8551ecdb7412ab22"&gt;full argument in favour of logging&lt;/a&gt; to the mailing list, but my favourite argument is this one:&lt;/p&gt;

&lt;blockquote cite="http://groups.google.com/group/django-developers/browse_thread/thread/8551ecdb7412ab22"&gt;&lt;p&gt;Built-in support for logging reflects a growing reality of modern Web development: more and more sites have interfaces with external web service APIs, meaning there are plenty of things that could go wrong that are outside the control of the developer. Failing gracefully and logging what happened is the best way to deal with 3rd party problems - much better than throwing a 500 and leaving no record of what went wrong.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I'm not actively pursuing this one yet, but I'm very interesting in hearing people's opinions on the best way to configure and use the Python logging module in production.&lt;/p&gt;

&lt;h4&gt;A replacement for get_absolute_url()&lt;/h4&gt;

&lt;p&gt;Django has a loose convention of encouraging people to add a &lt;code&gt;get_absolute_url&lt;/code&gt; method to their models that returns that object's URL. It's a controversial feature - for one thing, it's a bit of a layering violation since URL logic is meant to live in the &lt;samp&gt;urls.py&lt;/samp&gt; file. It's incredibly convenient though, and since it's good web citizenship for everything to have one and only one URL I think there's a pretty good argument for keeping it.&lt;/p&gt;

&lt;p&gt;The problem is, the name sucks. I first took a look at this in the last few weeks before the release of Django 1.0 - what started as a quick proposal to come up with a better name before we were stuck with it quickly descended in to a quagmire as I realised quite how broken &lt;code&gt;get_absolute_url()&lt;/code&gt; is. The short version: in some cases it means "get a relative URL starting with /", in other cases it means "get a full URL starting with http://" and the name doesn't accurately describe either.&lt;/p&gt;

&lt;p&gt;A full write-up of my investigation is &lt;a href="http://code.djangoproject.com/wiki/ReplacingGetAbsoluteUrl"&gt;available on the Wiki&lt;/a&gt;. My proposed solution was to replace it with two complementary methods - &lt;code&gt;get_url()&lt;/code&gt; and &lt;code&gt;get_url_path()&lt;/code&gt; - with the user implementing one hence allowing the other one to be automatically derived. My &lt;a href="http://github.com/simonw/django-urls"&gt;django-urls&lt;/a&gt; project illustrates the concept via a model mixin class. A year on I still think it's quite a neat idea, though as far as I can tell no one has ever actually used it.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://code.djangoproject.com/wiki/ReplacingGetAbsoluteUrl"&gt;ReplacingGetAbsoluteUrl&lt;/a&gt; on the wiki&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://github.com/simonw/django-urls"&gt;django-urls&lt;/a&gt; on GitHub&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/7e69c39c23ec1079"&gt;Recent get_absolute_url discussion&lt;/a&gt; on the django-developers mailing list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comments on this post are open, but if you have anything to say about any of the individual proposals it would be much more useful if you posted it to the relevant mailing list thread.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cookies"&gt;cookies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/csrf"&gt;csrf&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/html"&gt;html&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/logging"&gt;logging&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/luke-plant"&gt;luke-plant&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/markup"&gt;markup&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ponies"&gt;ponies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/signedcookies"&gt;signedcookies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/signing"&gt;signing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/xhtml"&gt;xhtml&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cookies"/><category term="cryptography"/><category term="csrf"/><category term="django"/><category term="html"/><category term="logging"/><category term="luke-plant"/><category term="markup"/><category term="ponies"/><category term="projects"/><category term="python"/><category term="security"/><category term="signedcookies"/><category term="signing"/><category term="xhtml"/></entry><entry><title>Adding signing (and signed cookies) to Django core</title><link href="https://simonwillison.net/2009/Sep/24/signing/#atom-tag" rel="alternate"/><published>2009-09-24T19:31:20+00:00</published><updated>2009-09-24T19:31:20+00:00</updated><id>https://simonwillison.net/2009/Sep/24/signing/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/133509246caf1d91"&gt;Adding signing (and signed cookies) to Django core&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I’ve been increasing my participation in Django recently—here’s my proposal for adding signing and signed cookies to Django, which I’d personally like to see ship as part of Django 1.2.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cookies"&gt;cookies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/signedcookies"&gt;signedcookies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/signing"&gt;signing&lt;/a&gt;&lt;/p&gt;



</summary><category term="cookies"/><category term="cryptography"/><category term="django"/><category term="security"/><category term="signedcookies"/><category term="signing"/></entry><entry><title>NaCl: Networking and Cryptography library</title><link href="https://simonwillison.net/2009/Jul/16/nacl/#atom-tag" rel="alternate"/><published>2009-07-16T20:24:50+00:00</published><updated>2009-07-16T20:24:50+00:00</updated><id>https://simonwillison.net/2009/Jul/16/nacl/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://nacl.cace-project.eu/"&gt;NaCl: Networking and Cryptography library&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
A new high level cryptography library. “NaCl advances the state of the art by improving security, by improving usability and by improving speed.” Ambitious claims, but DJB is one of the core maintainers.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/djb"&gt;djb&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nacl"&gt;nacl&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="djb"/><category term="nacl"/><category term="security"/></entry><entry><title>Cryptographic Right Answers</title><link href="https://simonwillison.net/2009/Jun/11/cryptographic/#atom-tag" rel="alternate"/><published>2009-06-11T22:16:25+00:00</published><updated>2009-06-11T22:16:25+00:00</updated><id>https://simonwillison.net/2009/Jun/11/cryptographic/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html"&gt;Cryptographic Right Answers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Best practise recommendations for cryptography: “While some people argue that you should never use cryptographic primitives directly and that trying to teach people cryptography just makes them more likely to shoot themselves in their proverbial feet, I come from a proud academic background and am sufficiently optimistic about humankind that I think it’s a good idea to spread some knowledge around.”


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/aes"&gt;aes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/colinpercival"&gt;colinpercival&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hashing"&gt;hashing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="aes"/><category term="colinpercival"/><category term="cryptography"/><category term="hashing"/><category term="security"/></entry><entry><title>Django snippets: Sign a string using SHA1, then shrink it using url-safe base65</title><link href="https://simonwillison.net/2008/Aug/27/snippets/#atom-tag" rel="alternate"/><published>2008-08-27T22:18:49+00:00</published><updated>2008-08-27T22:18:49+00:00</updated><id>https://simonwillison.net/2008/Aug/27/snippets/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.djangosnippets.org/snippets/1004/"&gt;Django snippets: Sign a string using SHA1, then shrink it using url-safe base65&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I needed a way to create tamper-proof URLs and cookies by signing them, but didn’t want the overhead of a full 40 character SHA1 hash. After some experimentation, it turns out you can knock a 40 char hash down to 27 characters by encoding it using a custom base65 encoding which only uses URL-safe characters.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/base65"&gt;base65&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cookies"&gt;cookies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django-snippets"&gt;django-snippets&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hashes"&gt;hashes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sha1"&gt;sha1&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/signedcookies"&gt;signedcookies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/urls"&gt;urls&lt;/a&gt;&lt;/p&gt;



</summary><category term="base65"/><category term="cookies"/><category term="cryptography"/><category term="django"/><category term="django-snippets"/><category term="hashes"/><category term="python"/><category term="security"/><category term="sha1"/><category term="signedcookies"/><category term="urls"/></entry><entry><title>Quoting Bruce Schneier</title><link href="https://simonwillison.net/2007/Nov/16/schneier/#atom-tag" rel="alternate"/><published>2007-11-16T10:25:42+00:00</published><updated>2007-11-16T10:25:42+00:00</updated><id>https://simonwillison.net/2007/Nov/16/schneier/#atom-tag</id><summary type="html">
    &lt;blockquote cite="http://www.schneier.com/blog/archives/2007/11/the_strange_sto.html"&gt;&lt;p&gt;I don't understand why the NSA was so insistent about including Dual_EC_DRBG in the standard. It makes no sense as a trap door: It's public, and rather obvious. It makes no sense from an engineering perspective: It's too slow for anyone to willingly use it. And it makes no sense from a backwards-compatibility perspective: Swapping one random-number generator for another is easy.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="http://www.schneier.com/blog/archives/2007/11/the_strange_sto.html"&gt;Bruce Schneier&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/bruce-schneier"&gt;bruce-schneier&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/dualecdrbg"&gt;dualecdrbg&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nsa"&gt;nsa&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/randomnumbers"&gt;randomnumbers&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="bruce-schneier"/><category term="cryptography"/><category term="dualecdrbg"/><category term="nsa"/><category term="randomnumbers"/><category term="security"/></entry><entry><title>The Beauty Of The Diffie-Hellman Protocol</title><link href="https://simonwillison.net/2007/Mar/1/beauty/#atom-tag" rel="alternate"/><published>2007-03-01T22:08:46+00:00</published><updated>2007-03-01T22:08:46+00:00</updated><id>https://simonwillison.net/2007/Mar/1/beauty/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://programming.reddit.com/info/177de/comments"&gt;The Beauty Of The Diffie-Hellman Protocol&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Some useful explanations here. Diffie-Hellman is used by OpenID to establish a shared secret between the provider and the consumer.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/diffiehellman"&gt;diffiehellman&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openid"&gt;openid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/reddit"&gt;reddit&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/><category term="diffiehellman"/><category term="openid"/><category term="reddit"/></entry><entry><title>James Randi owes me a million dollars</title><link href="https://simonwillison.net/2007/Jan/30/randi/#atom-tag" rel="alternate"/><published>2007-01-30T01:10:50+00:00</published><updated>2007-01-30T01:10:50+00:00</updated><id>https://simonwillison.net/2007/Jan/30/randi/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.crypto.com/blog/psychic_cryptanalysis/"&gt;James Randi owes me a million dollars&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Interesting case study in cryptographic bit commitment protocols, which allow something to be published that can later prove the authenticity of a revealed secret.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="http://reddit.com/info/11qhc/comments"&gt;reddit&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;&lt;/p&gt;



</summary><category term="cryptography"/></entry><entry><title>Easy Python Cryptography</title><link href="https://simonwillison.net/2003/Apr/14/ezPyCrypto/#atom-tag" rel="alternate"/><published>2003-04-14T11:04:05+00:00</published><updated>2003-04-14T11:04:05+00:00</updated><id>https://simonwillison.net/2003/Apr/14/ezPyCrypto/#atom-tag</id><summary type="html">
    &lt;p&gt;Via Garth Kidd's &lt;a href="http://www.deadlybloodyserious.com/Python/2003/04/14.html" title="14 Apr 2003"&gt;Python cryptography roundup&lt;/a&gt;, &lt;a href="http://www.freenet.org.nz/ezPyCrypto/"&gt;ezPyCrypto&lt;/a&gt; is a cryptography API so simple even I can use it. Unfortunately the example code is only available in the download archive (not on the web site) but here's an overview of how it works:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import ezPyCrypto
# Generate a 512 bit key
key = ezPyCrypto.key(512)

text = 'This will be encrypted'

# Encrypt the string
encrypted = key.encString(text)
print encrypted

# Unencrypt the string
decrypted = key.decString(encrypted)
print decrypted

# Export the public key
public = key.exportKey()
# This can now be saved or distributed

# Export the private key
private = key.exportKeyPrivate()
# This can now be saved somewhere safe

# Encrypting using an already generated public key:
key = ezPyCrypto.key()
key.importKey(public)
encrypted = key.encString(text)

# Decrypting using an already generated private key:
key = ezPyCrypto.key()
key.importKey(private)
decrypted = key.decString(text)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's pretty much it. The class also has support for passphrases which can be used to add an extra layer of protection to a private key, as well as methods to handle crypotgraphic signing and verification.&lt;/p&gt;

&lt;p&gt;ezPyCrypto is an easy to use wrapper for the excellent &lt;a href="http://www.amk.ca/python/code/crypto.html"&gt;PyCrypto&lt;/a&gt; module, and includes PyCrypto (and a handy Windows installer) in the distribution.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cryptography"/><category term="python"/></entry></feed>