diff --git a/README.md b/README.md
index cb6c8898b40adf0e277d475c295eea2faef13fbd..d0daba4bd7694acae8fccd66811767d663ab3531 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,7 @@ $ make doc
 
 <table width="100%" border="0" summary="list of modules">
 <tr><td><a href="https://lab.baconsvin.org/talla/onion/blob/develop/doc/onion_aes.md" class="module">onion_aes</a></td></tr>
+<tr><td><a href="https://lab.baconsvin.org/talla/onion/blob/develop/doc/onion_authenticate_cell.md" class="module">onion_authenticate_cell</a></td></tr>
 <tr><td><a href="https://lab.baconsvin.org/talla/onion/blob/develop/doc/onion_base16.md" class="module">onion_base16</a></td></tr>
 <tr><td><a href="https://lab.baconsvin.org/talla/onion/blob/develop/doc/onion_base32.md" class="module">onion_base32</a></td></tr>
 <tr><td><a href="https://lab.baconsvin.org/talla/onion/blob/develop/doc/onion_base64.md" class="module">onion_base64</a></td></tr>
diff --git a/doc/README.md b/doc/README.md
index 82fab387f7203bff5f9ef5565397509f783a58c8..2b59d74445382e3ffdcec14413995e21a9cfc02e 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -27,6 +27,7 @@ $ make doc
 
 <table width="100%" border="0" summary="list of modules">
 <tr><td><a href="onion_aes.md" class="module">onion_aes</a></td></tr>
+<tr><td><a href="onion_authenticate_cell.md" class="module">onion_authenticate_cell</a></td></tr>
 <tr><td><a href="onion_base16.md" class="module">onion_base16</a></td></tr>
 <tr><td><a href="onion_base32.md" class="module">onion_base32</a></td></tr>
 <tr><td><a href="onion_base64.md" class="module">onion_base64</a></td></tr>
diff --git a/doc/onion_authenticate_cell.md b/doc/onion_authenticate_cell.md
new file mode 100644
index 0000000000000000000000000000000000000000..0a9c604829f7beb3f51d831b05bedf17e7512487
--- /dev/null
+++ b/doc/onion_authenticate_cell.md
@@ -0,0 +1,50 @@
+
+
+# Module onion_authenticate_cell #
+* [Description](#description)
+* [Data Types](#types)
+* [Function Index](#index)
+* [Function Details](#functions)
+
+Onion Authenticate Cell Utilities.
+
+__Authors:__ Alexander Færøy ([`ahf@0x90.dk`](mailto:ahf@0x90.dk)).
+
+<a name="types"></a>
+
+## Data Types ##
+
+
+
+
+### <a name="type-config">config()</a> ###
+
+
+<pre><code>
+config() = #{client_identity_public_key =&gt; <a href="onion_rsa.md#type-public_key">onion_rsa:public_key()</a>, server_identity_public_key =&gt; <a href="onion_rsa.md#type-public_key">onion_rsa:public_key()</a>, server_log =&gt; binary(), client_log =&gt; binary(), server_certificate =&gt; <a href="public_key.md#type-der_encoded">public_key:der_encoded()</a>, ssl_session =&gt; <a href="onion_ssl_session.md#type-t">onion_ssl_session:t()</a>, authentication_secret_key =&gt; <a href="onion_rsa.md#type-secret_key">onion_rsa:secret_key()</a>}
+</code></pre>
+
+<a name="index"></a>
+
+## Function Index ##
+
+
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#create-1">create/1</a></td><td>Create an authenticate cell from the given configuration.</td></tr></table>
+
+
+<a name="functions"></a>
+
+## Function Details ##
+
+<a name="create-1"></a>
+
+### create/1 ###
+
+<pre><code>
+create(Config) -&gt; <a href="onion_cell.md#type-t">onion_cell:t()</a>
+</code></pre>
+
+<ul class="definitions"><li><code>Config = <a href="#type-config">config()</a></code></li></ul>
+
+Create an authenticate cell from the given configuration.
+
diff --git a/src/onion_authenticate_cell.erl b/src/onion_authenticate_cell.erl
new file mode 100644
index 0000000000000000000000000000000000000000..51f2c0aae4fb4a86fa0b614e11cf75faf618b380
--- /dev/null
+++ b/src/onion_authenticate_cell.erl
@@ -0,0 +1,128 @@
+%%%
+%%% Copyright (c) 2016 The Talla Authors. All rights reserved.
+%%% Use of this source code is governed by a BSD-style
+%%% license that can be found in the LICENSE file.
+%%%
+%%% -----------------------------------------------------------
+%%% @author Alexander Færøy <ahf@0x90.dk>
+%%% @doc Onion Authenticate Cell Utilities
+%%% @end
+%%% -----------------------------------------------------------
+-module(onion_authenticate_cell).
+
+%% API.
+-export([create/1]).
+
+-include("onion_test.hrl").
+
+-type config() :: #{
+        %% CID: A SHA256 hash of the initiator's RSA1024 identity key [32 octets].
+        client_identity_public_key => onion_rsa:public_key(),
+
+        %% SID: A SHA256 hash of the responder's RSA1024 identity key [32 octets].
+        server_identity_public_key => onion_rsa:public_key(),
+
+        %% SLOG: A SHA256 hash of all bytes sent from the responder to the
+        %% initiator as part of the negotiation up to and including the
+        %% AUTH_CHALLENGE cell; that is, the VERSIONS cell, the CERTS cell, the
+        %% AUTH_CHALLENGE cell, and any padding cells.  [32 octets].
+        server_log => binary(),
+
+        %% CLOG: A SHA256 hash of all bytes sent from the initiator to the
+        %% responder as part of the negotiation so far; that is, the VERSIONS
+        %% cell and the CERTS cell and any padding cells. [32 octets].
+        client_log => binary(),
+
+        %% SCERT: A SHA256 hash of the responder's TLS link certificate. [32 octets].
+        server_certificate => public_key:der_encoded(),
+
+        %% TLSSECRETS: A SHA256 HMAC, using the TLS master secret as the secret
+        %% key, of the following:
+        %%   - client_random, as sent in the TLS Client Hello.
+        %%   - server_random, as sent in the TLS Server Hello.
+        %%   - the NUL terminated ASCII string:
+        %%     "Tor V3 handshake TLS cross-certification".
+        %% [32 octets].
+        ssl_session => onion_ssl_session:t(),
+
+        %% SIG: A signature of a SHA256 hash of all the previous fields using
+        %% the initiator's "Authenticate" key as presented.  (As always in Tor,
+        %% we use OAEP-MGF1 padding; see tor-spec.txt section 0.3.) [variable
+        %% length].
+        authentication_secret_key => onion_rsa:secret_key()
+    }.
+
+%% @doc Create an authenticate cell from the given configuration.
+-spec create(Config) -> onion_cell:t()
+    when
+        Config :: config().
+create(Config) ->
+    Data = iolist_to_binary([<<"AUTH0001">>,
+                             public_key_hash(maps:get(client_identity_public_key, Config)),
+                             public_key_hash(maps:get(server_identity_public_key, Config)),
+                             maps:get(server_log, Config),
+                             maps:get(client_log, Config),
+                             certificate_hash(maps:get(server_certificate, Config)),
+                             tls_secrets(maps:get(ssl_session, Config)),
+                             random_bytes()]),
+
+    Hash = crypto:hash(sha256, Data),
+    Signature = onion_rsa:private_encrypt(Hash, maps:get(authentication_secret_key, Config), rsa_pkcs1_padding),
+    onion_cell:authenticate(1, <<Data/binary, Signature/binary>>).
+
+%% @private
+-spec tls_secrets(SSLSession) -> binary()
+    when
+        SSLSession :: onion_ssl_session:t().
+tls_secrets(SSLSession) ->
+    ClientRandom = onion_ssl_session:client_random(SSLSession),
+    ServerRandom = onion_ssl_session:server_random(SSLSession),
+    MasterSecret = onion_ssl_session:master_secret(SSLSession),
+    crypto:hmac(sha256, MasterSecret, [ClientRandom, ServerRandom, "Tor V3 handshake TLS cross-certification", <<0>>]).
+
+%% @private
+-spec public_key_hash(PublicKey) -> binary()
+    when
+        PublicKey :: onion_rsa:public_key().
+public_key_hash(PublicKey) ->
+    {ok, EncodedPublicKey} = onion_rsa:der_encode(PublicKey),
+    crypto:hash(sha256, EncodedPublicKey).
+
+%% @private
+-spec certificate_hash(Certificate) -> binary()
+    when
+        Certificate :: public_key:der_encoded().
+certificate_hash(Certificate) ->
+    crypto:hash(sha256, Certificate).
+
+%% @private
+-spec random_bytes() -> binary().
+random_bytes() ->
+    onion_random:bytes(24).
+
+-ifdef(TEST).
+create_size_test() ->
+    {ok, #{ public := ClientPublicKey }} = onion_rsa:keypair(1024),
+    {ok, #{ public := ServerPublicKey }} = onion_rsa:keypair(1024),
+    {ok, #{ secret := AuthSecretKey }}   = onion_rsa:keypair(1024),
+
+    Cell = create(#{
+             client_identity_public_key => ClientPublicKey,
+             server_identity_public_key => ServerPublicKey,
+
+             server_log => crypto:hash(sha256, <<>>),
+             client_log => crypto:hash(sha256, <<>>),
+
+             server_certificate => <<>>,
+
+              ssl_session => #{
+                master_secret => <<>>,
+                client_random => <<>>,
+                server_random => <<>>
+               },
+
+              authentication_secret_key => AuthSecretKey
+            }),
+    ?assertEqual(224 + 128, byte_size(maps:get(auth, maps:get(payload, Cell)))).
+
+-endif.