<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CipherStash</title>
    <description>The latest articles on DEV Community by CipherStash (cipherstash).</description>
    <link>https://dev.to/cipherstash</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F5898%2Fd2295d3b-c22e-4802-9653-2d2aa6c836f0.png</url>
      <title>DEV Community: CipherStash</title>
      <link>https://dev.to/cipherstash</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cipherstash"/>
    <language>en</language>
    <item>
      <title>Securing PostgreSQL, in the order an attacker would try things</title>
      <dc:creator>Dan Draper</dc:creator>
      <pubDate>Wed, 10 Jun 2026 04:14:55 +0000</pubDate>
      <link>https://dev.to/cipherstash/securing-postgresql-in-the-order-an-attacker-would-try-things-3h24</link>
      <guid>https://dev.to/cipherstash/securing-postgresql-in-the-order-an-attacker-would-try-things-3h24</guid>
      <description>&lt;p&gt;Postgres has a well-earned reputation for security. Roles, privileges, host-based authentication, SCRAM. The primitives are all there, and they're good.&lt;/p&gt;

&lt;p&gt;And yet databases keep leaking. &lt;a href="https://www.grcelearning.com/blog/human-error-is-responsible-for-85-of-data-breaches" rel="noopener noreferrer"&gt;82% of data breaches involve human error&lt;/a&gt;.&lt;br&gt;
The engine is rarely the weak point. The configuration around it is.&lt;/p&gt;

&lt;p&gt;Most hardening guides list fixes in no particular order, as if every gap were equally&lt;br&gt;
likely to be the one that gets you. I think it's more useful to think like the other&lt;br&gt;
side. So this walkthrough is ordered the way an attacker would actually probe your&lt;br&gt;
database: the front door, the keys, the side channels you're leaking through, and&lt;br&gt;
finally the data itself. Every step comes with the commands to do it. You should be&lt;br&gt;
able to work through the whole list against a real database in an afternoon.&lt;/p&gt;
&lt;h2&gt;
  
  
  Door one: who can connect, and as what
&lt;/h2&gt;

&lt;p&gt;An attacker's first question is the simplest one: can I reach this database at all,&lt;br&gt;
and what will it let me do once I'm in?&lt;/p&gt;

&lt;p&gt;Start at the network. Postgres decides who may connect, from where, and how they must&lt;br&gt;
authenticate in &lt;code&gt;pg_hba.conf&lt;/code&gt;. Restrict connections to the IP ranges that genuinely&lt;br&gt;
need them and you've already closed off the casual scan. The&lt;br&gt;
&lt;a href="https://www.postgresql.org/docs/current/auth-pg-hba-conf.html" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;&lt;br&gt;
covers the format.&lt;/p&gt;

&lt;p&gt;Then assume someone gets a connection anyway, because eventually someone will. What&lt;br&gt;
they can do is governed by &lt;a href="https://www.postgresql.org/docs/current/user-manag.html" rel="noopener noreferrer"&gt;roles&lt;/a&gt;&lt;br&gt;
and &lt;a href="https://www.postgresql.org/docs/current/ddl-priv.html" rel="noopener noreferrer"&gt;privileges&lt;/a&gt;, and the&lt;br&gt;
principle is boring but unbeatable: grant the minimum.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- A role for the sales team, with exactly the access they need&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;sales_team&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;sales_team&lt;/span&gt; &lt;span class="n"&gt;LOGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;sales_team&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;sales_team&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Privileges drift. People change teams, contractors leave, and the grants stay. Audit&lt;br&gt;
them on a schedule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;grantee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;privilege_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_grantable&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;role_table_grants&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;grantee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'sales_team'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And revoke what no longer belongs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;REVOKE&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;sensitive_data&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;temporary_contractors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Door two: passwords that hold up
&lt;/h2&gt;

&lt;p&gt;If the network lets them talk to Postgres, credentials are next. Two things matter&lt;br&gt;
more than the rest.&lt;/p&gt;

&lt;p&gt;First, make sure passwords are hashed and exchanged with SCRAM rather than MD5, and&lt;br&gt;
set them in a way that never echoes plaintext into a terminal or a shell history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;password_encryption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'scram-sha-256'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;\password&lt;/code&gt; prompt in psql masks your input and passes it to the server already&lt;br&gt;
encrypted. That beats typing &lt;code&gt;ALTER USER ... PASSWORD 'hunter2'&lt;/code&gt; into a console that&lt;br&gt;
keeps history.&lt;/p&gt;

&lt;p&gt;Second, put a clock on credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Set password expiration for a user&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;user1&lt;/span&gt; &lt;span class="k"&gt;VALID&lt;/span&gt; &lt;span class="k"&gt;UNTIL&lt;/span&gt; &lt;span class="s1"&gt;'2026-12-31'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One detail that surprises people: Postgres does not roll that date forward for you.&lt;br&gt;
Expiry is something you have to operationalize, not a switch you flip once.&lt;/p&gt;
&lt;h2&gt;
  
  
  Door three: the leak you configured yourself
&lt;/h2&gt;

&lt;p&gt;Counterintuitively, one of the most common ways sensitive data escapes Postgres&lt;br&gt;
involves no attacker at all. You write it to disk yourself, in the logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;log_statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single line copies every SQL statement into the log files, including the INSERT&lt;br&gt;
that carried a customer's SSN and the ALTER USER that carried a password. Logs tend&lt;br&gt;
to live with weaker access controls than the database, get shipped to third-party&lt;br&gt;
aggregators, and linger in backups. A carefully secured table doesn't help if the&lt;br&gt;
plaintext went to &lt;code&gt;/var/log&lt;/code&gt; on the way in.&lt;/p&gt;

&lt;p&gt;Safer defaults:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set log format and level in postgresql.conf
&lt;/span&gt;&lt;span class="n"&gt;log_statement&lt;/span&gt; = &lt;span class="s1"&gt;'none'&lt;/span&gt;
&lt;span class="n"&gt;log_line_prefix&lt;/span&gt; = &lt;span class="s1"&gt;'time=%t, pid=%p %q db=%d, usr=%u, client=%h , app=%a, line=%l '&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You keep the operational metadata (who connected, from where, when) without recording&lt;br&gt;
statement contents. The&lt;br&gt;
&lt;a href="https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-LOG-LINE-PREFIX" rel="noopener noreferrer"&gt;logging documentation&lt;/a&gt;&lt;br&gt;
covers the prefix tokens.&lt;/p&gt;

&lt;p&gt;Wherever the logs land, treat them as data: restrict access, rotate, archive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# Specify secure log location and rotation settings
&lt;/span&gt;&lt;span class="n"&gt;log_directory&lt;/span&gt; = &lt;span class="s1"&gt;'/var/log/postgresql/'&lt;/span&gt;
&lt;span class="n"&gt;log_filename&lt;/span&gt; = &lt;span class="s1"&gt;'postgresql.log'&lt;/span&gt;
&lt;span class="n"&gt;log_rotation_age&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;
&lt;span class="n"&gt;log_rotation_size&lt;/span&gt; = &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if what you actually need is an audit trail rather than ad hoc logging,&lt;br&gt;
&lt;a href="https://www.pgaudit.org/" rel="noopener noreferrer"&gt;PGAudit&lt;/a&gt; does the job properly, with session and&lt;br&gt;
object-level auditing, and &lt;a href="https://github.com/pgaudit/pgaudit_analyze" rel="noopener noreferrer"&gt;pgaudit_analyze&lt;/a&gt;&lt;br&gt;
loads the results back into a database for analysis.&lt;/p&gt;
&lt;h2&gt;
  
  
  Door four: assume they get in
&lt;/h2&gt;

&lt;p&gt;Everything so far keeps people out. This layer decides what they get when that fails&lt;br&gt;
anyway. A stolen snapshot, a leaked backup, an over-privileged role nobody revoked.&lt;br&gt;
What does the data look like then?&lt;/p&gt;

&lt;p&gt;The built-in answer is &lt;a href="https://www.postgresql.org/docs/current/pgcrypto.html" rel="noopener noreferrer"&gt;pgcrypto&lt;/a&gt;,&lt;br&gt;
and it's worth understanding exactly why it falls short.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;pgcrypto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;sensitive_data&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;   &lt;span class="nb"&gt;serial&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ssn&lt;/span&gt;  &lt;span class="n"&gt;bytea&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Insert data with server-side encryption&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;sensitive_data&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Alice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pgp_sym_encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'123-45-6789'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'encryption_key'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alice's SSN is now ciphertext in the table. But look at where the key is: in the SQL,&lt;br&gt;
on the server. Decryption happens server-side too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pgp_sym_decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'encryption_key'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;decrypted_ssn&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sensitive_data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the server is compromised, the keys are compromised with it, and the encryption&lt;br&gt;
bought you nothing. There's a performance tax as well: any query that needs to search&lt;br&gt;
or sort that column has to decrypt it row by row first. This is a large part of why&lt;br&gt;
pgcrypto is &lt;a href="https://www.percona.com/sites/default/files/presentations/percona-tech-day-2020-04.pdf" rel="noopener noreferrer"&gt;considered a poor fit for critical use&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Encrypt in the application, keep your queries
&lt;/h3&gt;

&lt;p&gt;The fix for the key problem is to encrypt before the data ever reaches Postgres, so&lt;br&gt;
the server never holds plaintext or key material. The catch has always been search:&lt;br&gt;
&lt;code&gt;WHERE email = ?&lt;/code&gt; is useless when ciphertext is random.&lt;br&gt;
&lt;a href="https://github.com/cipherstash/stack" rel="noopener noreferrer"&gt;CipherStash Stack&lt;/a&gt; addresses both at once.&lt;br&gt;
Data is encrypted in your application, and the values stored in Postgres carry&lt;br&gt;
encrypted index structures (HMACs for equality, bloom filters for free-text search,&lt;br&gt;
Order-Revealing-Encryption blocks for ranges) that the planner uses the way it uses&lt;br&gt;
any other index.&lt;/p&gt;

&lt;p&gt;A minimal end-to-end setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 1. Encrypted columns use the eql_v2_encrypted type&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;    &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="n"&gt;eql_v2_encrypted&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ssn&lt;/span&gt;   &lt;span class="n"&gt;eql_v2_encrypted&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- 2. An index per query pattern you actually use&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_users_email_eq&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;HASH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eql_v2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hmac_256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_users_ssn_eq&lt;/span&gt;   &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;HASH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eql_v2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hmac_256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 3. Describe what's encrypted in TypeScript — the source of truth&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;encryptedTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;encryptedColumn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cipherstash/stack/schema&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Encryption&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cipherstash/stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encryptedTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;encryptedColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;equality&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nf"&gt;encryptedColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ssn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;equality&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// 4. Initialise the client — keys come from your AWS KMS via ZeroKMS,&lt;/span&gt;
&lt;span class="c1"&gt;//    not from the database server.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nc"&gt;Encryption&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// 5. Insert + query — plaintext never enters Postgres&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;encryption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alice@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO users (email) VALUES ($1::jsonb)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;term&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;encryption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encryptQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alice@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;queryType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;equality&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM users WHERE email = $1::eql_v2_encrypted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;encryption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bulkDecryptModels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Per-value keys are derived on demand from a root key held in your own AWS KMS&lt;br&gt;
account, brokered by &lt;a href="https://cipherstash.com/docs/stack/cipherstash/kms" rel="noopener noreferrer"&gt;ZeroKMS&lt;/a&gt;,&lt;br&gt;
so there is no key on the database server for an attacker to find. A &lt;code&gt;pg_dump&lt;/code&gt; of&lt;br&gt;
that table contains ciphertext and opaque index structures. Nothing else. The stolen&lt;br&gt;
snapshot, the over-privileged role, and the leaked SQL log all see the same thing.&lt;/p&gt;

&lt;p&gt;(One naming note in case you go looking: older guides reference&lt;br&gt;
&lt;code&gt;@cipherstash/protectjs&lt;/code&gt; or &lt;code&gt;@cipherstash/jseql&lt;/code&gt;. Those are predecessor libraries.&lt;br&gt;
&lt;code&gt;@cipherstash/stack&lt;/code&gt; is the current surface for new code.)&lt;/p&gt;

&lt;p&gt;The full walkthrough, including free-text search and range queries, is in&lt;br&gt;
&lt;a href="https://cipherstash.com/blog/searchable-encryption-in-postgres" rel="noopener noreferrer"&gt;Searchable encryption in Postgres: a working guide&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  And if you can't change the application
&lt;/h3&gt;

&lt;p&gt;Some databases serve code you can't modify: a legacy app, a BI tool, a third-party&lt;br&gt;
client connecting over the wire. &lt;a href="https://github.com/cipherstash/proxy" rel="noopener noreferrer"&gt;CipherStash Proxy&lt;/a&gt;&lt;br&gt;
covers that case at the connection layer. It speaks the Postgres wire protocol on&lt;br&gt;
both sides, so clients connect to it exactly as they would connect to Postgres.&lt;br&gt;
Encrypted columns are configured in the Proxy rather than the application; queries&lt;br&gt;
with predicates on those columns are rewritten to run over the encrypted indexes, and&lt;br&gt;
results are decrypted on the way back.&lt;/p&gt;

&lt;p&gt;Same &lt;code&gt;eql_v2_encrypted&lt;/code&gt; column types, same indexes, either way. The choice between&lt;br&gt;
Stack and Proxy is only about &lt;em&gt;where&lt;/em&gt; encryption happens: in your app, or in front of&lt;br&gt;
your database.&lt;/p&gt;
&lt;h2&gt;
  
  
  Door five: the copies you forgot about
&lt;/h2&gt;

&lt;p&gt;Every backup is a complete copy of your database with none of its access controls.&lt;br&gt;
Lock the files down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Restrict file permissions to owner only&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 backup_file.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And encrypt backups as they're created, not as a cleanup job afterward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BACKUP_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_password_here"&lt;/span&gt;
pg_dump &lt;span class="nt"&gt;-d&lt;/span&gt; &amp;lt;dbname&amp;gt; &lt;span class="nt"&gt;-h&lt;/span&gt; localhost | openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-salt&lt;/span&gt; &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="nb"&gt;env&lt;/span&gt;:BACKUP_PASSWORD &lt;span class="nt"&gt;-out&lt;/span&gt; dbdump.sql.encrypted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If backups go to cloud storage, use a service that supports client-side encryption so&lt;br&gt;
the provider never holds the decryption key. And note the quiet bonus from door four:&lt;br&gt;
if your sensitive columns are encrypted application-side, the dump was never&lt;br&gt;
plaintext to begin with. That's the nicest property a backup can have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Door six: the exploit you already know about
&lt;/h2&gt;

&lt;p&gt;Stay current with &lt;a href="https://www.postgresql.org/download/" rel="noopener noreferrer"&gt;PostgreSQL releases&lt;/a&gt;. It's&lt;br&gt;
the least glamorous item here and the one with the clearest payoff, because most&lt;br&gt;
real-world exploitation targets vulnerabilities that were patched long before the&lt;br&gt;
attack. An unapplied update is a door you know is open, and so does everyone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's behind the last door
&lt;/h2&gt;

&lt;p&gt;No checklist makes you breach-proof, and I won't pretend this one does. What it&lt;br&gt;
changes is the cost of each failure. If the network rule fails, privileges contain&lt;br&gt;
it. If privileges fail, the logs hold nothing worth stealing. And if everything&lt;br&gt;
fails, if someone walks out with the database files themselves, application-side&lt;br&gt;
encryption decides whether they're holding your customers' data or noise.&lt;/p&gt;

&lt;p&gt;Work through the doors in order. The attacker will.&lt;/p&gt;

&lt;p&gt;:wq&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>security</category>
      <category>database</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Fixing a 1-in-256 bug in CLWW order-preserving encryption</title>
      <dc:creator>Dan Draper</dc:creator>
      <pubDate>Sat, 25 Apr 2026 04:32:10 +0000</pubDate>
      <link>https://dev.to/cipherstash/fixing-a-1-in-256-bug-in-clww-order-preserving-encryption-12ld</link>
      <guid>https://dev.to/cipherstash/fixing-a-1-in-256-bug-in-clww-order-preserving-encryption-12ld</guid>
      <description>&lt;p&gt;Many databases let you sort and range-query encrypted data using &lt;em&gt;order-preserving encryption&lt;/em&gt; (OPE): a scheme where ciphertext bytes compare in the same order as their plaintexts, so standard B-tree indexes and &lt;code&gt;ORDER BY&lt;/code&gt; clauses Just Work. A well-known construction is &lt;a href="https://cipherstash.com/papers/practical-ore-clww-2015.pdf" rel="noopener noreferrer"&gt;Chenette-Lewi-Weis-Wu (CLWW)&lt;/a&gt; from 2015 — small, fast, and widely deployed. The paper gives an order-&lt;em&gt;revealing&lt;/em&gt; scheme with a custom comparator, and notes in passing that the same ciphertext bytes can be compared &lt;em&gt;lexicographically&lt;/em&gt; to yield an order-&lt;em&gt;preserving&lt;/em&gt; scheme as a side benefit.&lt;/p&gt;

&lt;p&gt;But that reinterpretation is only almost right. Roughly 1 in 256 comparisons disagrees with the true plaintext order. In this post I'll walk through why, with a worked example, and show how two small changes to the encoding eliminate the residual — at the cost of one extra byte per ciphertext and a single arithmetic pass.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This post walks through the construction and the intuition. If you want the full derivation — triangular probability distributions, the signal/noise argument, empirical verification, and a discussion of what the scheme leaks — head over to the companion engineering note: &lt;a href="https://cipherstash.com/research/backward-carry-ope" rel="noopener noreferrer"&gt;Exact OPE from CLWW ORE via Backward Carry + MSB-Bit Placement&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why order-preserving encryption?
&lt;/h2&gt;

&lt;p&gt;When you encrypt a column in a database with a standard symmetric cipher — AES-GCM, ChaCha20, pick your favourite — you get great confidentiality. You also lose every other useful property of the column. The ciphertext byte order has nothing to do with the plaintext order, so your B-tree index, your &lt;code&gt;ORDER BY&lt;/code&gt; clauses, and your range queries (&lt;code&gt;WHERE price BETWEEN 100 AND 500&lt;/code&gt;) stop working entirely.&lt;/p&gt;

&lt;p&gt;Order-preserving encryption fixes this, at a cost. In an OPE scheme, if plaintext &lt;code&gt;x &amp;lt; y&lt;/code&gt;, then &lt;code&gt;enc(x) &amp;lt; enc(y)&lt;/code&gt; under the standard comparison your database already understands — usually byte-lexicographic compare, i.e. &lt;code&gt;memcmp&lt;/code&gt;. Drop these ciphertexts into any off-the-shelf sorted index and range scans work out of the box. No custom comparator. No query-rewriting middleware.&lt;/p&gt;

&lt;p&gt;To make that concrete, here's a handful of 8-bit integer plaintexts alongside illustrative ciphertexts — the bytes are made up rather than produced by running the scheme, but they follow its rules (9 bytes each, reserved leading byte, shared prefix where the high-order plaintext bits agree, first differing byte offset by ~128). Only the first 6 of 9 bytes are shown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plaintext&lt;/th&gt;
&lt;th&gt;Ciphertext (hex)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00 5e 38 12 9a 2c …&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;42&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00 5e 38 92 3f c4 …&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;100&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00 5e b8 4c 92 3f …&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00 de 7a 23 51 8c …&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;250&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00 de 7a a3 ff 22 …&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Plaintexts in ascending order produce ciphertexts in ascending byte-lexicographic order: &lt;code&gt;memcmp&lt;/code&gt; over any two rows returns the same verdict as comparing the plaintexts directly. Drop these into a B-tree index and &lt;code&gt;ORDER BY&lt;/code&gt; / range queries work out of the box. You can also see the scheme's leakage profile hiding in plain sight — the closer two plaintexts' high-order bits are, the more leading bytes their ciphertexts share. More on that in a minute.&lt;/p&gt;

&lt;p&gt;The cost is leakage. A scheme that preserves order also leaks order (tautologically), and typically a bit more — usually some information about the common prefix of two plaintexts. For many workloads that tradeoff is acceptable; for others you'd reach for a construction with a tighter leakage profile, like the Lewi–Wu &lt;a href="https://github.com/cipherstash/ore.rs" rel="noopener noreferrer"&gt;Block ORE scheme&lt;/a&gt; — which is what CipherStash uses for most production paths, exposed to Postgres through &lt;a href="https://github.com/cipherstash/encrypt-query-language" rel="noopener noreferrer"&gt;EQL&lt;/a&gt;. Block ORE needs a custom comparator, which in Postgres means registering a custom operator class via &lt;code&gt;CREATE OPERATOR CLASS&lt;/code&gt; / &lt;code&gt;CREATE OPERATOR FAMILY&lt;/code&gt;. Some managed platforms permit those statements without superuser (AWS RDS does, which is why EQL runs there today); others don't (Supabase, as of writing). When you're on a platform in the latter category, CLWW OPE is the next best thing — standard lex-compare on the ciphertext works with any stock B-tree index, no custom operator class required. I'll touch on what CLWW specifically leaks toward the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  CLWW in 60 seconds
&lt;/h2&gt;

&lt;p&gt;CLWW is a bit-by-bit ORE scheme. For an n-bit plaintext &lt;code&gt;p = b₀ b₁ … bₙ₋₁&lt;/code&gt; (MSB-first), it produces an n-byte ciphertext. The construction feeds the plaintext bits through a keyed hash function one bit at a time — we'll model that keyed hash as a &lt;em&gt;pseudorandom function&lt;/em&gt; (PRF), a function whose output is indistinguishable from uniform random bytes to anyone who doesn't have the key. In practice that's HMAC-SHA256, BLAKE3 in keyed mode, or similar; our implementation uses BLAKE3. At each step we pull one PRF byte and add the plaintext bit to it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F578v1nj6giqubr7hfqep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F578v1nj6giqubr7hfqep.png" alt="CLWW ORE flow diagram cᵢ = (PRFᵢ + bᵢ) mod 256" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The arrows between the PRF boxes are the important part. &lt;code&gt;PRFᵢ&lt;/code&gt; depends on all the plaintext bits &lt;code&gt;b₀ … bᵢ₋₁&lt;/code&gt; that came before it. So for two plaintexts X and Y that first differ at bit k:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At positions 0 through k, the PRF inputs are identical in both plaintexts, so &lt;code&gt;PRFᵢ^X = PRFᵢ^Y&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;At positions k+1 onward, the chain has diverged (one side saw &lt;code&gt;bₖ = 0&lt;/code&gt;, the other saw &lt;code&gt;bₖ = 1&lt;/code&gt;), so the PRFs look independent-random.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the first differing byte itself, then, the ciphertexts differ by exactly &lt;code&gt;b_k^Y − b_k^X&lt;/code&gt;, which is &lt;code&gt;+1&lt;/code&gt; or &lt;code&gt;−1&lt;/code&gt;. The native CLWW comparator exploits this: find the first differing byte, check whether &lt;code&gt;c_Y ≡ c_X + 1 (mod 256)&lt;/code&gt;. If yes, X &amp;lt; Y; otherwise Y &amp;lt; X. Note the &lt;code&gt;mod 256&lt;/code&gt; in that check — we'll come back to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The paper's OPE reinterpretation — and the 1/256 bug
&lt;/h2&gt;

&lt;p&gt;Section 3.2 of the CLWW paper observes that the ciphertext bytes agree up to the first differing byte, and at that byte one side is exactly one more than the other. So if you forget about the custom comparator and just sort the ciphertexts lexicographically, you'll usually get the right answer.&lt;/p&gt;

&lt;p&gt;"Usually" is doing a lot of work there.&lt;/p&gt;

&lt;p&gt;Consider X = 0 and Y = 1 as 8-bit plaintexts. Bits of X are &lt;code&gt;0000 0000&lt;/code&gt;; bits of Y are &lt;code&gt;0000 0001&lt;/code&gt;. The PRF chain for Y sees only zeros up to bit 6, so &lt;code&gt;PRF₀ … PRF₇&lt;/code&gt; are identical in both plaintexts. Every ciphertext byte agrees, except byte 7 — which encodes the one differing bit.&lt;/p&gt;

&lt;p&gt;Now imagine &lt;code&gt;PRF₇ = 0xFF&lt;/code&gt;. A 1-in-256 event.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Byte&lt;/th&gt;
&lt;th&gt;PRF&lt;/th&gt;
&lt;th&gt;X's bit&lt;/th&gt;
&lt;th&gt;Y's bit&lt;/th&gt;
&lt;th&gt;&lt;code&gt;c^X&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;c^Y&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0–6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PRFᵢ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PRFᵢ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PRFᵢ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xFF&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xFF&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0xFF + 1) mod 256 = 0x00&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Lex compare: bytes 0 through 6 agree, byte 7 has &lt;code&gt;0x00&lt;/code&gt; on the Y side and &lt;code&gt;0xFF&lt;/code&gt; on the X side. The comparator says Y &amp;lt; X. The plaintext says Y &amp;gt; X. Wrong answer.&lt;/p&gt;

&lt;p&gt;The CLWW comparator handles this case because its check is &lt;code&gt;c_Y ≡ c_X + 1 (mod 256)&lt;/code&gt;, which is true for &lt;code&gt;(0xFF, 0x00)&lt;/code&gt; as well as for &lt;code&gt;(0x42, 0x43)&lt;/code&gt;. Lex compare doesn't have the mod-256 awareness — when the byte wraps around, the ordering flips.&lt;/p&gt;

&lt;p&gt;Per-comparison error rate: &lt;code&gt;1/256 ≈ 3.9 × 10⁻³&lt;/code&gt;. For a range scan touching a few thousand ciphertexts, that's multiple mis-orderings per query. Unacceptable.&lt;/p&gt;

&lt;h2&gt;
  
  
  First fix: backward carry
&lt;/h2&gt;

&lt;p&gt;Here's the key reframe: instead of thinking of the ciphertext as a byte stream, think of it as a big-endian integer. When &lt;code&gt;PRFₖ + bₖ&lt;/code&gt; wraps past 256, we don't lose the &lt;code&gt;+1&lt;/code&gt; — we propagate it as an arithmetic carry to the byte on the left, exactly like schoolbook long addition. We reserve a leading byte at the top of the ciphertext to absorb any carry that makes it all the way up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;encrypt_ope_v1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hasher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;keyed_hasher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Pass 1: generate PRF bytes, record the plaintext bits.
&lt;/span&gt;    &lt;span class="n"&gt;prfs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;bit&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;bits_msb_first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;prfs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next_byte&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Pass 2: compute P + B as an (n+1)-byte big-endian integer,
&lt;/span&gt;    &lt;span class="c1"&gt;# with a reserved leading byte that absorbs the final carry.
&lt;/span&gt;    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;prfs&lt;/span&gt;
    &lt;span class="n"&gt;carry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;carry&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;
        &lt;span class="n"&gt;carry&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;       &lt;span class="c1"&gt;# always 0 or 1
&lt;/span&gt;    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;carry&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comparison is plain byte-lex compare — no custom comparator required.&lt;/p&gt;

&lt;p&gt;Let's replay the failing case. X = 0, Y = 1, &lt;code&gt;PRF₇ = 0xFF&lt;/code&gt;. The ciphertext is now 9 bytes (one reserved + eight content).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;X&lt;/strong&gt; (all bits zero): pass 2 adds nothing and no carry propagates.
&lt;code&gt;c^X = [0, PRF₀, …, PRF₆, 0xFF]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Y&lt;/strong&gt; (bit 7 = 1): at byte 8 we compute &lt;code&gt;0xFF + 1 + 0 = 0x100&lt;/code&gt; → byte 8 becomes &lt;code&gt;0x00&lt;/code&gt;, carry out = 1. At byte 7 we compute &lt;code&gt;PRF₆ + 0 + 1 = PRF₆ + 1&lt;/code&gt;, carry out = 0. Other bytes unchanged.
&lt;code&gt;c^Y = [0, PRF₀, …, PRF₅, PRF₆ + 1, 0x00]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lex compare: &lt;code&gt;c^X&lt;/code&gt; and &lt;code&gt;c^Y&lt;/code&gt; agree through byte 6. At byte 7, &lt;code&gt;c^X&lt;/code&gt; has &lt;code&gt;PRF₆&lt;/code&gt; and &lt;code&gt;c^Y&lt;/code&gt; has &lt;code&gt;PRF₆ + 1&lt;/code&gt;. Y is bigger — correctly. ✓&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;+1&lt;/code&gt; didn't disappear when the byte wrapped; it just moved one position to the left, where it reappears at the byte the lex comparator hits first.&lt;/p&gt;

&lt;h2&gt;
  
  
  But wait — this isn't exact
&lt;/h2&gt;

&lt;p&gt;A big improvement, but it turns out this scheme is only &lt;em&gt;almost&lt;/em&gt; right. The per-comparison error rate drops from &lt;code&gt;~1/256&lt;/code&gt; to around &lt;code&gt;7.7 × 10⁻⁶&lt;/code&gt; — about 500× better — but it's still not zero.&lt;/p&gt;

&lt;p&gt;The residual is a signal/noise mismatch. At the first differing byte, the plaintext injects a &lt;code&gt;+1&lt;/code&gt; signal — but the backward carry coming up from the byte to its right can also swing the result by &lt;code&gt;±1&lt;/code&gt;. Signal and noise are the same order of magnitude, so in rare PRF configurations they cancel exactly and the two ciphertexts tie where the plaintexts don't. The full derivation — triangular distributions, tail probabilities, the small correction for the &lt;code&gt;m = 2&lt;/code&gt; case — lives in the &lt;a href="https://cipherstash.com/research/backward-carry-ope" rel="noopener noreferrer"&gt;engineering note&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The question is: can we kill the residual without making the ciphertext larger?&lt;/p&gt;

&lt;h2&gt;
  
  
  Second fix: place the bit at the MSB
&lt;/h2&gt;

&lt;p&gt;The signal-vs-noise framing suggests the obvious move: make the signal bigger. We can't shrink the noise — &lt;code&gt;±1&lt;/code&gt; per byte is intrinsic to how the carry works — but we &lt;em&gt;can&lt;/em&gt; inject the plaintext bit at a higher-weight position within its byte.&lt;/p&gt;

&lt;p&gt;Concretely: instead of adding &lt;code&gt;+bit&lt;/code&gt; (which puts the signal at bit 0 of the byte, weight 1), add &lt;code&gt;+bit · 128&lt;/code&gt; (which puts it at bit 7, weight 128). Same ciphertext size. Same PRF chain. One line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-    total = out[i + 1] + bits[i]       + carry
&lt;/span&gt;&lt;span class="gi"&gt;+    total = out[i + 1] + bits[i] * 128 + carry
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signal is now &lt;code&gt;+128&lt;/code&gt; at the first differing byte. The carry noise is still &lt;code&gt;±1&lt;/code&gt;. They can't cancel — lex compare resolves at the first differing byte by a margin of at least 127 (or, if that byte happens to wrap and the carry propagates one position left, at the byte before it, which sits at 256× the integer weight and so dominates anyway). The &lt;a href="https://cipherstash.com/research/backward-carry-ope" rel="noopener noreferrer"&gt;engineering note&lt;/a&gt; has the full case analysis.&lt;/p&gt;

&lt;p&gt;Exact OPE. Verified empirically: 1 310 700 adjacent &lt;code&gt;u16&lt;/code&gt; pairs under 20 randomly sampled keys, zero ordering errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;Two small changes — a backward carry pass with a reserved byte, and placing the plaintext bit at the top bit of its byte rather than the bottom — turn CLWW's paper-suggested OPE reinterpretation from a ~1/256-wrong scheme into an exact one. Same number of PRF evaluations, one extra ciphertext byte, no custom comparator needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this gives you&lt;/strong&gt;: drop-in ciphertexts for any ordered index or sort operation, with ordering that matches plaintext ordering exactly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it doesn't give you&lt;/strong&gt;: strict-ORE-level leakage hiding (the scheme leaks first-differing-bit position, same as CLWW ORE), and no decryption — for round-trip you pair the OPE ciphertext with an authenticated symmetric cipher like AES-GCM.&lt;/p&gt;

&lt;p&gt;The implementation lives in our &lt;a href="https://crates.io/crates/cllw-ore" rel="noopener noreferrer"&gt;&lt;code&gt;cllw-ore&lt;/code&gt; crate&lt;/a&gt; on crates.io, with a fuller derivation of the error rate and the exactness argument in the &lt;a href="https://cipherstash.com/research/backward-carry-ope" rel="noopener noreferrer"&gt;engineering note&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you've got a production encrypted-database use case that needs order-preserving indexes — or you just enjoy small clean cryptographic primitives — I'd love to hear what you think.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>database</category>
      <category>security</category>
    </item>
    <item>
      <title>Show Dev: Introducing Protect.js</title>
      <dc:creator>Dan Draper</dc:creator>
      <pubDate>Fri, 14 Mar 2025 00:59:31 +0000</pubDate>
      <link>https://dev.to/cipherstash/show-dev-introducing-protectjs-53al</link>
      <guid>https://dev.to/cipherstash/show-dev-introducing-protectjs-53al</guid>
      <description>&lt;p&gt;&lt;strong&gt;Protecting data that’s sensitive — such as personal health or financial information — is crucial to building applications that users trust. But getting access control right is a tricky business. Complex requirements and a plethora of tools, as well as performance considerations, can kill dev team productivity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is why we created &lt;a href="https://github.com/cipherstash/protectjs" rel="noopener noreferrer"&gt;Protect.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Protect turns data access control on its head by protecting data directly. Unlike complex, application-specific frameworks or hand-rolled tools, Protect.js makes building secure, data-driven applications simple so you can deliver services that users trust without slowing down delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  We rolled the crypto so you don’t have to
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Security experts say you shouldn't roll your own crypto but it's ok, we've done the hard work for you.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Protect’s power comes from the strongest form of access control: encryption. Encryption is rarely considered for the fine-grained protection of data because it's hard to implement, slow, and doesn’t play nicely with other tools in the stack like identity providers or the database. That is, until today.&lt;/p&gt;

&lt;p&gt;Based on the CipherStash encryption SDK and using our revolutionary key management service, &lt;a href="https://cipherstash.com/products/zerokms" rel="noopener noreferrer"&gt;ZeroKMS&lt;/a&gt;, Protect.js unlocks the power of encryption but without the hassle. Protect.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works with any Node.js framework or ORM (like Next.js + Drizzle)&lt;/li&gt;
&lt;li&gt;Is based on AES-256 encryption and uses formally-verified cryptography&lt;/li&gt;
&lt;li&gt;Uses ZeroKMS key management that’s up to 14x faster than AWS KMS&lt;/li&gt;
&lt;li&gt;Supports queries and sorting over encrypted data&lt;/li&gt;
&lt;li&gt;Is so easy to use you can get started in ~under 15-minutes~&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Encryption in use
&lt;/h2&gt;

&lt;p&gt;You’ve probably heard of encryption &lt;em&gt;at rest&lt;/em&gt; or &lt;em&gt;in transit&lt;/em&gt; but these approaches are only part of the story when it comes to effective data protection.&lt;/p&gt;

&lt;p&gt;At-rest and in-transit encryption leave critical gaps in your data’s defenses which can lead to vulnerabilities or accidental leaks and make it harder to reason about whether data is secure, especially when trying to convince customers or an auditor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc8bks0vq0i36891s6u5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc8bks0vq0i36891s6u5k.png" alt="Encryption in use" width="800" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Protect.js uses encryption &lt;em&gt;in use&lt;/em&gt; to protect data.&lt;br&gt;
Sensitive data items, like individual email addresses remain protected right up until an authorized end-user needs to read them.&lt;br&gt;
This limits the “surface area” of a potential attack and reduces risk as well as making it easier to demonstrate that data is secure.&lt;/p&gt;

&lt;p&gt;To protect a sensitive database field with Protect.js, you do so via a &lt;strong&gt;protected schema&lt;/strong&gt; definition. To specify that the &lt;code&gt;email&lt;/code&gt; column of the &lt;code&gt;users&lt;/code&gt; table should be encrypted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/protect/schema.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;csTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;csColumn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cipherstash/protect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;csTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;csColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, to encrypt a value, pass any schemas you've defined to &lt;code&gt;protect&lt;/code&gt; and call &lt;code&gt;encrypt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/protect/client.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;protect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cipherstash/protect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./schema&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Do this once when your app starts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;protectClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;protect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Encrypt an email address for a configured column and table&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;protectClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret@squirrel.example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the &lt;a href="https://github.com/cipherstash/protectjs" rel="noopener noreferrer"&gt;Protect.js getting started guide&lt;/a&gt; if you want to jump right into the code. Or read on to learn about some of Protect.js's other capabilities!&lt;/p&gt;

&lt;h3&gt;
  
  
  Key management
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Encryption in use&lt;/em&gt; is similar to the idea of "field" or "row-level" encryption. One of the main differences is in how keys are managed: Encryption in use ensures each value is encrypted by a unique data key.&lt;/p&gt;

&lt;p&gt;I spoke about &lt;a href="https://youtu.be/zjI1qLakD-E?si=sEliLRNK6ZwiuCm_" rel="noopener noreferrer"&gt;why this is a good thing&lt;/a&gt; at BSides SF in 2024.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmejcayj5453bva3zc9v9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmejcayj5453bva3zc9v9.jpg" alt="You cant read the data if you dont have the encryption key" width="702" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even the best encryption tech is useless without good key management.&lt;br&gt;
When using traditional field-level encryption in a web-based application you have 2 options available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A local key (&lt;em&gt;fast but less secure&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;A cloud-based key-management service (&lt;em&gt;secure but slow&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A local key is a secret encryption key (usually stored as an environment variable). This approach uses the &lt;em&gt;same key&lt;/em&gt; to encrypt all data in the application and comes with some nasty security problems. For starters, if an adversary obtains the key, they can use it to access all of the data in your system.&lt;/p&gt;

&lt;p&gt;If you need to update ("rotate") the key you'll need to re-encrypt &lt;em&gt;everything&lt;/em&gt;. More subtle problems can arise too. AES keys are vulnerable to &lt;em&gt;key wear out&lt;/em&gt; which means that if a single key is used to encrypt more than about 4GB, previously encrypted values can be used to &lt;em&gt;recover the key itself&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Key Management Services (KMS) like &lt;a href="https://aws.amazon.com/kms/" rel="noopener noreferrer"&gt;AWS KMS&lt;/a&gt; or &lt;a href="https://learn.microsoft.com/en-us/azure/key-vault/general/overview" rel="noopener noreferrer"&gt;Azure KeyVault&lt;/a&gt; mitigate these problems with a technique called &lt;em&gt;envelope encryption&lt;/em&gt;. Instead of storing an encryption key in an application environment variable, a &lt;em&gt;root_key&lt;/em&gt; is stored within the cloud provider's infrastructure inside a device called a Hardware Security Module (HSM).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8ee5ojpyrlaepsxvnq8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu8ee5ojpyrlaepsxvnq8.png" alt="Envelope encryption" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To perform an encryption operation, clients must make a request to the key service which returns a randomly generated &lt;em&gt;data key&lt;/em&gt; along with a copy that has itself been encrypted using the &lt;em&gt;root key&lt;/em&gt; (called a &lt;em&gt;wrapped data key&lt;/em&gt;). The &lt;em&gt;data key&lt;/em&gt; is used to encrypt the target value (such as an email address) and discarded with the result stored in the database with the &lt;em&gt;wrapped data key&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Envelope encryption is a big security improvement over a local key but has a major drawback. Because each data key requires a separate HTTP request, performance can be &lt;strong&gt;abysmal&lt;/strong&gt;. To get around this, cloud providers added support for &lt;em&gt;data key caching&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However, when caching data-keys many of the same problems as using a local-key can arise. Use a single data key to encrypt too much data and you can run into wear-out issues. A compromise of the cache used to store data-keys could lead to a pretty significant data breach.&lt;/p&gt;

&lt;p&gt;Data key caching also means that there is no-longer a &lt;em&gt;1-to-1 mapping&lt;/em&gt; between a data-key and the specific value it was used to encrypt which means we miss out on powerful access-control and auditing capabilities. We'll cover these in a moment!&lt;/p&gt;

&lt;h3&gt;
  
  
  Security or performance: why not both?
&lt;/h3&gt;

&lt;p&gt;To address these problems, Protect.js uses ZeroKMS, which eliminates the performance-security tradeoffs common with traditional KMS. Instead of a single root key, ZeroKMS uses composable pairs of keys to generate data keys. One half of the pair, the &lt;em&gt;client key&lt;/em&gt; is stored by your application and the other, stored by ZeroKMS.&lt;/p&gt;

&lt;p&gt;This technique has a number of security benefits, but most relevant to this discussion is that it now makes it safe to do &lt;em&gt;bulk requests&lt;/em&gt; for data keys. ZeroKMS can generate up to &lt;strong&gt;10,000&lt;/strong&gt; data keys in a single operation.&lt;/p&gt;

&lt;p&gt;To demonstrate the impact on performance of this approach, we've shared some benchmarks below of Protect.js running in a Next.js application with Postgres and Drizzle. Each request fetches 10 user records from a table that have 2 fields encrypted (email and address).&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://app.artillery.io/share/sh_a2775fd02bf981207dd24e2e371b144f3e7792704948ac998ae34e83e28894b3" rel="noopener noreferrer"&gt;first report&lt;/a&gt; shows AWS KMS performance without data-key caching.&lt;br&gt;
It managed an average of 27 and a peak of 44 requests per second.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj9ltvsxartnaip7limb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj9ltvsxartnaip7limb.png" alt="Artillery graph of AWS KMS performance" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ZeroKMS managed &lt;a href="https://app.artillery.io/share/sh_75edb9d22a060633bfdce04777ffd60d1bcfc88989393dc38d3a4924b83fc6cd" rel="noopener noreferrer"&gt;7 times the average and 14 times the peak&lt;/a&gt; performance of AWS KMS, with a peak rate of 615 requests/second.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffz6o3inkp2k849nui4hc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffz6o3inkp2k849nui4hc.png" alt="Artillery graph of ZeroKMS performance" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Apdex scores are particularly telling:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzbwtuvl8vq0tre3wkai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzbwtuvl8vq0tre3wkai.png" alt=" " width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a future post, we'll do a deep dive on how we ran these benchmarks as well as some surprising results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rust you can trust
&lt;/h3&gt;

&lt;p&gt;Under the hood, Protect.js is &lt;a href="https://crates.io/crates/cipherstash-client" rel="noopener noreferrer"&gt;written in Rust&lt;/a&gt;.&lt;br&gt;
We chose Rust because it's incredibly fast, memory efficient, and has some unique security properties, particularly when it comes to cryptography. Rust is the &lt;em&gt;only&lt;/em&gt; mainstream compiled language that is also memory safe without the need for a garbage collector.&lt;br&gt;
This &lt;strong&gt;eliminates&lt;/strong&gt; the most common type of security vulnerabilities: memory bugs.&lt;/p&gt;

&lt;p&gt;Computerphile has a &lt;a href="https://youtu.be/pTMvh6VzDls?si=PIouKj8H_OIWn-8D" rel="noopener noreferrer"&gt;great video&lt;/a&gt; about Rust and memory safety if you'd like to learn more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quantum resistant, verified cryptography
&lt;/h3&gt;

&lt;p&gt;The low-level cryptographic components of Protect.js use &lt;a href="https://crates.io/crates/aws-lc-rs" rel="noopener noreferrer"&gt;aws-lc-rs&lt;/a&gt;, Amazon’s formally verified cryptography library. Used to mathematically &lt;em&gt;prove&lt;/em&gt; the correctness of software, formal verification is the gold-standard in high-assurance, secure-by-design systems. Protect.js is also designed to be resistant to attacks by a quantum computer should such devices ever become practical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vitamins for your crypto
&lt;/h3&gt;

&lt;p&gt;At CipherStash, we’re also working on formal verification for other parts of our stack and have created an open source framework, called &lt;a href="https://github.com/cipherstash/vitaminc" rel="noopener noreferrer"&gt;Vitamin C&lt;/a&gt;. Vitamin C is like vitamins for cryptography. It simplifies the writing of high-assurance software by providing secure, highly-scrutinised and tested reusable building blocks.&lt;/p&gt;

&lt;h3&gt;
  
  
  SOC 2 compliant
&lt;/h3&gt;

&lt;p&gt;CipherStash, including the ZeroKMS key service is SOC 2 compliant.&lt;br&gt;
You can learn more in our &lt;a href="https://trust.cipherstash.com/" rel="noopener noreferrer"&gt;trust centre&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s coming next?
&lt;/h2&gt;

&lt;p&gt;We've barely scratched the surface in this post but over the coming weeks we'll share more about what Protect.js can do to make effective data protection easy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Granular control with identity-based context locking&lt;/li&gt;
&lt;li&gt;Searchable encryption with Protect.js and when to use it&lt;/li&gt;
&lt;li&gt;Deep dives on the internals of Protect.js and ZeroKMS&lt;/li&gt;
&lt;li&gt;More benchmarks, code samples, and tutorials for specific use-cases&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Protect sensitive data in just 15 minutes
&lt;/h2&gt;

&lt;p&gt;All there is to do now is give &lt;a href="https://github.com/cipherstash/protectjs" rel="noopener noreferrer"&gt;Protect.js&lt;/a&gt; a try!&lt;br&gt;
Don't forget to star us on Github, too :)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>encryption</category>
      <category>database</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Verifying Rust Zeroize with Assembly...including portable SIMD</title>
      <dc:creator>Dan Draper</dc:creator>
      <pubDate>Wed, 10 Jan 2024 12:31:13 +0000</pubDate>
      <link>https://dev.to/cipherstash/verifying-rust-zeroize-with-assemblyincluding-portable-simd-2g65</link>
      <guid>https://dev.to/cipherstash/verifying-rust-zeroize-with-assemblyincluding-portable-simd-2g65</guid>
      <description>&lt;p&gt;When writing code that deals with sensitive information like passwords or payment data, it's important to &lt;em&gt;zeroize&lt;/em&gt; memory when you're done with it. Failing to do so can leave sensitive data in memory even after the program is terminated and even end up on disk when the computer uses swap.&lt;/p&gt;

&lt;p&gt;In this post, I'll explain what zeroizing is, why and when you should use it and how to implement it correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is &lt;em&gt;Zeroizing&lt;/em&gt;?
&lt;/h2&gt;

&lt;p&gt;When a sensitive value, say an encryption key, is used in a program it must be stored in memory: either on the stack or in the heap. In either case, even after memory is dropped (or freed, garbage collected etc), the contents may still lurk in the computer - even beyond the life of the program. It is therefore important that such data be cleared before the memory is dropped so that secrets are not leaked to unexpected places.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is Zeroizing important?
&lt;/h2&gt;

&lt;p&gt;The code below demonstrates that even after it has been dropped, data stored in a given memory location can still be read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;SensitiveData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;// Representing sensitive data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Some mock sensitive data&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sensitive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SensitiveData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data_location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sensitive&lt;/span&gt;&lt;span class="py"&gt;.data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sensitive&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Attempt to read the data back&lt;/span&gt;
    &lt;span class="c1"&gt;// after it has been dropped&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;recovered_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;copy_nonoverlapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="n"&gt;data_location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;recovered_data&lt;/span&gt;&lt;span class="nf"&gt;.as_mut_ptr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="mi"&gt;16&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Recovered data: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recovered_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code calls creates a mock &lt;code&gt;SensitiveData&lt;/code&gt; value and then calls &lt;code&gt;mem::drop&lt;/code&gt; directly instead of letting Rust do it when the value goes out of scope. Before doing so, it stores the location of the memory that was used for the data as a raw pointer and then uses that location to read back the original contents of the memory.&lt;/p&gt;

&lt;p&gt;While this is a very simple example, it illustrates that just because memory is dropped, data still exists in the system even if the program doesn't care about it anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Zeroize
&lt;/h2&gt;

&lt;p&gt;Zeroizing memory is surprisingly very tricky. Even Rust, famous for memory safety has no formal built-in way to do this. The main challenge is stopping the compiler from optimizing away code that it &lt;em&gt;thinks&lt;/em&gt; is not necessary.&lt;/p&gt;

&lt;p&gt;Let's look at an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib.rs (simd_zeroize)&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;SafeArray&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;SafeArray&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;consume_and_sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Careful! This could overflow!&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, I have a type called &lt;code&gt;SafeArray&lt;/code&gt; which just wraps a 4-element array of &lt;code&gt;u32&lt;/code&gt;. I've created my own type so that I can implement the &lt;code&gt;Drop&lt;/code&gt; trait in a moment.&lt;/p&gt;

&lt;p&gt;My type has a single function which consumes &lt;code&gt;self&lt;/code&gt; and sums all elements as a u32. Because &lt;code&gt;self&lt;/code&gt; is consumed but not returned it will be dropped. (Be aware that this code could easily cause an addition overflow but I'm intentionally keeping it very simple to limit how much assembly code is generated).&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspecting the compiled code
&lt;/h2&gt;

&lt;p&gt;To really understand what's going on here we can look at the compiled assembly code. I'm working on a Mac and can do this using the &lt;code&gt;objdump&lt;/code&gt; tool. &lt;a href="https://godbolt.org/" rel="noopener noreferrer"&gt;Compiler Explorer&lt;/a&gt; is also a handy tool but doesn't seem to support Arm assembly which is what Rust will use when compiling on Apple Silicon.&lt;/p&gt;

&lt;p&gt;Before looking at the assembly, the code must be compiled in &lt;strong&gt;release&lt;/strong&gt; mode as this will ensure that all of the compiler's target optimizations are applied.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo build --release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I'll use &lt;code&gt;objdump&lt;/code&gt; to disassemble the machine code into Arm64 ASM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;objdump -d target/debug/libsimd_zeroize.rlib &amp;gt; assembly.s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the &lt;code&gt;assembly.s&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0000000000000000 &amp;lt;ltmp0&amp;gt;:
       0: 00 00 c0 3d   ldr q0, [x0]
       4: 00 b8 b1 4e   addv.4s s0, v0
       8: 00 00 26 1e   fmov    w0, s0
       c: c0 03 5f d6   ret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry if you don't know or understand assembly code, we'll focus just on specific instructions for this exercise.&lt;/p&gt;

&lt;p&gt;The line starting with &lt;code&gt;0000000000000000&lt;/code&gt; is the label Rust has given to the &lt;code&gt;consume_and_sum&lt;/code&gt; method and the actual machine instructions are contained below it. These steps load the values from a memory address stored in &lt;code&gt;x0&lt;/code&gt; into a register called &lt;code&gt;q0&lt;/code&gt;, add all 4 values in one step (using the vectorized addv.4s instruction), move the result into an output register and return.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Registers are what the CPU uses to perform most operations so  this code loads data from memory into the register to that an operation can be performed.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Drop
&lt;/h2&gt;

&lt;p&gt;Let's see what happens when we try to implement zeroization when our &lt;code&gt;SafeArray&lt;/code&gt; is dropped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Drop&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;SafeArray&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Demonstration only: Don't do this&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the ASM for the whole program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;&lt;span class="nl"&gt;0000000000000000&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ltmp0&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
       &lt;span class="err"&gt;0:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
       &lt;span class="err"&gt;4:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;b8&lt;/span&gt; &lt;span class="nv"&gt;b1&lt;/span&gt; &lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;   &lt;span class="nv"&gt;addv&lt;/span&gt;&lt;span class="mf"&gt;.4&lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;s0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;v0&lt;/span&gt;
       &lt;span class="err"&gt;8:&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt; &lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;   &lt;span class="nv"&gt;fmov&lt;/span&gt;    &lt;span class="nv"&gt;w1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;s0&lt;/span&gt;
       &lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;a9&lt;/span&gt;   &lt;span class="nv"&gt;stp&lt;/span&gt; &lt;span class="nv"&gt;xzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;xzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;10:&lt;/span&gt; &lt;span class="nv"&gt;e0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt; &lt;span class="nv"&gt;aa&lt;/span&gt;   &lt;span class="nv"&gt;mov&lt;/span&gt; &lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;x1&lt;/span&gt;
      &lt;span class="err"&gt;14:&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;d6&lt;/span&gt;   &lt;span class="nv"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important line is shown below. It uses &lt;code&gt;stp&lt;/code&gt; which stores a pair of registers, in this case the special &lt;em&gt;zero&lt;/em&gt; register, &lt;code&gt;xzr&lt;/code&gt; in the memory pointed to by &lt;code&gt;x0&lt;/code&gt;. In other words, the memory was zeroed! It worked!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;       &lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;a9&lt;/span&gt;   &lt;span class="nv"&gt;stp&lt;/span&gt; &lt;span class="nv"&gt;xzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;xzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But let's not get too excited, yet. We should check that it still works for other types. Changing the code to use &lt;code&gt;u8&lt;/code&gt; instead of &lt;code&gt;u32&lt;/code&gt; (and leaving the drop implementation the same), we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Changed to u8&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;SafeArray&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;SafeArray&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;consume_and_sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Careful! This could overflow!&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compiles to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;&lt;span class="nl"&gt;0000000000000000&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ltmp0&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
       &lt;span class="err"&gt;0:&lt;/span&gt; &lt;span class="mi"&gt;08&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt; &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;lsr&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;
       &lt;span class="err"&gt;4:&lt;/span&gt; &lt;span class="mi"&gt;08&lt;/span&gt; &lt;span class="mi"&gt;41&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt; &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;lsr&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;
       &lt;span class="err"&gt;8:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;61&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;lsr&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;
       &lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;d6&lt;/span&gt;   &lt;span class="nv"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks quite different from the earlier version! The compiler is using a totally different approach. This code is doing is a series of additions involving the original value in &lt;code&gt;w0&lt;/code&gt; and its progressively right-shifted versions. After each shift, the shifted value is added to an accumulating sum. The shifts are by 8, 16, and then 24 bits, effectively breaking &lt;code&gt;w0&lt;/code&gt; into four bytes, adding these bytes together, and storing the final sum back into &lt;code&gt;w0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But where is the zeroizing code!?&lt;/em&gt; For some reason the compiler decided that our code to zeroize was irrelevant and optimized it away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoiding unsafe compiler operations
&lt;/h2&gt;

&lt;p&gt;Compilers are complicated pieces of software and are designed to generate code that is optimal for the target architecture. This means their behaviour can sometimes be hard to reason about and, like in the case above, remove code that is important to security in the interests of performance.&lt;/p&gt;

&lt;p&gt;We need a different approach to ensure our attempts to zeroize data don't get optimized away.&lt;/p&gt;

&lt;p&gt;Thankfully, there is already a crate to do this: &lt;a href="https://crates.io/crates/zeroize" rel="noopener noreferrer"&gt;Zeroize&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;I'll add it to my &lt;code&gt;Cargo.toml&lt;/code&gt; with the &lt;code&gt;derive&lt;/code&gt; feature enabled as we'll use that in a moment. I've also added &lt;code&gt;#[no_mangle]&lt;/code&gt; to the &lt;code&gt;drop&lt;/code&gt; which retains symbol names in the generated assembly code and will make things a bit easier to read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# Cargo.toml&lt;/span&gt;

&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;zeroize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.7.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"derive"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can derive &lt;code&gt;Zeroize&lt;/code&gt; for &lt;code&gt;SafeArray&lt;/code&gt; and call &lt;code&gt;zeroize&lt;/code&gt; in the &lt;code&gt;Drop&lt;/code&gt; implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;zeroize&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zeroize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Zeroize)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;SafeArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Drop&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;SafeArray&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="nf"&gt;.zeroize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiled assembly is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;&lt;span class="nl"&gt;0000000000000000&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ltmp0&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
       &lt;span class="err"&gt;0:&lt;/span&gt; &lt;span class="nv"&gt;ff&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;d1&lt;/span&gt;   &lt;span class="nv"&gt;sub&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;
       &lt;span class="err"&gt;4:&lt;/span&gt; &lt;span class="mi"&gt;08&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt; &lt;span class="mi"&gt;08&lt;/span&gt; &lt;span class="mi"&gt;53&lt;/span&gt;   &lt;span class="nb"&gt;lsr&lt;/span&gt; &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;
       &lt;span class="err"&gt;8:&lt;/span&gt; &lt;span class="nv"&gt;e8&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
       &lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;09&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="mi"&gt;53&lt;/span&gt;   &lt;span class="nb"&gt;lsr&lt;/span&gt; &lt;span class="nv"&gt;w9&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;
      &lt;span class="err"&gt;10:&lt;/span&gt; &lt;span class="nv"&gt;e9&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;w9&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;14:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="mi"&gt;53&lt;/span&gt;   &lt;span class="nb"&gt;lsr&lt;/span&gt; &lt;span class="nv"&gt;w10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;
      &lt;span class="err"&gt;18:&lt;/span&gt; &lt;span class="nv"&gt;ea&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;w10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;08&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt; &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;
      &lt;span class="err"&gt;20:&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt; &lt;span class="nv"&gt;w9&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w9&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w10&lt;/span&gt;
      &lt;span class="err"&gt;24:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt; &lt;span class="mi"&gt;09&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt; &lt;span class="nv"&gt;w0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;w9&lt;/span&gt;
      &lt;span class="err"&gt;28:&lt;/span&gt; &lt;span class="nv"&gt;ff&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;wzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;ff&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;wzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;30:&lt;/span&gt; &lt;span class="nv"&gt;ff&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;wzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;34:&lt;/span&gt; &lt;span class="nv"&gt;ff&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;wzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;38:&lt;/span&gt; &lt;span class="nv"&gt;ff&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;91&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;
      &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;d6&lt;/span&gt;   &lt;span class="nv"&gt;ret&lt;/span&gt;

&lt;span class="nl"&gt;0000000000000040&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;_drop&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
      &lt;span class="err"&gt;40:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;wzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;44:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;04&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;wzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;48:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;08&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;wzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;   &lt;span class="nv"&gt;strb&lt;/span&gt;    &lt;span class="nv"&gt;wzr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;50:&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;d6&lt;/span&gt;   &lt;span class="nv"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a lot more code now but for the most part it is doing the same thing as before (the addition is done over several instructions this time though).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;important part&lt;/strong&gt; is that we have a &lt;code&gt;Drop&lt;/code&gt; implementation that is correctly zeroizing memory 🎉. As you can see, there is the implementation of the &lt;code&gt;Drop&lt;/code&gt; trait, conveniently labeled &lt;code&gt;&amp;lt;_drop&amp;gt;&lt;/code&gt; (thanks to &lt;code&gt;#[no_mangle]&lt;/code&gt;) but that the zeroizing code has also been included (via &lt;em&gt;inlining&lt;/em&gt;) in the summation code above. In this case, the compiler has used the &lt;code&gt;strb&lt;/code&gt; instruction to store the zero register (&lt;code&gt;wzr&lt;/code&gt;) into each element of our array.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;ZeroizeOnDrop&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The Zeroize crate comes with a marker trait called &lt;code&gt;ZeroizeOnDrop&lt;/code&gt; which works for any &lt;code&gt;Zeroize&lt;/code&gt; type and means I don't have to implement &lt;code&gt;Drop&lt;/code&gt; every time. I can derive &lt;code&gt;ZeroizeOnDrop&lt;/code&gt; instead of using my own &lt;code&gt;Drop&lt;/code&gt; implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;zeroize&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Zeroize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ZeroizeOnDrop&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Zeroize,&lt;/span&gt; &lt;span class="nd"&gt;ZeroizeOnDrop)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;SafeArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caution!
&lt;/h2&gt;

&lt;p&gt;Implementing &lt;code&gt;Zeroize&lt;/code&gt; alone won't automatically zeroize memory on drop. &lt;code&gt;Zeroize&lt;/code&gt; just implements the &lt;code&gt;zeroize&lt;/code&gt; method to clear memory. The &lt;code&gt;ZeroizeOnDrop&lt;/code&gt; trait must be implemented as well to automatically zeroize when the value is dropped.&lt;/p&gt;

&lt;h2&gt;
  
  
  But...what about Portable SIMD?
&lt;/h2&gt;

&lt;p&gt;But you may also be asking, what is SIMD!?&lt;/p&gt;

&lt;h2&gt;
  
  
  ...um, what is SIMD?
&lt;/h2&gt;

&lt;p&gt;Single Instruction, Multiple Data (SIMD) is a parallel processing paradigm used in computer architecture to enhance performance by executing the same operation simultaneously on multiple data points. This approach is especially effective for tasks that require the same computation to be repeated over a large data set, such as in digital signal processing, image and video processing, and scientific simulations. In my case, I'm using SIMD for high-performance cryptography implementations.&lt;/p&gt;

&lt;p&gt;SIMD architectures achieve this by employing vector processors or SIMD extensions in CPUs, where a single instruction directs the simultaneous execution of operations on multiple data elements within wider registers. For instance, a SIMD instruction could add or multiply pairs of numbers in a single operation, significantly speeding up computations compared to processing each pair sequentially. This method leverages data-level parallelism, different from the traditional sequential execution model, and is a key feature in modern processors to boost computational efficiency and performance.&lt;/p&gt;

&lt;p&gt;For example, with SIMD I can sum 8 arrays of 4 integers in parallel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#![feature(portable_simd)]&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;simd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Simd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Simd&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nn"&gt;Simd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="nn"&gt;Simd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="nn"&gt;Simd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="nn"&gt;Simd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.reduce&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sums&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 1 + 2 + 1 + 0&lt;/span&gt;
        &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 1 + 2 + 2 + 0&lt;/span&gt;
        &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// etc&lt;/span&gt;
        &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neat, huh?!&lt;/p&gt;

&lt;h2&gt;
  
  
  OK, back to Zeroize for SIMD
&lt;/h2&gt;

&lt;p&gt;While the Zeroize crate is awesome, and you should absolutely use it, it doesn't currently have implementations for the forthcoming &lt;a href="https://rust-lang.github.io/portable-simd/core_simd/simd/struct.Simd.html#" rel="noopener noreferrer"&gt;portable SIMD&lt;/a&gt; modules for Rust. Unlike working with SIMD directly, which requires knowledge of the specific CPU architecture you're building for, Portable SIMD abstracts common CPU vectorizations into a universal interface that works on most architectures.&lt;/p&gt;

&lt;p&gt;I've created a type which wraps &lt;code&gt;Simd&amp;lt;u16, 8&amp;gt;&lt;/code&gt;, a vector of 8 &lt;code&gt;u16&lt;/code&gt; values and a simple method that adds 2 values, consuming both.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;MySimd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Simd&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;MySimd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;consume_and_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated assembly is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;&lt;span class="nl"&gt;0000000000000000&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ltmp0&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
       &lt;span class="err"&gt;0:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
       &lt;span class="err"&gt;4:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;q1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
       &lt;span class="err"&gt;8:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="mi"&gt;84&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt;&lt;span class="mf"&gt;.8&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;  &lt;span class="nv"&gt;v0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;v0&lt;/span&gt;
       &lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;str&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x8&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;10:&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;d6&lt;/span&gt;   &lt;span class="nv"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We just added 8 pairs of numbers in only 5 instructions! Let's try adding a Drop implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Drop&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MySimd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// splat is roughly equivalent to `[0u16; 8]&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;=&lt;/span&gt; &lt;span class="nn"&gt;Simd&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;splat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But oh no! The generated assembly is &lt;strong&gt;identical&lt;/strong&gt;! My drop code was completely ignored 😫.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;&lt;span class="nl"&gt;0000000000000000&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ltmp0&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
       &lt;span class="err"&gt;0:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
       &lt;span class="err"&gt;4:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;q1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
       &lt;span class="err"&gt;8:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="mi"&gt;84&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt;&lt;span class="mf"&gt;.8&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;  &lt;span class="nv"&gt;v0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;v0&lt;/span&gt;
       &lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;str&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x8&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;10:&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;d6&lt;/span&gt;   &lt;span class="nv"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using &lt;code&gt;unsafe&lt;/code&gt; to be &lt;em&gt;safe&lt;/em&gt;!?
&lt;/h2&gt;

&lt;p&gt;Ironically, the only way we can make this code safely and correctly zero memory that may contain sensitive data is to use some &lt;code&gt;unsafe&lt;/code&gt; operations. The Zeroize crate itself uses two approaches to avoid compiler optimizations removing zeroizing code. I'll use them both here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;core&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Drop&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MySimd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;write_volatile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;zeroed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nn"&gt;atomic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;compiler_fence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;atomic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SeqCst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before explaining what's going on, let's first see if it works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;&lt;span class="nl"&gt;0000000000000000&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ltmp0&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
       &lt;span class="err"&gt;0:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;e4&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;   &lt;span class="nv"&gt;movi&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt; &lt;span class="nv"&gt;v0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;0000000000000000&lt;/span&gt;
       &lt;span class="err"&gt;4:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;str&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
       &lt;span class="err"&gt;8:&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;d6&lt;/span&gt;   &lt;span class="nv"&gt;ret&lt;/span&gt;

&lt;span class="nl"&gt;000000000000000c&lt;/span&gt; &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;_consume_and_add&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;:&lt;/span&gt;
       &lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;10:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;ldr&lt;/span&gt; &lt;span class="nv"&gt;q1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;14:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="mi"&gt;84&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="nv"&gt;e&lt;/span&gt;   &lt;span class="nv"&gt;add&lt;/span&gt;&lt;span class="mf"&gt;.8&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt;  &lt;span class="nv"&gt;v0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;v0&lt;/span&gt;
      &lt;span class="err"&gt;18:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;01&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;str&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x8&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="nb"&gt;c&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;e4&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;   &lt;span class="nv"&gt;movi&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt; &lt;span class="nv"&gt;v0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;0000000000000000&lt;/span&gt;
      &lt;span class="err"&gt;20:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;str&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;24:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt;   &lt;span class="nv"&gt;str&lt;/span&gt; &lt;span class="nv"&gt;q0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;28:&lt;/span&gt; &lt;span class="nv"&gt;c0&lt;/span&gt; &lt;span class="mi"&gt;03&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;d6&lt;/span&gt;   &lt;span class="nv"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two functions represent the &lt;code&gt;consume_and_add&lt;/code&gt; method on &lt;code&gt;MySimd&lt;/code&gt; and the &lt;code&gt;drop&lt;/code&gt; method in the &lt;code&gt;Drop&lt;/code&gt; trait. The top function confusingly denoted by &lt;code&gt;ltmp0&lt;/code&gt; (I'm still not sure why) is the Drop code and it contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight armasm"&gt;&lt;code&gt;       &lt;span class="err"&gt;0:&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="nv"&gt;e4&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;   &lt;span class="nv"&gt;movi&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;&lt;span class="nv"&gt;d&lt;/span&gt; &lt;span class="nv"&gt;v0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;0000000000000000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This moves the special zero value into the vector &lt;code&gt;v0&lt;/code&gt; which was dropped. Because the &lt;code&gt;consume_and_add&lt;/code&gt; method returns a vector, only one of the 2 arguments is actually dropped. You can also see that the same code has been inlined into the &lt;code&gt;consume_and_add&lt;/code&gt; function.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, what's going on here?
&lt;/h2&gt;

&lt;p&gt;Firstly, we're using &lt;a href="https://doc.rust-lang.org/std/ptr/fn.write_volatile.html" rel="noopener noreferrer"&gt;write_volatile&lt;/a&gt; to reliably zero the target memory. The Rust compiler guarantees not to mess with it! Unfortunately, the method is unsafe but its the only way to &lt;em&gt;safely&lt;/em&gt; zero the data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxo9knbjx5gqjap4ivu3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxo9knbjx5gqjap4ivu3.gif" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Secondly, we're using what's called an atomic &lt;a href="https://doc.rust-lang.org/stable/core/sync/atomic/fn.compiler_fence.html" rel="noopener noreferrer"&gt;compiler fence&lt;/a&gt; which tells the compiler it is not allowed to reorganize the memory in question. It doesn't prevent the CPU from doing so in hardware though that is a post for another day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Zeroize
&lt;/h2&gt;

&lt;p&gt;Instead of implementing &lt;code&gt;Drop&lt;/code&gt; I can use my custom &lt;code&gt;Zeroize&lt;/code&gt; implementation and then just implement &lt;code&gt;ZeroizeOnDrop&lt;/code&gt; like we did earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Zeroize&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MySimd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;zeroize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nn"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;write_volatile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;zeroed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nn"&gt;atomic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;compiler_fence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;atomic&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SeqCst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;ZeroizeOnDrop&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MySimd&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Better, safer code
&lt;/h2&gt;

&lt;p&gt;While you may not have this exact problem in your day-to-day code, understanding what's happening under the hood can be instructive. And hopefully lead to better and safer code.&lt;/p&gt;

&lt;p&gt;:wq&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Encrypt(Syd) MeetUp</title>
      <dc:creator>Tia</dc:creator>
      <pubDate>Tue, 02 Aug 2022 05:55:46 +0000</pubDate>
      <link>https://dev.to/cipherstash/encryptsyd-meetup-319a</link>
      <guid>https://dev.to/cipherstash/encryptsyd-meetup-319a</guid>
      <description>&lt;p&gt;We'd love it if you were able to join our community_Encrypt(Syd)_and hope to see you at a meetup soon!&lt;br&gt;&lt;br&gt;
We've got some great talks this month, join online or come say hi IRL - &lt;a href="https://www.meetup.com/en-AU/encrypt-syd/events/dwnrssydclbpb/" rel="noopener noreferrer"&gt;https://www.meetup.com/en-AU/encrypt-syd/events/dwnrssydclbpb/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8boxq55vdu5gqy3zkgwi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8boxq55vdu5gqy3zkgwi.png" alt=" " width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>encryption</category>
      <category>eventsinyourcity</category>
      <category>learning</category>
      <category>community</category>
    </item>
  </channel>
</rss>
