<?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: Moritz Höppner</title>
    <description>The latest articles on DEV Community by Moritz Höppner (@moritzhoeppner).</description>
    <link>https://dev.to/moritzhoeppner</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2654748%2F1c035fa1-08b9-4222-80f1-7446847477ee.jpeg</url>
      <title>DEV Community: Moritz Höppner</title>
      <link>https://dev.to/moritzhoeppner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moritzhoeppner"/>
    <language>en</language>
    <item>
      <title>Multiplication in Galois fields with the xtimes function</title>
      <dc:creator>Moritz Höppner</dc:creator>
      <pubDate>Sun, 04 Jan 2026 17:33:31 +0000</pubDate>
      <link>https://dev.to/moritzhoeppner/multiplication-in-galois-fields-with-the-xtimes-function-4ed6</link>
      <guid>https://dev.to/moritzhoeppner/multiplication-in-galois-fields-with-the-xtimes-function-4ed6</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/moritzhoeppner/how-to-implement-ghash-3c0h"&gt;my previous post&lt;/a&gt;, I wrote about finite fields (Galois fields) of order 2&lt;sup&gt;n&lt;/sup&gt;, abbreviated GF(2&lt;sup&gt;n&lt;/sup&gt;). Their elements are congruence classes of polynomials over the field Z2 = { 0, 1 }. Each congruence class consists of all polynomials that leave the same remainder when divided by some fixed polynomial m.&lt;/p&gt;

&lt;p&gt;To multiply two elements B and C from GF(2&lt;sup&gt;n&lt;/sup&gt;), you choose a polynomial b from B and a polynomial c from C, and then calculate d = (b ⋅ c) mod m. The result d is a polynomial, which belongs to some congruence class D in GF(2&lt;sup&gt;n&lt;/sup&gt;). D is the product of B and C.&lt;/p&gt;

&lt;p&gt;In section 4.2 of the &lt;a href="https://www.nist.gov/publications/advanced-encryption-standard-aes-0" rel="noopener noreferrer"&gt;AES spec&lt;/a&gt;, you can find a different algorithm for multiplication in GF(2&lt;sup&gt;8&lt;/sup&gt;), which is conceptually simpler than the algorithm above, because it doesn't need polynomial multiplication and modulo division, but only addition and shifting of coefficients. However, I myself needed some time to understand how exactly the algorithm works and why exactly it is correct. So I decided to write about it and share my understanding of it. That's the first section of this post.&lt;/p&gt;

&lt;p&gt;The AES spec states this algorithm only for GF(2&lt;sup&gt;8&lt;/sup&gt;) but it can easily be generalized to GF(2&lt;sup&gt;n&lt;/sup&gt;) for arbitrary n. And in fact, it is just the algorithm presented in the &lt;a href="https://csrc.nist.gov/pubs/sp/800/38/d/final" rel="noopener noreferrer"&gt;GCM spec&lt;/a&gt; for multiplication in GF(2&lt;sup&gt;128&lt;/sup&gt;), although the spec doesn't say this. So in the second section of this post, I will explain the connection between the algorithms in both specs in more detail. So read until the end if you are - like I was - struggling to understand section 6.3 of the GCM spec on multiplication of blocks. (Why is this pseudo-code correct? What's the magic bit string R?)&lt;/p&gt;

&lt;p&gt;In case you're curious to see the algorithm I'm talking about in code, take a look at &lt;a href="https://github.com/moritzhoeppner/gf-ruby" rel="noopener noreferrer"&gt;my Ruby implementation of it&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiplication in GF(2&lt;sup&gt;8&lt;/sup&gt;) following the AES spec
&lt;/h2&gt;

&lt;p&gt;The goal of the algorithm in the AES spec is to calculate (b ⋅ c) mod m for polynomials b, c of degree &amp;lt; 8 and the fixed polynomial m = x&lt;sup&gt;8&lt;/sup&gt;+x&lt;sup&gt;4&lt;/sup&gt;+x&lt;sup&gt;3&lt;/sup&gt;+x+1. I'll break down the algorithm into three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calculate p ⋅ x for some polynomial p of degree &amp;lt; 8,&lt;/li&gt;
&lt;li&gt;calculate (p ⋅ x) mod m for some polynomial p of degree &amp;lt; 8 (this is called the xtimes function),&lt;/li&gt;
&lt;li&gt;reduce the calculation of (b ⋅ c) mod m to repeated applications of the function from step 2.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Calculation of p ⋅ x
&lt;/h3&gt;

&lt;p&gt;Let's give the coefficients of p names: Let p = p7x&lt;sup&gt;7&lt;/sup&gt; + p6x&lt;sup&gt;6&lt;/sup&gt; + p5x&lt;sup&gt;5&lt;/sup&gt; + p4x&lt;sup&gt;4&lt;/sup&gt; + p3x&lt;sup&gt;3&lt;/sup&gt; + p2x&lt;sup&gt;2&lt;/sup&gt; + p1x + p0. Of course, p doesn't have to have degree 7; p7 can be zero, just as any other coefficient.&lt;/p&gt;

&lt;p&gt;If you multiply p with x, you'll get p ⋅ x = p7x&lt;sup&gt;8&lt;/sup&gt; + p6x&lt;sup&gt;7&lt;/sup&gt; + p5x&lt;sup&gt;6&lt;/sup&gt; + p4x&lt;sup&gt;5&lt;/sup&gt; + p3x&lt;sup&gt;4&lt;/sup&gt; + p2x&lt;sup&gt;3&lt;/sup&gt; + p1x&lt;sup&gt;2&lt;/sup&gt; + p0x.&lt;/p&gt;

&lt;p&gt;If you model polynomials as finite sequences of their coefficients, p is (p7, p6, p5, p4, p3, p2, p1, p0) and p ⋅ x is (p7, p6, p5, p4, p3, p2, p1, p0, 0). So multiplication of polynomials with x is extremely simple: you just have to add a zero to the sequence of coefficients.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calculation of (p ⋅ x) mod m
&lt;/h3&gt;

&lt;p&gt;Now we're going to define the so-called xtimes function. It should satisfy the condition xtimes(p) = (p ⋅ x) mod m. But we don't want to use this equation as definition, as we are searching for something simpler.&lt;/p&gt;

&lt;p&gt;If p ⋅ x has degree &amp;lt; 8 (i.e. if p7 is zero), then (p ⋅ x) mod m is just p ⋅ x. So we can define:&lt;/p&gt;

&lt;p&gt;xtimes(p) = (p6, p5, p4, p3, p2, p1, p0, 0) if p7 = 0.&lt;/p&gt;

&lt;p&gt;(Note that we choose to omit the leading zero coefficient p7. If you actually define polynomials as finite sequences, this omission has to be justified. After all, the sequence (0, p6, p5, p4, p3, p2, p1, p0, 0) is different from the sequence (p6, p5, p4, p3, p2, p1, p0, 0). However, the omission is certainly justified here because in the end, we are interested in finding a representative of a congruence class. And leading zero coefficients surely don't change the congruence class of the polynomial.)&lt;/p&gt;

&lt;p&gt;If, on the other hand, p7 is not zero, we have to calculate the reduction modulo m. In the case of AES, m is fixed, but let's do the reduction for an arbitrary polynomial of degree 8, m = m8x&lt;sup&gt;8&lt;/sup&gt; + m7x&lt;sup&gt;7&lt;/sup&gt; + m6x&lt;sup&gt;6&lt;/sup&gt; + m5x&lt;sup&gt;5&lt;/sup&gt; + m4x&lt;sup&gt;4&lt;/sup&gt; + m3x&lt;sup&gt;3&lt;/sup&gt; + m2x&lt;sup&gt;2&lt;/sup&gt; + m1x + m0. Remember that the coefficients are members of the field Z2 = { 0, 1 }. Addition and subtraction in Z2 are both the XOR operation.&lt;/p&gt;

&lt;p&gt;Since p7 is not zero, it must be 1. And since m has degree 8, we have m8 = 1 as well. So the polynomial long division of p ⋅ x by m looks like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(x&lt;sup&gt;8&lt;/sup&gt; + p6x&lt;sup&gt;7&lt;/sup&gt; + ... + p0x) / (x&lt;sup&gt;8&lt;/sup&gt; + m7x&lt;sup&gt;7&lt;/sup&gt; + ... m1x + m0) = 1&lt;br&gt;
- (x&lt;sup&gt;8&lt;/sup&gt; + m7x&lt;sup&gt;7&lt;/sup&gt; + ... m1x + m0)&lt;br&gt;
-------------------------------&lt;br&gt;
(1 - 1)x&lt;sup&gt;8&lt;/sup&gt; + (p6 - m7)x&lt;sup&gt;7&lt;/sup&gt; + ... + (p0 - m1)x + (0 - m0)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So written as a sequence, the remainder polynomial is (1 - 1, p6 - m7, ...,  p0 - m1, 0 - m0) = (0, p6 - m7, ...,  p0 - m1, m0).&lt;/p&gt;

&lt;p&gt;With the same justification as above, we skip the leading zero. Since subtraction in Z2 is the XOR operation, we can calculate the remainder like this: (p6, p5, p4, p3, p2, p1, p0, 0) XOR (m7, m6, m5, m4, m3, m2, m1, m0).&lt;/p&gt;

&lt;p&gt;Now, back to the spec. Here, m is the fixed polynomial x&lt;sup&gt;8&lt;/sup&gt;+x&lt;sup&gt;4&lt;/sup&gt;+x&lt;sup&gt;3&lt;/sup&gt;+x+1, so the second part of the xtimes definition looks like this:&lt;/p&gt;

&lt;p&gt;xtimes(p) = (p6, p5, p4, p3, p2, p1, p0, 0) XOR (0, 0, 0, 1, 1, 0, 1, 1) if p7 = 1.&lt;/p&gt;

&lt;p&gt;Note that the the algorithm works just as well for other Galois fields GF(2&lt;sup&gt;n&lt;/sup&gt;): For n=8, we only used the fact that m has degree 8. However, the modulus polynomial for GF(2&lt;sup&gt;n&lt;/sup&gt;) has always degree n. Meaning: So far, the algorithm works for every n.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduction of multiplication to xtimes
&lt;/h3&gt;

&lt;p&gt;We can use the xtimes function to calculate (b ⋅ c) mod m for arbitrary polynomials over Z2 of degree &amp;lt; 8. For example, let c be x&lt;sup&gt;2&lt;/sup&gt;+x:&lt;/p&gt;

&lt;p&gt;b ⋅ (x&lt;sup&gt;2&lt;/sup&gt;+x) mod m&lt;br&gt;
= (bx&lt;sup&gt;2&lt;/sup&gt; + bx) mod m&lt;br&gt;
= (bx&lt;sup&gt;2&lt;/sup&gt; mod m) + (bx mod m)&lt;/p&gt;

&lt;p&gt;Okay, (bx mod m) is just xtimes(b), that's good. The first summand can also be expressed in terms of xtimes:&lt;/p&gt;

&lt;p&gt;bx&lt;sup&gt;2&lt;/sup&gt; mod m&lt;br&gt;
= (bx ⋅ x) mod m&lt;br&gt;
= ((bx mod m) ⋅ x) mod m&lt;br&gt;
= (xtimes(b) ⋅ x) mod m&lt;br&gt;
= xtimes(xtimes(b))&lt;/p&gt;

&lt;p&gt;So we have:&lt;/p&gt;

&lt;p&gt;b ⋅ (x&lt;sup&gt;2&lt;/sup&gt;+x) mod m = xtimes(xtimes(b)) + xtimes(b)&lt;/p&gt;

&lt;p&gt;In general, the algorithm for calculating (b ⋅ c) mod m works like this: Apply the xtimes function k times to b if ck is one. Then add all the results.&lt;/p&gt;

&lt;p&gt;All of this works just the same for other Galois fields, even of different orders. So it's no surprise that we find the same algorithm in the GCM spec, where it is used to multiply 128-bit blocks instead of bytes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiplication in GF(2&lt;sup&gt;128&lt;/sup&gt;) following the GCM spec
&lt;/h2&gt;

&lt;p&gt;To spare you the hassle to look it up, here is a screenshot of the multiplication algorithm in the &lt;a href="https://csrc.nist.gov/pubs/sp/800/38/d/final" rel="noopener noreferrer"&gt;GCM spec&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%2Fmsnf70h8rybk5jd09oze.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%2Fmsnf70h8rybk5jd09oze.png" alt="Multiplication in GF(2^128) according to the NIST's GCM spec" width="637" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just like above, one factor is fixed (Y) and the coefficients of the other (X) are inspected.&lt;/p&gt;

&lt;p&gt;The blocks Vi are the results of repeated applications of xtimes to Y. The blocks Zi are the result of adding all Vis that correspond to a coefficient 1.&lt;/p&gt;

&lt;p&gt;The Vi+1 is analogous to the xtimes definition, but there is a little gotcha: In GCM, the order of the coefficient is reversed, so the bit sequence x0x1...x127 represents the polynomial x0 + x1 ⋅ x + ... + x127 ⋅ x&lt;sup&gt;127&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;When I explained above how to calculate p ⋅ x, I represented polynomials by bit sequences and assumed a different ordering, so that the x0x1...x127 would represent the polynomial x0 ⋅ x&lt;sup&gt;127&lt;/sup&gt; + ... + x126 ⋅ x + x127.&lt;/p&gt;

&lt;p&gt;That's why multiplying a polynomial with x is not achieved by shifting the coefficients not to the left but to the right, and that's the explanation for the "&amp;gt;&amp;gt; 1" in the definition of Vi+1.&lt;/p&gt;

&lt;p&gt;It also explains why the distinction between cases in the definition of Vi+1 works by looking at the &lt;em&gt;least&lt;/em&gt; significant (right-most) bit, while the distinction in my xtimes definition worked by looking at the first/left-most/most significant bit.&lt;/p&gt;

&lt;p&gt;And the unusual ordering of coefficients is the reason that the loop in step 3 ranges from 0 to 127, instead of the other way around.&lt;/p&gt;

&lt;p&gt;Finally, the bit string R = 11100001 || 0&lt;sup&gt;120&lt;/sup&gt; is a shifted representation of the modulus polynomial. In the case of GCM, this polynomial is m = x&lt;sup&gt;128&lt;/sup&gt;+x&lt;sup&gt;7&lt;/sup&gt;+x&lt;sup&gt;2&lt;/sup&gt;+x+1. To define xtimes, we discarded the highest order coefficient and wrote the other ones in a bit sequence. This gives us the bit sequence 0&lt;sup&gt;120&lt;/sup&gt; || 10000111. But again, GCM reverses the coefficients, so you end up with R.&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>math</category>
    </item>
    <item>
      <title>How to implement GHASH</title>
      <dc:creator>Moritz Höppner</dc:creator>
      <pubDate>Tue, 30 Dec 2025 07:48:44 +0000</pubDate>
      <link>https://dev.to/moritzhoeppner/how-to-implement-ghash-3c0h</link>
      <guid>https://dev.to/moritzhoeppner/how-to-implement-ghash-3c0h</guid>
      <description>&lt;p&gt;GHASH is the hash function that GCM uses to compute authentication tags. It is defined in &lt;a href="https://csrc.nist.gov/pubs/sp/800/38/d/final" rel="noopener noreferrer"&gt;NIST's GCM spec&lt;/a&gt;. The spec states the algorithm in a way that makes it easy to implement but hides the mathematical background to some extent. In this post, I want to describe the algorithm from a somewhat more mathematical angle and thereby touch on the topic of &lt;em&gt;finite fields&lt;/em&gt; or, synonymously, &lt;em&gt;Galois fields&lt;/em&gt;. I will show you how to implement GHASH in Ruby coming from this point of view.&lt;/p&gt;

&lt;h2&gt;
  
  
  A high-level view on GHASH
&lt;/h2&gt;

&lt;p&gt;GHASH is a keyed hash function. In its NIST version (which is slightly different from its &lt;a href="https://csrc.nist.rip/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf" rel="noopener noreferrer"&gt;original definition&lt;/a&gt;), it takes a 128-bit secret key H and the data to hash X as inputs, where the bit length of X must be a multiple of 128. (Strictly speaking, the spec defines one function for every H with only X as input, but I'll ignore this technicality.) Let X1, ..., Xm be the blocks of X, so that we have X = X1 || X2 ||  ... || Xm. Now we can calculate GHASH like this:&lt;/p&gt;

&lt;p&gt;X1 ⋅ H&lt;sup&gt;m&lt;/sup&gt; + X2 ⋅ H&lt;sup&gt;m-1&lt;/sup&gt;  + ... + Xm ⋅ H&lt;br&gt;
= ∑i=1&lt;sup&gt;m&lt;/sup&gt; (Xi ⋅ H&lt;sup&gt;m-i+1&lt;/sup&gt;)&lt;/p&gt;

&lt;p&gt;Doesn't this look surprisingly simple? It's only adding and multiplying blocks - basically evaluating a polynomial in H.&lt;/p&gt;

&lt;p&gt;However, the catch is this: If we define GHASH as above, we can't add and multiply blocks like we do with ordinary integers. Instead, we need to use special versions of addition and multiplication, which are the operations that make the set of 128-bit blocks a field - a so called &lt;em&gt;Galois field&lt;/em&gt; of order 2&lt;sup&gt;128&lt;/sup&gt;, which is sometimes abbreviated GF(2&lt;sup&gt;128&lt;/sup&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Galois fields
&lt;/h2&gt;

&lt;p&gt;I'll make a few remarks about the theory of Galois fields but they will only touch the surface of the topic. If you want to dive deeper, I recommend having a look at Norman L. Bigg's &lt;em&gt;Discrete Mathematics&lt;/em&gt;. It is very readable and hands-on, contrary to the treatment of the topic in certain Algebra textbooks, which in my experience tend to leave the reader alone with highly abstract definitions and statements.&lt;/p&gt;

&lt;p&gt;Elements of Galois fields are congruence classes of polynomials. More precisely, an element of GF(2&lt;sup&gt;128&lt;/sup&gt;) is the set of all polynomials with coefficients in Z2 = { 0, 1 } that leave the same remainder when divided by a fixed polynomial P of degree 128. Different choices of P yield different Galois fields of the same order, but not every P is suitable; it must have certain properties (which we'll skip here). For GCM/GHASH, we have P(x) = x&lt;sup&gt;128&lt;/sup&gt;+x&lt;sup&gt;7&lt;/sup&gt;+x&lt;sup&gt;2&lt;/sup&gt;+x+1.&lt;/p&gt;

&lt;p&gt;Every element of GF(2&lt;sup&gt;128&lt;/sup&gt;) is a set of polynomials. In each of these sets, there is only one polynomial of degree &amp;lt; 128. (Just as in each congruence class of positive integers modulo p there is only one element &amp;lt; p.) We can choose this polynomial as representative of the congruence class and thus think of GF(2&lt;sup&gt;128&lt;/sup&gt;) as a set of polynomials.&lt;/p&gt;

&lt;p&gt;Okay, so how does addition and multiplication in GF(2&lt;sup&gt;128&lt;/sup&gt;) work? We add two polynomials as we do usually. But remember that we are dealing with polynomials over Z2 = { 0, 1 }, so we add coefficients as elements of the field Z2 - meaning we XOR them: 0+0 = 0, 0+1 = 1+0 = 1, 1+1 = 0. Adding two polynomials of degree &amp;lt; 128 again gives us a polynomial of degree &amp;lt; 128, which consequently is the representative of some element of GF(2&lt;sup&gt;128&lt;/sup&gt;). And we multiply polynomials like we usually do. However, when multiplying two polynomials, their degree can increase, so we might end up with a polynomial of degree &amp;gt;= 128. To find the representative of the congruence class to which this polynomial belongs, we have to reduce it modulo P, i.e. find the remainder when dividing it by P (for example using polynomial long division).&lt;/p&gt;

&lt;p&gt;(In case you're curious how this explanation of multiplication in GF(2&lt;sup&gt;128&lt;/sup&gt;) relates to the pseudo-code given in section 6.3 of the GCM spec, take a look at &lt;a href="https://dev.to/moritzhoeppner/multiplication-in-galois-fields-with-the-xtimes-function-4ed6"&gt;this post&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;By shifting from congruence classes to representatives of congruence classes, we can explain addition and multiplication in Galois fields in terms of addition, multiplication and modulo division of polynomials.&lt;/p&gt;

&lt;p&gt;I have written &lt;a href="https://github.com/moritzhoeppner/z2-polynomial" rel="noopener noreferrer"&gt;a little Ruby gem&lt;/a&gt; that provides the class &lt;code&gt;Z2Polynomial&lt;/code&gt;, which implements addition, multiplication and modulo division for polynomials over Z2. I won't go into the details of this implementation here but use it for the GHASH implementation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Arithmetic of blocks
&lt;/h2&gt;

&lt;p&gt;How do we get from blocks of bits to polynomials to do arithmetic, and then back to interpret the result as a block of bits? Well, the idea is as simple as that: The first bit of the block is the first coefficient of the polynomial, the second bit is the second coefficient and so forth. So, for example, the byte 1101 0010 corresponds to the polynomial x&lt;sup&gt;7&lt;/sup&gt;+x&lt;sup&gt;6&lt;/sup&gt;+x&lt;sup&gt;4&lt;/sup&gt;+x.&lt;/p&gt;

&lt;p&gt;Conveniently, the &lt;code&gt;Z2Polynomial&lt;/code&gt; class has two class methods that do the conversion from blocks to polynomials and back: &lt;code&gt;from_hexstr&lt;/code&gt; and &lt;code&gt;to_hexstr&lt;/code&gt;. For example, 1101 0010 in hexadecimal representation is d2. So we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Z2Polynomial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_hexstr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'d2'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "x^7 + x^6 + x^4 + x"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this mapping from blocks of bits to polynomials is somewhat arbitrary. It is the one you find, for example, in the &lt;a href="https://www.nist.gov/publications/advanced-encryption-standard-aes-0" rel="noopener noreferrer"&gt;AES spec&lt;/a&gt;, but it is by no means the only possible one.&lt;/p&gt;

&lt;p&gt;And, in fact, the GCM spec defines a different mapping from blocks to polynomials: It reverses the order of the coefficients, so that 1101 0010 corresponds to the polynomial x&lt;sup&gt;6&lt;/sup&gt;+x&lt;sup&gt;3&lt;/sup&gt;+x+1. The spec calls this convention "little endian". Both this term and the unusual mapping itself are criticized by Phillip Rogaway in his paper &lt;a href="https://web.cs.ucdavis.edu/~rogaway/papers/modes.pdf" rel="noopener noreferrer"&gt;&lt;em&gt;Evaluation of Some Blockcipher&lt;br&gt;
Modes of Operation&lt;/em&gt;&lt;/a&gt; (pp. 130-131). We will come back later to this little gotcha.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementing GHASH
&lt;/h2&gt;

&lt;p&gt;We're going to implement a class &lt;code&gt;Ghash&lt;/code&gt; with one class method &lt;code&gt;digest&lt;/code&gt; which takes the data and the key as inputs and returns the hash, everything as hex strings. So we want something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Ghash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;input: &lt;/span&gt;&lt;span class="sx"&gt;%w(
    01020304050607080910111213141516
    01020304050607080910111213141516
    abcd
  )&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;key: &lt;/span&gt;&lt;span class="s1"&gt;'01020304050607080910111213141516'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; 'a1a2a3a4a5a6a7a8a9b0b1b2b3b4b5b6'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generating a test vector
&lt;/h3&gt;

&lt;p&gt;How are we going to know our implementation is correct? We'll have to test the &lt;code&gt;digest&lt;/code&gt; function with known GHASH input/output combinations. To get these, we can encrypt any data with AES-GCM, note the authentication tag and derive the GHASH value from it.&lt;/p&gt;

&lt;p&gt;The Web Crypto API keeps the full 128-bit authentication tag and appends it to the ciphertext. Let's encrypt something with it - if you like, you can use &lt;a href="https://moritzhoeppner.github.io/gcm-vs-ctr/" rel="noopener noreferrer"&gt;this web tool&lt;/a&gt; to follow along. I'll use the following inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key (K): &lt;code&gt;e9d83714dc4943a2adc515234bbb543c889a762237a4fde9cfbbc1680a934bd1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;IV: &lt;code&gt;72b83e1eeee393cc7857fb4e&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Plaintext: &lt;code&gt;Hello world! I want something longer than 1 block.&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these inputs, the Web Crypto API implementation of AES-GCM produces the following output: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;127084b89eb8e6f0a47728e519cc4e3e&lt;br&gt;
dc72b11f761467442ba58eda136ba1e1&lt;br&gt;
3ce5546767055019928bf81afe655053&lt;br&gt;
9c03966fb14e503a70622bce17fa0393&lt;br&gt;
48b7&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The first 50 bytes are the actual ciphertext. The remaining 16 bytes are the authentication tag T: &lt;code&gt;966fb14e503a70622bce17fa039348b7&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;From this, we can obtain a GHASH input/output pair when we check the construction of T in the NIST spec of GCM (keeping in mind that we have no AAD and our IV is 96 bits long):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;T is GCTRK(J0, S) = CIPHK(J0) XOR S.&lt;/li&gt;
&lt;li&gt;J0 is the bit string IV || 0&lt;sup&gt;31&lt;/sup&gt; || 1, so in our case and in hexadecimal notation: &lt;code&gt;72b83e1eeee393cc7857fb4e00000001&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;CIPHK(J0) is the AES encryption of J0 with key K. In our case, that's &lt;code&gt;114965dde9be70892a5703ee8242b4b0&lt;/code&gt;, which you can verify with OpenSSL:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 72b83e1eeee393cc7857fb4e00000001 | &lt;span class="se"&gt;\&lt;/span&gt;
  basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; | &lt;span class="se"&gt;\ &lt;/span&gt;    
  openssl enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-aes-256-ecb&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; e9d83714dc4943a2adc515234bbb543c889a762237a4fde9cfbbc1680a934bd1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-nopad&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
  basenc &lt;span class="nt"&gt;--base16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;S is GHASHH(input data).&lt;/li&gt;
&lt;li&gt;The input data is constructed as follows: First, the ciphertext (without the authentication tag) is padded with zeroes so that it is a multiple of 128 bits. Let C* be this padded ciphertext. We concatenate C* with 64 zero bits. Then, we concatenate the result with the bit length of the original ciphertext as a 64-bit integer. In our case, the bit length of the original ciphertext is 50 ⋅ 8 = 400 = 0x190. So the input data is this:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;127084b89eb8e6f0a47728e519cc4e3e&lt;br&gt;
dc72b11f761467442ba58eda136ba1e1&lt;br&gt;
3ce5546767055019928bf81afe655053&lt;br&gt;
9c030000000000000000000000000000&lt;br&gt;
00000000000000000000000000000190&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;H is CIPHK(0&lt;sup&gt;128&lt;/sup&gt;), i.e. the AES encryption of the zero block with key K. In our case, that's &lt;code&gt;c51d75d9ab375617a2f68b5f905ca869&lt;/code&gt;, which you can again verify with OpenSSL:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 00000000000000000000000000000000 | &lt;span class="se"&gt;\&lt;/span&gt;
  basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
  openssl enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-aes-256-ecb&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; e9d83714dc4943a2adc515234bbb543c889a762237a4fde9cfbbc1680a934bd1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-nopad&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
  basenc &lt;span class="nt"&gt;--base16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To get our test vector from this, we calculate S = CIPHK(J0) XOR T:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    114965dde9be70892a5703ee8242b4b0
XOR 966fb14e503a70622bce17fa039348b7
=   8726d493b98400eb0199141481d1fc07
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, so we know that for key &lt;code&gt;c51d75d9ab375617a2f68b5f905ca869&lt;/code&gt; and input data&lt;/p&gt;

&lt;p&gt;&lt;code&gt;127084b89eb8e6f0a47728e519cc4e3e&lt;br&gt;
dc72b11f761467442ba58eda136ba1e1&lt;br&gt;
3ce5546767055019928bf81afe655053&lt;br&gt;
9c030000000000000000000000000000&lt;br&gt;
00000000000000000000000000000190&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;our GHASH implementation should return &lt;code&gt;8726d493b98400eb0199141481d1fc07&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's formulate this expectation as an rspec test!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'digest'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'returns the expected hash'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ghash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="ss"&gt;input: &lt;/span&gt;&lt;span class="sx"&gt;%w(
        127084b89eb8e6f0a47728e519cc4e3e
        dc72b11f761467442ba58eda136ba1e1
        3ce5546767055019928bf81afe655053
        9c030000000000000000000000000000
        00000000000000000000000000000190
      )&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;key: &lt;/span&gt;&lt;span class="s1"&gt;'c51d75d9ab375617a2f68b5f905ca869'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'8726d493b98400eb0199141481d1fc07'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing the digest function
&lt;/h3&gt;

&lt;p&gt;First, we fix the polynomial which is used for reduction. Remember, it is x&lt;sup&gt;128&lt;/sup&gt;+x&lt;sup&gt;7&lt;/sup&gt;+x&lt;sup&gt;2&lt;/sup&gt;+x+1 according to the GCM spec. We can build a &lt;code&gt;Z2Polynomial&lt;/code&gt; object by passing the coefficients as an array to the constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ghash&lt;/span&gt;
  &lt;span class="c1"&gt;# P(x) = x^128 + x^7 + x^2 + x + 1. We pass the coefficients as&lt;/span&gt;
  &lt;span class="c1"&gt;# array to the constructor of Z2Polynomial.&lt;/span&gt;
  &lt;span class="no"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Z2Polynomial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&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="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="mi"&gt;120&lt;/span&gt; &lt;span class="o"&gt;+&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;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;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="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's get to work: Split the input string into blocks, convert them to polynomials, then build the sum X1 ⋅ H&lt;sup&gt;m&lt;/sup&gt; + X2 ⋅ H&lt;sup&gt;m-1&lt;/sup&gt;  + ... + Xm ⋅ H, where the Xis are polynomials that correspond to the blocks and H is a polynomial that corresponds to the key. In the end, we must convert the resulting polynomial back to a hex string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ghash&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
    &lt;span class="c1"&gt;# We start the sum with the zero polynomial (Y_0 in the&lt;/span&gt;
    &lt;span class="c1"&gt;# NIST spec).&lt;/span&gt;
    &lt;span class="n"&gt;digest_pol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Z2Polynomial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&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="c1"&gt;# Convert the key to a polynomial to do GF arithmetic.&lt;/span&gt;
    &lt;span class="n"&gt;key_pol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Z2Polynomial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_hexstr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Split the input string into slices of 32 characters,&lt;/span&gt;
    &lt;span class="c1"&gt;# i.e. 128 bits in hexadecimal representation.&lt;/span&gt;
    &lt;span class="n"&gt;blocks_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:join&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;blocks_hex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;block_hex&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="c1"&gt;# Convert the block to a polynomial to do arithmetic.&lt;/span&gt;
      &lt;span class="n"&gt;block_pol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Z2Polynomial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_hexstr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# Calculate Y_i = (Y_(i-1) + X_i) ⋅ H, where X_i is the&lt;/span&gt;
      &lt;span class="c1"&gt;# i-th block and H is the key.&lt;/span&gt;
      &lt;span class="n"&gt;digest_pol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;digest_pol&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;block_pol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;key_pol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="no"&gt;P&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;# Now, digest_pol is a polynomial that represents the&lt;/span&gt;
    &lt;span class="c1"&gt;# GHASH result. Convert it back to a hex string.&lt;/span&gt;
    &lt;span class="n"&gt;digest_pol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_hexstr&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run the rspec test and ... it fails. The problem here is that Z2Polynomial assumes a different mapping between blocks and polynomials than the GHASH spec - remember the so-called "little endian" convention of GHASH. We can fix this easily: After converting a block to a polynomial, reverse the order of the coefficients; and do the same before converting a polynomial back to a block. All together, we have the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'z2_polynomial'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ghash&lt;/span&gt;
  &lt;span class="c1"&gt;# P(x) = x^128 + x^7 + x^2 + x + 1. We pass the coefficients as&lt;/span&gt;
  &lt;span class="c1"&gt;# array to the constructor of Z2Polynomial.&lt;/span&gt;
  &lt;span class="no"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Z2Polynomial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&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="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="mi"&gt;120&lt;/span&gt; &lt;span class="o"&gt;+&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;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;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="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
      &lt;span class="c1"&gt;# We start the sum with the zero polynomial (Y_0 in the&lt;/span&gt;
      &lt;span class="c1"&gt;# NIST spec).&lt;/span&gt;
      &lt;span class="n"&gt;digest_pol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Z2Polynomial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&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="c1"&gt;# Convert the key to a polynomial to do GF arithmetic.&lt;/span&gt;
      &lt;span class="n"&gt;key_pol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_to_polynomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# Split the input string into slices of 32 characters,&lt;/span&gt;
      &lt;span class="c1"&gt;# i.e. 128 bits in hexadecimal representation.&lt;/span&gt;
      &lt;span class="n"&gt;blocks_hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:join&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="n"&gt;blocks_hex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;block_hex&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="c1"&gt;# Convert the block to a polynomial to do arithmetic.&lt;/span&gt;
        &lt;span class="n"&gt;block_pol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block_to_polynomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Calculate Y_i = (Y_(i-1) + X_i) ⋅ H, where X_i is the&lt;/span&gt;
        &lt;span class="c1"&gt;# i-th block and H is the key.&lt;/span&gt;
        &lt;span class="n"&gt;digest_pol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;digest_pol&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;block_pol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;key_pol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="no"&gt;P&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="c1"&gt;# Now, digest_pol is a polynomial that represents the&lt;/span&gt;
      &lt;span class="c1"&gt;# GHASH result. Convert it back to a hex string.&lt;/span&gt;
      &lt;span class="n"&gt;polynomial_to_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digest_pol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;block_to_polynomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;reverse_coefficients&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Z2Polynomial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_hexstr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;polynomial_to_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;reverse_coefficients&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pol&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_hexstr&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reverse_coefficients&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;# For example, the polynomial x + 1 reversed should be&lt;/span&gt;
      &lt;span class="c1"&gt;# x^127 + x^126. To achieve this, we must pad with zeroes&lt;/span&gt;
      &lt;span class="c1"&gt;# before calling reverse.&lt;/span&gt;
      &lt;span class="n"&gt;pol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pad_to_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, the test passes! 🎉&lt;/p&gt;

</description>
      <category>security</category>
      <category>cryptography</category>
      <category>ruby</category>
      <category>math</category>
    </item>
    <item>
      <title>How to decrypt broken GCM ciphertext</title>
      <dc:creator>Moritz Höppner</dc:creator>
      <pubDate>Sat, 06 Sep 2025 17:00:48 +0000</pubDate>
      <link>https://dev.to/moritzhoeppner/how-to-decrypt-broken-gcm-ciphertext-58a1</link>
      <guid>https://dev.to/moritzhoeppner/how-to-decrypt-broken-gcm-ciphertext-58a1</guid>
      <description>&lt;p&gt;GCM-encrypted data has an authentication tag that serves as an integrity protection mechanism. It is essentially a keyed hash of the ciphertext. If the ciphertext is broken, for example because someone tampered with it or because an encrypted file is corrupted due to hardware issues, the authentication tag no longer matches the ciphertext and becomes invalid.&lt;/p&gt;

&lt;p&gt;Some libraries will refuse to decrypt the ciphertext if the authentication tag is invalid. This is probably a good decision: The whole point of authenticated encryption is to make it impossible to tamper with encrypted data. And it probably prevents security issues and makes developers' lives a little easier, since they don't have to decide whether to authenticate ciphertext. If they use authenticated encryption, the authentication tag must be valid. Period.&lt;/p&gt;

&lt;p&gt;However, if you still want to decrypt the ciphertext, you can choose a GCM implementation that doesn't enforce authentication. OpenSSL is such a library, as you can see from &lt;a href="https://github.com/openssl/openssl/blob/c66d9760a77c5a8ec4b8bdb6000b4213384d0e3e/demos/cipher/aesgcm.c" rel="noopener noreferrer"&gt;this example&lt;/a&gt;. But there is another option that I find interesting because it reveals something about the inner workings of GCM: You can use CTR mode for decryption. This is what I'm going to describe here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Counter Mode
&lt;/h2&gt;

&lt;p&gt;I've written about Counter Mode (CTR) in &lt;a href="https://dev.to/moritzhoeppner/the-counter-mode-manually-4d0"&gt;a previous post&lt;/a&gt;. Its specification doesn't really prescribe a way of generating counter blocks. So you start with any sequence of distinct blocks (called counter blocks). You encrypt them and then XOR the result with your plaintext (to encrypt) or your ciphertext (to decrypt). That's basically it.&lt;/p&gt;

&lt;p&gt;(A quick side note: If you're curious why the counter blocks must be distinct, take a look at &lt;a href="https://dev.to/moritzhoeppner/how-to-break-stream-ciphers-with-repeating-keystreams-3lo5"&gt;this post&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Although &lt;a href="https://csrc.nist.gov/pubs/sp/800/38/a/final" rel="noopener noreferrer"&gt;the CTR spec&lt;/a&gt; doesn't prescribe a way of generating counter blocks, it recommends the so-called &lt;em&gt;standard incrementing function&lt;/em&gt; in Appendix B. The idea is this: You start with any block, usually 128 bits, and you choose how many bits to use as the counter. Say, 32 bits. Now, the standard incrementing function interprets the 32 least-significant bits of the block as an integer and increments it. This can be done again and again until all 32 counter bits are 1. Then the counter "wraps", so in the next block all counter bits will be 0. For example, if the counter length is indeed 32 bits (4 bytes), then a sequence of counter blocks in hexadecimal representation might look like this (starting with a random block):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;63a962e5207b6f0174bfb64ee2d1bcee&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;63a962e5207b6f0174bfb64ee2d1bcef&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;63a962e5207b6f0174bfb64ee2d1bcf0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;63a962e5207b6f0174bfb64ee2d1bcf1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;&lt;code&gt;63a962e5207b6f0174bfb64efffffffe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;63a962e5207b6f0174bfb64effffffff&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;63a962e5207b6f0174bfb64e00000000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;63a962e5207b6f0174bfb64e00000001&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; use CTR in a spec-compliant way and generate your counter blocks differently. But this is the algorithm recommended in the spec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Galois/Counter Mode
&lt;/h2&gt;

&lt;p&gt;Galois/Counter Mode (GCM) doesn't just add the authentication tag to CTR. It is also more specific in three aspects—so you could say, GCM is an extension (adding the authentication tag) of a special case of CTR (being more specific about certain things).&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://csrc.nist.gov/pubs/sp/800/38/d/final" rel="noopener noreferrer"&gt;GCM spec&lt;/a&gt; is more specific than the CTR spec in the following ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Block size: For CTR, you can choose any block size. For GCM, the block size must be 128 bits.&lt;/li&gt;
&lt;li&gt;The incrementing function: GCM makes the standard incrementing function mandatory. GCM also restricts the counter length: It must be 32 bits.&lt;/li&gt;
&lt;li&gt;The initial counter block: For CTR, you can choose any initial counter block, while GCM has a built-in way of generating the first counter block. GCM needs an initialization vector (IV) as input, and the algorithm for generating the first counter block depends on the length of the IV. Usually, you have a 96-bit IV, and in this case the first counter block is &lt;code&gt;IV || 00000002&lt;/code&gt; (the counter part again in hexadecimal representation).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Decrypt GCM ciphertext with CTR
&lt;/h2&gt;

&lt;p&gt;After this little comparison, we can easily decrypt GCM ciphertext with CTR—at least as long as our IV for GCM has a length of 96 bits; the case for other IV lengths is a bit more complicated and I will ignore it for now. For CTR decryption, we simply have to choose the standard incrementing function with a counter length of 32 bits and &lt;code&gt;IV || 00000002&lt;/code&gt; as the initial counter block.&lt;/p&gt;

&lt;p&gt;We can test this idea using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API" rel="noopener noreferrer"&gt;Web Crypto API&lt;/a&gt;. It implements CTR and GCM and, luckily, uses the standard incrementing function for CTR. So we only have to choose the right counter length and initial counter block.&lt;/p&gt;

&lt;p&gt;I have written &lt;a href="https://github.com/moritzhoeppner/gcm-vs-ctr" rel="noopener noreferrer"&gt;a little web tool&lt;/a&gt;, which you can use to play around with this idea. Note that the Crypto API adds the GCM authentication tag to the ciphertext. By default, the authentication tag has a length of 128 bits. So when you encrypt something with GCM in the browser and decrypt the result with CTR, you'll get your original plaintext plus 128 bits of garbage, which are the result of "decrypting" the authentication tag.&lt;/p&gt;

</description>
      <category>security</category>
      <category>cryptography</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to break stream ciphers with repeating keystreams</title>
      <dc:creator>Moritz Höppner</dc:creator>
      <pubDate>Sat, 15 Feb 2025 13:08:53 +0000</pubDate>
      <link>https://dev.to/moritzhoeppner/how-to-break-stream-ciphers-with-repeating-keystreams-3lo5</link>
      <guid>https://dev.to/moritzhoeppner/how-to-break-stream-ciphers-with-repeating-keystreams-3lo5</guid>
      <description>&lt;p&gt;Stream ciphers usually generate a keystream from a secret key and other input. The encryption function XORs the plaintext with the keystream. The decryption function XORs the ciphertext with the keystream. Examples of stream ciphers that work like this are AES-&lt;a href="https://csrc.nist.gov/pubs/sp/800/38/a/final" rel="noopener noreferrer"&gt;CTR&lt;/a&gt; and &lt;a href="https://datatracker.ietf.org/doc/html/rfc7539#section-2.4" rel="noopener noreferrer"&gt;ChaCha20&lt;/a&gt;. If the keystream ever repeats itself, the respective ciphertexts can be decrypted without knowledge of the secret key quite easily. To do this is especially easy if the attacker manages to encrypt a message of their choosing with the repeating part of the keystream. In this post, I will show how the decryption works in such a case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theory
&lt;/h2&gt;

&lt;p&gt;The scenario is this: The attacker wants to decrypt a given ciphertext &lt;code&gt;cipher_secret&lt;/code&gt; and knows a plaintext-ciphertext combination (say, &lt;code&gt;plain_known&lt;/code&gt; and &lt;code&gt;cipher_known&lt;/code&gt;), where &lt;code&gt;cipher_known&lt;/code&gt; has been encrypted with the same keystream as &lt;code&gt;cipher_secret&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cipher_secret = plain_secret XOR keystream
cipher_known = plain_known XOR keystream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cipher_secret&lt;/code&gt; can now be decrypted with just two XOR operations. First, we calculate the keystream:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keystream = 0 XOR keystream
          = (plain_known XOR plain_known) XOR keystream
          = plain_known XOR (plain_known XOR keystream)
          = plain_known XOR cipher_known
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we decrypt &lt;code&gt;cipher_secret&lt;/code&gt; as usual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plain_secret = cipher_secret XOR keystream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let's try this method in a *nix shell! The vulnerable application may encrypt plaintexts with AES-CTR using hard-coded counter blocks. This can be simulated with OpenSSL by using a fixed IV:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="k"&gt;function &lt;/span&gt;enc&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; | openssl enc &lt;span class="nt"&gt;-aes-256-ctr&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; 00000000000000000000000000000000
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use this function to generate the ciphertext known by the attacker:&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="nv"&gt;$ cipher_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;enc &lt;span class="s2"&gt;"I am secret"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$cipher_secret&lt;/span&gt; | hexdump &lt;span class="nt"&gt;-C&lt;/span&gt;
00000000  bb b0 61 db 0a 3a fa b3  db 96 ee                 |..a..:.....|
0000000b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the attacker lets the application encrypt a plaintext with the same length (11 bytes):&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="nv"&gt;$ plain_known&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"01234567890"&lt;/span&gt;
&lt;span class="nv"&gt;$ cipher_known&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;enc &lt;span class="nv"&gt;$plain_known&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll use the &lt;code&gt;xor&lt;/code&gt; shell function from &lt;a href="https://dev.to/moritzhoeppner/the-counter-mode-manually-4d0"&gt;my last post&lt;/a&gt; to do the XORing:&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="nv"&gt;$ keystream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;xor &lt;span class="nv"&gt;$plain_known&lt;/span&gt; &lt;span class="nv"&gt;$cipher_known&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;xor &lt;span class="nv"&gt;$cipher_secret&lt;/span&gt; &lt;span class="nv"&gt;$keystream&lt;/span&gt;
I am secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That worked :)&lt;/p&gt;

&lt;p&gt;The procedure is not dependent on the cipher algorithm, as long as it works by XORing the plaintext/ciphertext with a keystream. For example, you'll get the same result (with different ciphertexts) if you use ChaCha20 instead of AES-CTR:&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="k"&gt;function &lt;/span&gt;enc&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; | openssl enc &lt;span class="nt"&gt;-chacha20&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; 00000000000000000000000000000000
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The case without known plaintext
&lt;/h2&gt;

&lt;p&gt;What if the attacker doesn't know the plaintext corresponding to one of the ciphertexts, i.e. &lt;code&gt;plain_known&lt;/code&gt; isn't actually known? In this situation, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cipher_1 = plain_1 XOR keystream
cipher_2 = plain_2 XOR keystream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cipher_1 XOR cipher_2 = plain_1 XOR plain_2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the attacker can't immediately calculate the plaintexts but the result of XORing two plaintexts, which is also quite bad: If one has some knowledge about the structure of the plaintexts—such as common words or most likely bytes—it becomes surprisingly simple to brute-force one plaintext and thereby reveal the other. I have demonstrated this technique &lt;a href="https://github.com/moritzhoeppner/xor-brute-force" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>The Counter Mode - manually!</title>
      <dc:creator>Moritz Höppner</dc:creator>
      <pubDate>Thu, 06 Feb 2025 19:02:41 +0000</pubDate>
      <link>https://dev.to/moritzhoeppner/the-counter-mode-manually-4d0</link>
      <guid>https://dev.to/moritzhoeppner/the-counter-mode-manually-4d0</guid>
      <description>&lt;p&gt;The counter mode of operation (CTR) is defined in the &lt;a href="https://csrc.nist.gov/pubs/sp/800/38/a/final" rel="noopener noreferrer"&gt;NIST Special Publication 800-38A&lt;/a&gt;, pp. 15-16. I'd summarize it like this: The CTR mode transforms any block cipher into a stream cipher. Encryption and decryption are the same function. They encrypt a sequence of counter blocks and XOR the result with the plaintext (for encryption) or the ciphertext (for decryption).&lt;/p&gt;

&lt;p&gt;My goal here is encrypting a plaintext with AES-256-CTR. And I want to do the CTR part manually, i.e. in my shell only with the usual tools like &lt;code&gt;hexdump&lt;/code&gt;, &lt;code&gt;basenc&lt;/code&gt; and &lt;code&gt;dd&lt;/code&gt;. To encrypt the counter blocks, I'll need OpenSSL - but not in CTR mode!&lt;/p&gt;

&lt;p&gt;The shell is probably not the best tool for something like this. Especially XORing data is a little awkward. Or maybe I just think so because I'm certainly not particularly good at shell programming. However, for now I'll stay with the shell and won't switch to a language like Ruby or Go. This way, you can follow without having to install an interpreter or compiler for my preferred language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;p&gt;Let's say, we want to encrypt the plaintext &lt;code&gt;Lorem ipsum dolor sit amet&lt;/code&gt; with AES-256-CTR. The plaintext in ASCII encoding consist of two 128-bit blocks:&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="nv"&gt;$ P&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Lorem ipsum dolor sit amet"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$P&lt;/span&gt; | hexdump &lt;span class="nt"&gt;-C&lt;/span&gt;
00000000  4c 6f 72 65 6d 20 69 70  73 75 6d 20 64 6f 6c 6f  |Lorem ipsum dolo|
00000010  72 20 73 69 74 20 61 6d  65 74                    |r sit amet|
0000001a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To encrypt them in CTR, we start with two counter blocks, which we save in shell variables:&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="nv"&gt;$ T1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;00000000000000000000000000000000
&lt;span class="nv"&gt;$ T2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;00000000000000000000000000000001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to encrypt them with AES-256. Since both &lt;code&gt;T1&lt;/code&gt; and &lt;code&gt;T2&lt;/code&gt; are exactly one block, we can apply the AES cipher function directly. To do this with OpenSSL, we choose the ECB mode, which simply applies AES block by block. Let's save a 256-bit key in a shell variable and then encrypt the counter blocks:&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="nv"&gt;$ key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
&lt;span class="nv"&gt;$ O1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$T1&lt;/span&gt; | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; | openssl enc &lt;span class="nt"&gt;-aes-256-ecb&lt;/span&gt; &lt;span class="nt"&gt;-K&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="nt"&gt;-nopad&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ O2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$T2&lt;/span&gt; | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; | openssl enc &lt;span class="nt"&gt;-aes-256-ecb&lt;/span&gt; &lt;span class="nt"&gt;-K&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="nt"&gt;-nopad&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need the &lt;code&gt;-nopad&lt;/code&gt; flag here, because otherwise OpenSSL will add a complete padding block to &lt;code&gt;T1&lt;/code&gt; and &lt;code&gt;T2&lt;/code&gt;, respectively.&lt;/p&gt;

&lt;p&gt;Now, we split the plaintext in blocks:&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="nv"&gt;$ P1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$P&lt;/span&gt; | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;skip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ P2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$P&lt;/span&gt; | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;skip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, so the ciphertext will be &lt;code&gt;P1 XOR O1&lt;/code&gt; and &lt;code&gt;P2 XOR O2&lt;/code&gt;. To be precise, the second ciphertext block is actually not &lt;code&gt;P2 XOR O2&lt;/code&gt;, because &lt;code&gt;P2&lt;/code&gt; has only 10 bytes and &lt;code&gt;O2&lt;/code&gt; has 16 bytes. The CTR specification states that the last ciphertext block (which may not be a complete block) &lt;code&gt;Cn&lt;/code&gt; is calculated like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cn = Pn XOR MSB_u(On)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;u&lt;/code&gt; is the length of &lt;code&gt;Pn&lt;/code&gt; and &lt;code&gt;MSB_u(On)&lt;/code&gt; are the &lt;code&gt;u&lt;/code&gt; most significant bytes of &lt;code&gt;On&lt;/code&gt;, i.e. the &lt;code&gt;u&lt;/code&gt; left-most bytes. In our case, &lt;code&gt;u&lt;/code&gt; is 10, so we only need the first 10 bytes of &lt;code&gt;O2&lt;/code&gt;:&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="nv"&gt;$ O2_MSB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$O2&lt;/span&gt; | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay. Now, we need to calculate &lt;code&gt;P1 XOR O1&lt;/code&gt; and &lt;code&gt;P2 XOR O2_MSB&lt;/code&gt;. How do we do that? We could look at the hexdumps, calculate the binary representations and do the XORing by hand. But of course it'd be nice to do it programmatically. As indicated, to do that in the shell is a little awkward.&lt;/p&gt;

&lt;h2&gt;
  
  
  XOR as shell function
&lt;/h2&gt;

&lt;p&gt;We can XOR to &lt;em&gt;integers&lt;/em&gt; (base 10) like this:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
3
&lt;span class="c"&gt;# That's right:&lt;/span&gt;
&lt;span class="c"&gt;#     0110 (6)&lt;/span&gt;
&lt;span class="c"&gt;#     0101 (5)&lt;/span&gt;
&lt;span class="c"&gt;# --------&lt;/span&gt;
&lt;span class="c"&gt;# XOR 0011 (3)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use this syntax, we first convert our data to a hexadecimal representation and then interpret this representation as one number and transform it to base 10:&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="nv"&gt;$ a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;a
&lt;span class="c"&gt;# $a now contains the string 'a', i.e. 0x61&lt;/span&gt;
&lt;span class="nv"&gt;$ a_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$a_hex&lt;/span&gt;
61
&lt;span class="c"&gt;# Great. 0x61 in base 10 is 6*16 + 1 = 97.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="c"&gt;#$a_hex))&lt;/span&gt;
&lt;span class="m"&gt;97&lt;/span&gt;
&lt;span class="c"&gt;# Woohoo!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, we can transform our data into base 10 integers and XOR them. Afterwards, we must transform the integer back to raw data. We can transform a base 10 integer into its hexadecimal representation with &lt;code&gt;printf&lt;/code&gt; and then decode it with &lt;code&gt;basenc&lt;/code&gt;:&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="nv"&gt;$ input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;97
&lt;span class="nv"&gt;$ input_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%02x"&lt;/span&gt; &lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$input_hex&lt;/span&gt;
61
&lt;span class="nv"&gt;$ input_raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$input_hex&lt;/span&gt; | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$input_raw&lt;/span&gt;
a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A side note: We can convert an integer to its hexadecimal representation with &lt;code&gt;printf "%x" $input&lt;/code&gt;. However, this does not necessarily output complete bytes. For example:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%x"&lt;/span&gt; 3
3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But &lt;code&gt;basenc&lt;/code&gt; expects complete bytes with two characters each, so we must pad the output with zeros:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%02x"&lt;/span&gt; 3
03
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, with these ingredients, we can implement an XOR function:&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="k"&gt;function &lt;/span&gt;xor&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;op1_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;op1_dec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="c"&gt;#$op1_hex)))&lt;/span&gt;

  &lt;span class="nv"&gt;op2_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$2&lt;/span&gt; | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;op2_dec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="c"&gt;#$op2_hex)))&lt;/span&gt;

  &lt;span class="nv"&gt;xor_dec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="nv"&gt;$op1_dec&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="nv"&gt;$op2_dec&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;xor_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%02x"&lt;/span&gt; &lt;span class="nv"&gt;$xor_dec&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;n &lt;span class="nv"&gt;$xor_hex&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; basenc &lt;span class="o"&gt;--&lt;/span&gt;base16 &lt;span class="o"&gt;-&lt;/span&gt;d
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we test this function, we may not see an output because it has no printable characters. So we must pipe it to &lt;code&gt;hexdump&lt;/code&gt; or &lt;code&gt;basenc&lt;/code&gt;:&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="nv"&gt;$ &lt;/span&gt;xor e f | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt;
03
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The e character is encoded as 0x65, the f character is encoded as 0x66. 6 XOR 6 is 0, 5 XOR 6 is 3. It works!&lt;/p&gt;

&lt;p&gt;Unfortunately, there is still a problem:&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="nv"&gt;$ &lt;/span&gt;xor &lt;span class="nv"&gt;$P1&lt;/span&gt; &lt;span class="nv"&gt;$O1&lt;/span&gt;
xor:2: number truncated after 17 digits: 4C6F72656D20697073756D20646F6C6F
xor:5: number truncated after 16 digits: F29000B62A499FD0A9F39A6ADD2E7780
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apparently, &lt;code&gt;$((16#...))&lt;/code&gt; cannot handle numbers of the size we need here. A simple solution that works for us is to split the arguments into bytes and XOR them separately:&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="k"&gt;function &lt;/span&gt;xor&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;op_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 &lt;span class="nv"&gt;$op_length&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;op1_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;skip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;i-1&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;op2_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$2&lt;/span&gt; | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;skip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;i-1&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

    &lt;span class="nv"&gt;op1_dec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="c"&gt;#$op1_hex)))&lt;/span&gt;
    &lt;span class="nv"&gt;op2_dec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="c"&gt;#$op2_hex)))&lt;/span&gt;

    &lt;span class="nv"&gt;xor_dec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="nv"&gt;$op1_dec&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="nv"&gt;$op2_dec&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;xor_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%02x"&lt;/span&gt; &lt;span class="nv"&gt;$xor_dec&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nv"&gt;result_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$xor_hex&lt;/span&gt;
    &lt;span class="k"&gt;else
      &lt;/span&gt;&lt;span class="nv"&gt;result_hex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$result_hex$xor_hex&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
  done

  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;n &lt;span class="nv"&gt;$result_hex&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; basenc &lt;span class="o"&gt;--&lt;/span&gt;base16 &lt;span class="o"&gt;-&lt;/span&gt;d
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not an elegant solution, but good enough for the CTR demonstration I'm doing here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to CTR
&lt;/h2&gt;

&lt;p&gt;Now we can calculate the ciphertext:&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="nv"&gt;$ C1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;xor &lt;span class="nv"&gt;$P1&lt;/span&gt; &lt;span class="nv"&gt;$O1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ C2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;xor &lt;span class="nv"&gt;$P2&lt;/span&gt; &lt;span class="nv"&gt;$O2_MSB&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$C1$C2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$C&lt;/span&gt; | hexdump &lt;span class="nt"&gt;-C&lt;/span&gt;
00000000  be ff 72 d3 47 69 f6 a0  da 86 f7 4a b9 41 1b ef  |..r.Gi.....J.A..|
00000010  82 7d 05 c7 3e 99 fe 88  c3 82                    |.&lt;span class="o"&gt;}&lt;/span&gt;..&amp;gt;.....|
0000001a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay good, looks like gibberish. But how do we know if &lt;code&gt;$C&lt;/code&gt; is actually the correct AES-256-CTR ciphertext?&lt;/p&gt;

&lt;p&gt;Well, we can calculate it with OpenSSL and compare:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$P&lt;/span&gt; | openssl enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-aes-256-ctr&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; 00000000000000000000000000000000 &lt;span class="se"&gt;\&lt;/span&gt;
    | hexdump &lt;span class="nt"&gt;-C&lt;/span&gt;
00000000  be ff 72 d3 47 69 f6 a0  da 86 f7 4a b9 41 1b ef  |..r.Gi.....J.A..|
00000010  82 7d 05 c7 3e 99 fe 88  c3 82                    |.&lt;span class="o"&gt;}&lt;/span&gt;..&amp;gt;.....|
0000001a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yep, we did good. :)&lt;/p&gt;

&lt;p&gt;I said above that encryption and decryption are the same function. We can decrypt the ciphertext by XORing the encrypted counter blocks again:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;xor &lt;span class="nv"&gt;$C1&lt;/span&gt; &lt;span class="nv"&gt;$O1&lt;/span&gt;&lt;span class="si"&gt;)$(&lt;/span&gt;xor &lt;span class="nv"&gt;$C2&lt;/span&gt; &lt;span class="nv"&gt;$O2_MSB&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
Lorem ipsum dolor sit amet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beautiful!&lt;/p&gt;

&lt;p&gt;But what's up with the initialization vector? Why just 16 zero bytes? And what does "initialization vector" even mean in the context of CTR? The NIST spec doesn't speak of IVs. Let's have a look at OpenSSL's implementation of CTR!&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenSSL's implementation of CTR
&lt;/h2&gt;

&lt;p&gt;The relevant function is &lt;a href="https://github.com/openssl/openssl/blob/becc0078f8215ffc062f5ba06c73ba51d3b14b6e/crypto/modes/ctr128.c#L73" rel="noopener noreferrer"&gt;CRYPTO_ctr128_encrypt&lt;/a&gt;. When we ignore the lines that are contingent on the OPENSSL_SMALL_FOOTPRINT and STRICT_ALIGNMENT flags, the function becomes pretty simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CRYPTO_ctr128_encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&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="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;ivec&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="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;ecount_buf&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="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;block128_f&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&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="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&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;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ivec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ecount_buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;ctr128_inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ivec&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&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;l&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;ecount_buf&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="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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="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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&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 comment above the function states that &lt;code&gt;*num&lt;/code&gt; and &lt;code&gt;ecount_buf&lt;/code&gt; must be initialized with zeros. So &lt;code&gt;n&lt;/code&gt; starts at 0. The &lt;code&gt;while&lt;/code&gt; loop iterates over the input bytes that belong either to the plaintext (if we are encrypting) or to the ciphertext (if we are decrypting). The first thing that happens in the loop is that the IV &lt;code&gt;ivec&lt;/code&gt; is encrypted with the given block cipher and the result is written to &lt;code&gt;ecount_buf&lt;/code&gt;. The IV is then incremented. A look at &lt;code&gt;ctr128_inc&lt;/code&gt; in the same file shows that this basically means that 1 is added to the IV. Then the first byte of the input is XORed with the first byte of the encrypted IV. In the next 15 iterations, the next input bytes are XORed with the next bytes of the encrypted IV. In the 17th iteration, &lt;code&gt;n&lt;/code&gt; is 0 again. So now the incremented IV is encrypted, and the 17th input byte is then XORed with the first input byte of the result. And so on.&lt;/p&gt;

&lt;p&gt;So when we give OpenSSL an "initialization vector" for CTR, this is the first counter block. Given any counter block, the subsequent counter block is generated by adding 1. This is why we could reproduce our encryption result with the counter blocks &lt;code&gt;T1&lt;/code&gt; and &lt;code&gt;T2&lt;/code&gt; by passing the zero IV to OpenSSL.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose counter blocks
&lt;/h2&gt;

&lt;p&gt;As you might suspect, it is not a very good idea to start the counter blocks with 0 by default. Or, in other words, to set the IV to 0 by default. The NIST spec states in Appendix B (p. 18): "The specification of the CTR mode requires a unique counter block for each plaintext block that is ever encrypted under a given key, across all messages." The authors then give some hints on how this can be achieved. I won't go into these details here. For now, I just wanted to understand the CTR algorithm itself and how it can be implemented in the shell.&lt;/p&gt;

</description>
      <category>security</category>
      <category>cryptography</category>
      <category>bash</category>
      <category>shell</category>
    </item>
    <item>
      <title>How to truncate CBC ciphertext</title>
      <dc:creator>Moritz Höppner</dc:creator>
      <pubDate>Sat, 11 Jan 2025 10:10:44 +0000</pubDate>
      <link>https://dev.to/moritzhoeppner/how-to-truncate-cbc-ciphertext-457o</link>
      <guid>https://dev.to/moritzhoeppner/how-to-truncate-cbc-ciphertext-457o</guid>
      <description>&lt;p&gt;Suppose you have a large CBC ciphertext, say AES-256-CBC encrypted, and you only need the first &lt;code&gt;n&lt;/code&gt; bytes of the plaintext. You might know that it is a text document, and you want to display a preview. Or you might want to determine its format by some &lt;a href="https://en.wikipedia.org/wiki/List_of_file_signatures" rel="noopener noreferrer"&gt;magic bytes&lt;/a&gt; at the beginning of the file.&lt;/p&gt;

&lt;p&gt;You could of course decrypt the whole thing and only use the first &lt;code&gt;n&lt;/code&gt; bytes, but obviously that'd be not very good performance-wise.&lt;/p&gt;

&lt;p&gt;I'll show two ways of truncating CBC ciphertext so that you don't need to decrypt the whole file to get the first bytes. The idea is very simple: Remove everything from the ciphertext but the first blocks. But there is one gotcha, and that's padding. So I'll write a little about that. To reproduce the example, you need a *nix shell, the OpenSSL command line utility, hexdump, basenc (from GNU coreutils) and dd.&lt;/p&gt;

&lt;p&gt;Let's prepare an example plaintext and ciphertext:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"Lorem ipsum dolor sit amet, consetetur"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; lorem.txt
&lt;span class="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; lorem.txt &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-out&lt;/span&gt; lorem.enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Decryption is done block by block, instead of decrypting the first &lt;code&gt;n&lt;/code&gt; bytes, we decrypt the first &lt;code&gt;m&lt;/code&gt; blocks, where &lt;code&gt;m&lt;/code&gt; is the smallest multiple of the block size (16 bytes in our case), so that &lt;code&gt;m * { block size } &amp;lt;= n&lt;/code&gt;. In this tutorial, I'll decrypt the first block.&lt;/p&gt;

&lt;h2&gt;
  
  
  The naive approach
&lt;/h2&gt;

&lt;p&gt;If we only want to decrypt the first block, we should be able to remove everything else from the ciphertext:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lorem.enc &lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lorem-truncated.enc &lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And decrypt:&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="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; lorem-truncated.enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c
bad decrypt
408F800302000000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:providers/implementations/ciphers/ciphercommon_block.c:107:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, that didn't work. The last command should result in a "bad decrypt" error message, raised in OpenSSL's &lt;a href="https://github.com/openssl/openssl/blob/3ffa64cd4566cb2d14f6b871e02460f54e1d4da1/providers/implementations/ciphers/ciphercommon_block.c#L107" rel="noopener noreferrer"&gt;providers/implementations/ciphers/ciphercommon_block.c:107&lt;/a&gt;. We can see in the source code that OpenSSL looks at the last byte of the given block &lt;code&gt;buf&lt;/code&gt; and raises an error if this byte is 0 or greater than the block size, i.e. greater than 16 or 0x10.&lt;/p&gt;

&lt;p&gt;Let's play a little with OpenSSL to find out why this happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playing with OpenSSL
&lt;/h2&gt;

&lt;p&gt;To simplify the following shell commands, we can make tiny shell scripts for encryption and decryption:&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;# enc.sh&lt;/span&gt;

openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# dec.sh&lt;/span&gt;

openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, so the first question is: Is &lt;code&gt;buf&lt;/code&gt; a block of the plaintext or the ciphertext? Shouldn't it be part of the ciphertext because the error occured &lt;em&gt;during decryption&lt;/em&gt;? Let's find out.&lt;/p&gt;

&lt;p&gt;The truncated ciphertext looks like this:&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="nv"&gt;$ &lt;/span&gt;hexdump &lt;span class="nt"&gt;-C&lt;/span&gt; lorem-truncated.enc                                                 
00000000  81 90 91 f9 c1 33 1b fb  6d 49 3f d5 c5 04 43 89  |.....3..mI?...C.|
00000010
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can change the last byte to something between 0x00 and 0x10, say 0x0a, to see if the error message changes:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;819091f9c1331bfb6d493fd5c504430a | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; | ./dec.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nope, still the same.&lt;/p&gt;

&lt;p&gt;Okay, now the same with the plaintext. Currently, we have:&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="nv"&gt;$ &lt;/span&gt;hexdump &lt;span class="nt"&gt;-C&lt;/span&gt; lorem.txt
00000000  4c 6f 72 65 6d 20 69 70  73 75 6d 20 64 6f 6c 6f  |Lorem ipsum dolo|
00000010  72 20 73 69 74 20 61 6d  65 74 2c 20 63 6f 6e 73  |r sit amet, cons|
00000020  65 74 65 74 75 72                                 |etetur|
00000030
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we truncate the second and third block of the ciphertext anyway, we ignore the corresponding plaintext blocks for the moment. We can reproduce the problem with only one input block:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;4c6f72656d20697073756d20646f6c6f &lt;span class="se"&gt;\&lt;/span&gt;
    | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | ./enc.sh &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="se"&gt;\&lt;/span&gt;
    | ./dec.sh
bad decrypt
408F800302000000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:providers/implementations/ciphers/ciphercommon_block.c:107:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our little experiment. We change the last byte to 0x0a:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;4c6f72656d20697073756d20646f6c0a &lt;span class="se"&gt;\&lt;/span&gt;
    | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | ./enc.sh &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="se"&gt;\&lt;/span&gt;
    | ./dec.sh
bad decrypt
408F800302000000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:providers/implementations/ciphers/ciphercommon_block.c:112:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, we still get a "bad decrypt" error. But: It is raised now in line 112 instead of line 107! It seems that we passed the check in ciphercommon_block.c:106 and now run into a different problem. Let's play a little with this to make sure we got it right:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;4c6f72656d20697073756d20646f6c00 &lt;span class="se"&gt;\&lt;/span&gt;
    | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | ./enc.sh &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="se"&gt;\&lt;/span&gt;
    | ./dec.sh
&lt;span class="c"&gt;# Last byte is 0x00 -&amp;gt; error in line 107&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;4c6f72656d20697073756d20646f6c10 &lt;span class="se"&gt;\&lt;/span&gt;
    | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | ./enc.sh &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="se"&gt;\&lt;/span&gt;
    | ./dec.sh
&lt;span class="c"&gt;# Last byte is 0x10 (block size) -&amp;gt; error in line 112&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;4c6f72656d20697073756d20646f6c11 &lt;span class="se"&gt;\&lt;/span&gt;
    | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | ./enc.sh &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="se"&gt;\&lt;/span&gt;
    | ./dec.sh
&lt;span class="c"&gt;# Last byte is 0x11 (&amp;gt; block size) -&amp;gt; error in line 107&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great. So the decryption fails &lt;em&gt;after&lt;/em&gt; decrypting a block, the problem is the format of the &lt;em&gt;plaintext&lt;/em&gt;. First of all, the last byte of the plaintext has to be greater than 0 and smaller than or equal to the block size.&lt;/p&gt;

&lt;p&gt;Now, if the last byte is correct, why is an error raised in &lt;a href="https://github.com/openssl/openssl/blob/aececda752d182f271bf2263f5ef9020a64668c5/providers/implementations/ciphers/ciphercommon_block.c#L112" rel="noopener noreferrer"&gt;ciphercommon_block.c:112&lt;/a&gt;? The &lt;code&gt;for&lt;/code&gt; loop looks at the last &lt;code&gt;pad&lt;/code&gt; bytes of the block, where &lt;code&gt;pad&lt;/code&gt; is the last byte itself. If one of these bytes is not equal to &lt;code&gt;pad&lt;/code&gt;, an error is raised. So if &lt;code&gt;pad&lt;/code&gt; is 0x01, the &lt;code&gt;for&lt;/code&gt; loop only looks at the last byte itself. Let's try it:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;4c6f72656d20697073756d20646f6c01 &lt;span class="se"&gt;\&lt;/span&gt;
    | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | ./enc.sh &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="se"&gt;\&lt;/span&gt;
    | ./dec.sh
Lorem ipsum dol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works! But, of course, we lost the last byte to satisfy OpenSSL. If &lt;code&gt;pad&lt;/code&gt; is 0x02, the &lt;code&gt;for&lt;/code&gt; loop looks at the last two bytes and requires both of them to be 0x02:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;4c6f72656d20697073756d20646f0202 &lt;span class="se"&gt;\&lt;/span&gt;
    | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | ./enc.sh &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="se"&gt;\&lt;/span&gt;
    | ./dec.sh
Lorem ipsum &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above, we tried 0x10 as last byte. Now we know that if the last byte is 0x10 (the block size), then every byte of the block has to be 0x10:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;10101010101010101010101010101010 &lt;span class="se"&gt;\&lt;/span&gt;
    | basenc &lt;span class="nt"&gt;--base16&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | ./enc.sh &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="se"&gt;\&lt;/span&gt;
    | ./dec.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As expected, no error occurs, but also no plaintext is left.&lt;/p&gt;

&lt;h2&gt;
  
  
  Padding
&lt;/h2&gt;

&lt;p&gt;We found out that the last bytes of our plaintext block &lt;em&gt;must&lt;/em&gt; be one of these, or else OpenSSL complains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;01
0202
030303
...
10101010101010101010101010101010
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are padding bytes. When encrypting data, OpenSSL adds them to the plaintext so that the length of the data is a multiple of 16 bytes. After all, block ciphers need blocks of a fixed length as input, 16 bytes in the case of AES. If the plaintext length is already a multiple of 16 bytes, a whole block of 0x10 padding bytes is added. So the last byte is always a padding byte. This last byte is &lt;code&gt;B&lt;/code&gt; the last &lt;code&gt;B&lt;/code&gt; bytes are removed from the plaintext after decryption.&lt;/p&gt;

&lt;p&gt;This is one of many possible padding schemes, called PKCS #7. You might get a little confused when you try to find its specification. At least, I did. PKCS #7 was the name of a standard for a format to store encrypted data in. It describes something called "envelope encryption", which means data is encrypted, and then the encryption key is itself encrypted and sent together with the encrypted data. &lt;a href="https://datatracker.ietf.org/doc/html/rfc2315#section-10.3" rel="noopener noreferrer"&gt;RFC 2315&lt;/a&gt; describes this process and mentions in passing the above padding scheme. And even symmetric encryption doesn't necessarily have anything to do with envelope encryption, the padding scheme is now called PKCS #7. Basically the same scheme (only for smaller block sizes) is described in the PKCS #5 standard (&lt;a href="https://datatracker.ietf.org/doc/html/rfc1423#section-1.1" rel="noopener noreferrer"&gt;RFC 1423&lt;/a&gt;), again in a very specific context, here of DES-CBC encryption. To add some more confusion, PKCS #7 is today obsoleted by something called CMS, described in &lt;a href="https://datatracker.ietf.org/doc/html/rfc5652" rel="noopener noreferrer"&gt;RFC 5652&lt;/a&gt;. And this specification describes the same padding scheme.&lt;/p&gt;

&lt;p&gt;We can see the padding bytes added by OpenSSL during encryption with the &lt;code&gt;-nopad&lt;/code&gt; flag:&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="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; lorem.enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-nopad&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | hexdump &lt;span class="nt"&gt;-C&lt;/span&gt;
00000000  4c 6f 72 65 6d 20 69 70  73 75 6d 20 64 6f 6c 6f  |Lorem ipsum dolo|
00000010  72 20 73 69 74 20 61 6d  65 74 2c 20 63 6f 6e 73  |r sit amet, cons|
00000020  65 74 65 74 75 72 0a 0a  0a 0a 0a 0a 0a 0a 0a 0a  |etetur..........|
00000030
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Back to the truncating problem
&lt;/h2&gt;

&lt;p&gt;I think the best option for truncating the ciphertext is to use the &lt;code&gt;-nopad&lt;/code&gt; flag. Then OpenSSL treats padding bytes as plaintext, meaning it doesn't expect any padding bytes:&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="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; lorem-truncated.enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-nopad&lt;/span&gt;
Lorem ipsum dolo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, we are done. The naive approach was almost right, we simply had to add &lt;code&gt;-nopad&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But just for fun, I want to show you another possibility I thought of before I knew the &lt;code&gt;-nopad&lt;/code&gt; option existed.&lt;/p&gt;

&lt;p&gt;We know that the last block of the ciphertext contains the encrypted padding bytes. So we can simply keep this last block. However, the last block can only be decrypted properly if the second-to-last ciphertext block is also present, as in CBC mode, any decrypted block is XORed with the ciphertext block before. So we keep the last two blocks. This means that our truncated ciphertext has at least three blocks. Our original plaintext had only three blocks to begin with, so to demonstrate the procedure, we need a slightly longer plaintext.&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; lorem.txt
&lt;span class="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; lorem.txt &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-out&lt;/span&gt; lorem.enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c
&lt;span class="nv"&gt;$ &lt;/span&gt;hexdump &lt;span class="nt"&gt;-C&lt;/span&gt; lorem.enc
00000000  81 90 91 f9 c1 33 1b fb  6d 49 3f d5 c5 04 43 89  |.....3..mI?...C.|
00000010  a2 47 23 26 af 09 04 6e  f3 f6 1a b7 16 b9 95 18  |.G#&amp;amp;...n........|
00000020  93 9c e7 f4 23 a2 2e c6  c5 49 e1 73 65 52 cc 92  |....#....I.seR..|
00000030  48 b3 8f c6 61 50 50 52  1d bf bf 43 b4 c8 d8 8a  |H...aPPR...C....|
00000040
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our new &lt;code&gt;lorem-truncated.enc&lt;/code&gt; contains the first and last two blocks of &lt;code&gt;lorem.enc&lt;/code&gt;:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lorem.enc &lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lorem-truncated.enc &lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lorem.enc &lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;skip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; lorem-truncated.enc
&lt;span class="nv"&gt;$ &lt;/span&gt;hexdump &lt;span class="nt"&gt;-C&lt;/span&gt; lorem-truncated.enc
00000000  81 90 91 f9 c1 33 1b fb  6d 49 3f d5 c5 04 43 89  |.....3..mI?...C.|
00000010  93 9c e7 f4 23 a2 2e c6  c5 49 e1 73 65 52 cc 92  |....#....I.seR..|
00000020  48 b3 8f c6 61 50 50 52  1d bf bf 43 b4 c8 d8 8a  |H...aPPR...C....|
00000030
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenSSL can decrypt this file without errors:&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="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; lorem-truncated.enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    | hexdump &lt;span class="nt"&gt;-C&lt;/span&gt;
00000000  4c 6f 72 65 6d 20 69 70  73 75 6d 20 64 6f 6c 6f  |Lorem ipsum dolo|
00000010  46 a3 d7 ab 1b 48 3f e6  ff db 4c 12 a0 de bf ff  |F....H?...L.....|
00000020  67 20 65 6c 69 74 72 2c  20 73 65 64 0a           |g elitr, sed.|
0000002d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second block is garbage because OpenSSL XORed the decrypted block with the first block of &lt;code&gt;lorem-truncated.enc&lt;/code&gt;. But it should be XORed with the second block of &lt;code&gt;lorem.enc&lt;/code&gt;, which isn't there anymore.&lt;/p&gt;

&lt;p&gt;But we can of course simple remove the garbage block and the padding block from the plaintext:&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="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; lorem-truncated.enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none
Lorem ipsum dolo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>security</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Bit flipping Attack on CBC: Change of the Ciphertext</title>
      <dc:creator>Moritz Höppner</dc:creator>
      <pubDate>Sun, 05 Jan 2025 17:55:31 +0000</pubDate>
      <link>https://dev.to/moritzhoeppner/bitflip-attack-on-cbc-change-of-the-ciphertext-4h68</link>
      <guid>https://dev.to/moritzhoeppner/bitflip-attack-on-cbc-change-of-the-ciphertext-4h68</guid>
      <description>&lt;p&gt;Just like in &lt;a href="https://dev.to/moritzhoeppner/bitflip-attack-on-cbc-change-of-the-iv-6ml"&gt;yesterday's tutorial&lt;/a&gt;, I want to demonstrate a bit flipping attack on an AES-CBC encrypted ciphertext. This time, we won't change the first plaintext block by tampering with the IV but the second one by tampering with the first ciphertext block. To follow along, you'll need a shell on a *nix system, the OpenSSL command line utility, hexdump, dd and basenc (which is part of GNU corutils).&lt;/p&gt;

&lt;p&gt;The attack doesn't depend on the block cipher (although I'll be using the fact that AES has a block size of 128 bit) but only on the mode of operation, which is CBC. For an introduction to CBC, take a look at &lt;a href="https://www.crypto101.io/" rel="noopener noreferrer"&gt;Crypto 101&lt;/a&gt;, which contains a nice explanation of the kind of attack I'm about to show. My goal here is simply to show how to actually do it, how to calculate the bytes, how to read and write the encrypted files.&lt;/p&gt;

&lt;p&gt;The original plaintext is the following HTML document (UTF-8 encoded):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    Hello World!
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We save it as &lt;code&gt;secret.html&lt;/code&gt; and generate the ciphertext with OpenSSL (the exact values for the IV and key don't matter, I'm using simply some MD5 hash):&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="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; secret.html &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secret.enc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at both files with hexdump:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ hexdump -C secret.html    
00000000  3c 21 44 4f 43 54 59 50  45 20 68 74 6d 6c 3e 0a  |&amp;lt;!DOCTYPE html&amp;gt;.|
00000010  3c 68 74 6d 6c 3e 0a 20  20 3c 62 6f 64 79 3e 0a  |&amp;lt;html&amp;gt;.  &amp;lt;body&amp;gt;.|
00000020  20 20 20 20 48 65 6c 6c  6f 20 57 6f 72 6c 64 21  |    Hello World!|
00000030  0a 20 20 3c 2f 62 6f 64  79 3e 0a 3c 2f 68 74 6d  |.  &amp;lt;/body&amp;gt;.&amp;lt;/htm|
00000040  6c 3e                                             |l&amp;gt;|
00000042
$ hexdump -C secret.enc     
00000000  09 58 ca bb 89 66 e7 85  31 70 5a 4b 54 59 1e b0  |.X...f..1pZKTY..|
00000010  b4 1d 57 94 12 53 d0 0b  79 3f 0e b6 67 c7 a6 7e  |..W..S..y?..g..~|
00000020  42 78 e1 39 5f 3c 8a f6  9b 2a c1 0d 3e bd 97 75  |Bx.9_&amp;lt;...*..&amp;gt;..u|
00000030  c0 c9 42 08 cf d2 c5 a8  16 cd ee 73 1a af ce 7c  |..B........s...||
00000040  d8 2b bc 4a 38 04 69 80  01 91 6b d1 74 5d 52 9d  |.+.J8.i...k.t]R.|
00000050
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AES block size is 128 bit, which means 16 bytes, so exactly one row of the hexdump output. You can see that the last plaintext row is smaller than one block. In this case the missing bytes are added before the encryption. This is called &lt;em&gt;padding&lt;/em&gt; and is the reason the ciphertext has 5 complete blocks.&lt;/p&gt;

&lt;p&gt;In CBC mode, decryption of ciphertext blocks other than the first one works like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{n+1-th plaintext block} =
  AES_decrypt({n+1-th ciphertext block}, key) XOR
  {n-th ciphertext block}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So by changing the n-th ciphertext block, we can change the outcome of the decryption of the n+1-th ciphertext block.&lt;/p&gt;

&lt;p&gt;Okay, let's change the start of the second block from &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; to &lt;code&gt;:)____&lt;/code&gt;, where &lt;code&gt;_&lt;/code&gt; denotes a whitespace character. We do this by changing the first block of the ciphertext. The algorithm for this is exactly the same as in &lt;a href="https://dev.to/moritzhoeppner/bitflip-attack-on-cbc-change-of-the-iv-6ml"&gt;the case of the IV&lt;/a&gt;, with the only difference that we use the first ciphertext block instead of the IV.&lt;/p&gt;

&lt;p&gt;As we can see in the hexdump, the hexadecimal UTF-8 representation of &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; is 3c68746d6c3e. The one of &lt;code&gt;:)____&lt;/code&gt; is 3a2920202020. Let C be the first six bytes of the ciphertext. We replace them by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  C XOR ("&amp;lt;html&amp;gt;" XOR ":)    ")
= 399ef6c358ca XOR (3c68746d6c3e XOR 3a2920202020)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's do it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    0011 1100 0110 1000 0111 0100 0110 1101 0110 1100 0011 1110 (3c68746d6c3e "&amp;lt;html&amp;gt;")
XOR 0011 1010 0010 1001 0010 0000 0010 0000 0010 0000 0010 0000 (3a2920202020, ":)   ")
    -----------------------------------------------------------
    0000 0110 0100 0001 0101 0100 0100 1101 0100 1100 0001 1110

    0000 1001 0101 1000 1100 1010 1011 1011 1000 1001 0110 0110 (0958cabb8966, start of first block)
XOR 0000 0110 0100 0001 0101 0100 0100 1101 0100 1100 0001 1110 (last result)
    -----------------------------------------------------------
    0000 1111 0001 1001 1001 1110 1111 0110 1100 0101 0111 1000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we must replace the first 6 bytes of the ciphertext by 0f199ef6c578. First, we write these bytes in a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ echo 0f199ef6c578 | basenc --base16 -d &amp;gt; secret-modified.enc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we add everything from secret.enc but the first 6 bytes to the new file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dd if=secret.enc bs=6 skip=1 &amp;gt;&amp;gt; secret-modified.enc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we decrypt the modified file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ openssl enc -aes-256-cbc -d \
    -in secret-modified.enc \
    -iv be154e2343408caa1f11ab3445bdd34c \
    -K be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c \
    &amp;gt; secret-modified.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the &lt;code&gt;secret-modified.html&lt;/code&gt; file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ binary garbage }:)
  &amp;lt;body&amp;gt;
    Hello World!
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, we managed to replace &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; (the start of the second block) by &lt;code&gt;:)&lt;/code&gt;. The only problem is that we had to change the first ciphertext block for this. So the first plaintext block is of course no longer &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/code&gt; but just 16 bytes of garbage.&lt;/p&gt;

&lt;p&gt;Two thoughts on this garbage phenomenon. First, it shows how resistant the CBC mode is against data corruption. After all, we have only one block of garbage, the rest of the decrypted file seems okay. And in fact, if one block of the ciphertext is corrupted, only itself and the following block are impacted. &lt;/p&gt;

&lt;p&gt;Second, if we are lucky, we might be able to hide the 16 bytes of garbage from our victim that decrypts and displays the file we tampered with. An HTML document will likely be displayed in a browser. So we could try to choose the changed block in a way that the garbage bytes become part of an (not exactly spec compliant) HTML tag. For example, if there was no newline after &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/code&gt;, the hexdump of our original &lt;code&gt;secret.html&lt;/code&gt; would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ hexdump -C secret.html       
00000000  3c 21 44 4f 43 54 59 50  45 20 68 74 6d 6c 3e 3c  |&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;|
00000010  68 74 6d 6c 3e 0a 20 20  3c 62 6f 64 79 3e 0a 20  |html&amp;gt;.  &amp;lt;body&amp;gt;. |
00000020  20 20 20 48 65 6c 6c 6f  20 57 6f 72 6c 64 21 0a  |   Hello World!.|
00000030  20 20 3c 2f 62 6f 64 79  3e 0a 3c 2f 68 74 6d 6c  |  &amp;lt;/body&amp;gt;.&amp;lt;/html|
00000040  3e                                                |&amp;gt;|
00000041
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In such a scenario we could tamper with the second ciphertext block and try to change the third block to something containing &lt;code&gt;&amp;gt;:)&lt;/code&gt;. For example, the result could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ hexdump -C secret-modified.html       
00000000  3c 21 44 4f 43 54 59 50  45 20 68 74 6d 6c 3e 3c  |&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;|
00000010  xx xx xx xx xx xx xx xx  xx xx xx xx xx xx xx xx  |    garbage     |
00000020  3e 3a 29 48 65 6c 6c 6f  20 57 6f 72 6c 64 21 0a  |&amp;gt;:)Hello World!.|
00000030  20 20 3c 2f 62 6f 64 79  3e 0a 3c 2f 68 74 6d 6c  |  &amp;lt;/body&amp;gt;.&amp;lt;/html|
00000040  3e                                                |&amp;gt;|
00000041
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the user will never see the suspicous 16 bytes of garbage, because the browser ignores tags it doesn't know.&lt;/p&gt;

</description>
      <category>security</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Bit flipping Attack on CBC: Change of the IV</title>
      <dc:creator>Moritz Höppner</dc:creator>
      <pubDate>Sat, 04 Jan 2025 07:21:33 +0000</pubDate>
      <link>https://dev.to/moritzhoeppner/bitflip-attack-on-cbc-change-of-the-iv-6ml</link>
      <guid>https://dev.to/moritzhoeppner/bitflip-attack-on-cbc-change-of-the-iv-6ml</guid>
      <description>&lt;p&gt;Given an AES-CBC encrypted ciphertext, it is possible to change the outcome of the decryption in a predictable way: If you know some bytes of the first plaintext block, you can change these bytes by changing the initialization vector (IV). This is one type of a so called &lt;em&gt;bit flipping attack&lt;/em&gt;. It doesn't matter if we use AES or some other block cipher. But I will demonstrate the attack with AES-256. To follow this tutorial, you'll only need a shell on a *nix operating system with the OpenSSL command line utility installed.&lt;/p&gt;

&lt;p&gt;I won't explain the details of CBC; if you're not familiar with it, I recommend the relevant section of &lt;a href="https://www.crypto101.io/" rel="noopener noreferrer"&gt;Crypto 101&lt;/a&gt;. There you'll find also the description of a more realistic use case for bit flipping attacks, that is: smuggling content into encrypted cookies.&lt;/p&gt;

&lt;p&gt;Let's say, the original plaintext is &lt;code&gt;&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;&lt;/code&gt;, encoded in UTF-8 or some similar encoding scheme (similar in the sense that one ASCII character is encoded by one byte and that the encoding is an extension of ASCII).&lt;/p&gt;

&lt;p&gt;To generate the ciphertext, we need a 256-bit key and an IV with the length of one&lt;br&gt;
block, i.e. 128 bit. We'll use &lt;code&gt;be154e2343408caa1f11ab3445bdd34c&lt;/code&gt; as IV and&lt;br&gt;
&lt;code&gt;be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c&lt;/code&gt; as key (both are given here in hexadecimal representation).&lt;/p&gt;

&lt;p&gt;We generate the ciphertext with OpenSSL:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;p&amp;gt;Hello World!&amp;lt;/p&amp;gt;"&lt;/span&gt; | openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; be154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ciphertext.enc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's assume that we want the decrypted text to be &lt;code&gt;:) Hello World!&amp;lt;/p&amp;gt;&lt;/code&gt;. This means that the IV must be changed so that &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; (&lt;code&gt;3c703e&lt;/code&gt; in hexadecimal UTF-8 representation) becomes &lt;code&gt;:)_&lt;/code&gt; (&lt;code&gt;3a2920&lt;/code&gt; in hexadecimal UTF-8 representation), where &lt;code&gt;_&lt;/code&gt; denotes a whitespace character.&lt;/p&gt;

&lt;p&gt;To generate the new IV, take the first three bytes of the original IV, say &lt;code&gt;abc&lt;/code&gt;, and calculate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  abc XOR ("&amp;lt;p&amp;gt;" XOR ":) ")
= be154e XOR (3c703e XOR 3a2920)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll explain below why this does the trick. First the calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    0011 1100 0111 0000 0011 1110 (3c703e, original plaintext, "&amp;lt;p&amp;gt;")
XOR 0011 1010 0010 1001 0010 0000 (3a2920, desired output, ":) ")
---------------------------------
    0000 0110 0101 1001 0001 1110

    1011 1110 0001 0101 0100 1110 (be154e, initial segment of IV)
XOR 0000 0110 0101 1001 0001 1110 (last result)
---------------------------------
    1011 1000 0100 1100 0101 0000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is &lt;code&gt;b84c50&lt;/code&gt; in hexadecimal representation. So the new IV is &lt;code&gt;b84c502343408caa1f11ab3445bdd34c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Test it by decrypting the ciphertext with it:&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="nv"&gt;$ &lt;/span&gt;openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; ciphertext.enc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-iv&lt;/span&gt; b84c502343408caa1f11ab3445bdd34c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-K&lt;/span&gt; be154e2343408caa1f11ab3445bdd34cbe154e2343408caa1f11ab3445bdd34c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilà, you should see &lt;code&gt;:) Hello World!&amp;lt;/p&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Why does this IV do what we want? Well, because of how CBC works, we know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AES_decrypt(first_ciphertext_block, key) XOR IV = first_plaintext_block
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;xyz&lt;/code&gt; are the first three bytes of the result of &lt;code&gt;AES_decrypt&lt;/code&gt;, and &lt;code&gt;abc&lt;/code&gt; are the first three bytes of the IV, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xyz XOR abc = "&amp;lt;p&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We changed the first three bytes of the IV by XORing the original plaintext and the desired output. So, the question is: Why does the following hold?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xyz XOR (abc XOR ("&amp;lt;p&amp;gt;" XOR ":) ")) = ":) "
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, here is why:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  xyz XOR (abc XOR ("&amp;lt;p&amp;gt;" XOR ":) "))
= (xyz XOR abc) XOR ("&amp;lt;p&amp;gt;" XOR ":) ")  [because XOR is associative]
= "&amp;lt;p&amp;gt;" XOR ("&amp;lt;p&amp;gt;" XOR ":) ")          [as noted above]
= ("&amp;lt;p&amp;gt;" XOR "&amp;lt;p&amp;gt;") XOR ":) "          [because XOR is associative]
= ":) "                                [because x XOR x = 0 and 0 XOR x = x]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>security</category>
      <category>cryptography</category>
    </item>
  </channel>
</rss>
