github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/crypto/xts/xts.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package xts implements the XTS cipher mode as specified in IEEE P1619/D16.
     6  //
     7  // XTS mode is typically used for disk encryption, which presents a number of
     8  // novel problems that make more common modes inapplicable. The disk is
     9  // conceptually an array of sectors and we must be able to encrypt and decrypt
    10  // a sector in isolation. However, an attacker must not be able to transpose
    11  // two sectors of plaintext by transposing their ciphertext.
    12  //
    13  // XTS wraps a block cipher with Rogaway's XEX mode in order to build a
    14  // tweakable block cipher. This allows each sector to have a unique tweak and
    15  // effectively create a unique key for each sector.
    16  //
    17  // XTS does not provide any authentication. An attacker can manipulate the
    18  // ciphertext and randomise a block (16 bytes) of the plaintext.
    19  //
    20  // (Note: this package does not implement ciphertext-stealing so sectors must
    21  // be a multiple of 16 bytes.)
    22  package xts // import "golang.org/x/crypto/xts"
    23  
    24  import (
    25  	"crypto/cipher"
    26  	"errors"
    27  )
    28  
    29  // Cipher contains an expanded key structure. It doesn't contain mutable state
    30  // and therefore can be used concurrently.
    31  type Cipher struct {
    32  	k1, k2 cipher.Block
    33  }
    34  
    35  // blockSize is the block size that the underlying cipher must have. XTS is
    36  // only defined for 16-byte ciphers.
    37  const blockSize = 16
    38  
    39  // NewCipher creates a Cipher given a function for creating the underlying
    40  // block cipher (which must have a block size of 16 bytes). The key must be
    41  // twice the length of the underlying cipher's key.
    42  func NewCipher(cipherFunc func([]byte) (cipher.Block, error), key []byte) (c *Cipher, err error) {
    43  	c = new(Cipher)
    44  	if c.k1, err = cipherFunc(key[:len(key)/2]); err != nil {
    45  		return
    46  	}
    47  	c.k2, err = cipherFunc(key[len(key)/2:])
    48  
    49  	if c.k1.BlockSize() != blockSize {
    50  		err = errors.New("xts: cipher does not have a block size of 16")
    51  	}
    52  
    53  	return
    54  }
    55  
    56  // Encrypt encrypts a sector of plaintext and puts the result into ciphertext.
    57  // Plaintext and ciphertext may be the same slice but should not overlap.
    58  // Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
    59  func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
    60  	if len(ciphertext) < len(plaintext) {
    61  		panic("xts: ciphertext is smaller than plaintext")
    62  	}
    63  	if len(plaintext)%blockSize != 0 {
    64  		panic("xts: plaintext is not a multiple of the block size")
    65  	}
    66  
    67  	var tweak [blockSize]byte
    68  	for i := 0; i < 8; i++ {
    69  		tweak[i] = byte(sectorNum)
    70  		sectorNum >>= 8
    71  	}
    72  
    73  	c.k2.Encrypt(tweak[:], tweak[:])
    74  
    75  	for i := 0; i < len(plaintext); i += blockSize {
    76  		for j := 0; j < blockSize; j++ {
    77  			ciphertext[i+j] = plaintext[i+j] ^ tweak[j]
    78  		}
    79  		c.k1.Encrypt(ciphertext[i:], ciphertext[i:])
    80  		for j := 0; j < blockSize; j++ {
    81  			ciphertext[i+j] ^= tweak[j]
    82  		}
    83  
    84  		mul2(&tweak)
    85  	}
    86  }
    87  
    88  // Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
    89  // Plaintext and ciphertext may be the same slice but should not overlap.
    90  // Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
    91  func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
    92  	if len(plaintext) < len(ciphertext) {
    93  		panic("xts: plaintext is smaller than ciphertext")
    94  	}
    95  	if len(ciphertext)%blockSize != 0 {
    96  		panic("xts: ciphertext is not a multiple of the block size")
    97  	}
    98  
    99  	var tweak [blockSize]byte
   100  	for i := 0; i < 8; i++ {
   101  		tweak[i] = byte(sectorNum)
   102  		sectorNum >>= 8
   103  	}
   104  
   105  	c.k2.Encrypt(tweak[:], tweak[:])
   106  
   107  	for i := 0; i < len(plaintext); i += blockSize {
   108  		for j := 0; j < blockSize; j++ {
   109  			plaintext[i+j] = ciphertext[i+j] ^ tweak[j]
   110  		}
   111  		c.k1.Decrypt(plaintext[i:], plaintext[i:])
   112  		for j := 0; j < blockSize; j++ {
   113  			plaintext[i+j] ^= tweak[j]
   114  		}
   115  
   116  		mul2(&tweak)
   117  	}
   118  }
   119  
   120  // mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
   121  // x¹²⁸ + x⁷ + x² + x + 1.
   122  func mul2(tweak *[blockSize]byte) {
   123  	var carryIn byte
   124  	for j := range tweak {
   125  		carryOut := tweak[j] >> 7
   126  		tweak[j] = (tweak[j] << 1) + carryIn
   127  		carryIn = carryOut
   128  	}
   129  	if carryIn != 0 {
   130  		// If we have a carry bit then we need to subtract a multiple
   131  		// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
   132  		// By dropping the carry bit, we're subtracting the x^128 term
   133  		// so all that remains is to subtract x⁷ + x² + x + 1.
   134  		// Subtraction (and addition) in this representation is just
   135  		// XOR.
   136  		tweak[0] ^= 1<<7 | 1<<2 | 1<<1 | 1
   137  	}
   138  }