...

Source file src/golang.org/x/crypto/xts/xts.go

Documentation: golang.org/x/crypto/xts

     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. This package
    19  // does not implement ciphertext-stealing so sectors must be a multiple of 16
    20  // bytes.
    21  //
    22  // Note that XTS is usually not appropriate for any use besides disk encryption.
    23  // Most users should use an AEAD mode like GCM (from crypto/cipher.NewGCM) instead.
    24  package xts // import "golang.org/x/crypto/xts"
    25  
    26  import (
    27  	"crypto/cipher"
    28  	"encoding/binary"
    29  	"errors"
    30  	"sync"
    31  
    32  	"golang.org/x/crypto/internal/alias"
    33  )
    34  
    35  // Cipher contains an expanded key structure. It is safe for concurrent use if
    36  // the underlying block cipher is safe for concurrent use.
    37  type Cipher struct {
    38  	k1, k2 cipher.Block
    39  }
    40  
    41  // blockSize is the block size that the underlying cipher must have. XTS is
    42  // only defined for 16-byte ciphers.
    43  const blockSize = 16
    44  
    45  var tweakPool = sync.Pool{
    46  	New: func() interface{} {
    47  		return new([blockSize]byte)
    48  	},
    49  }
    50  
    51  // NewCipher creates a Cipher given a function for creating the underlying
    52  // block cipher (which must have a block size of 16 bytes). The key must be
    53  // twice the length of the underlying cipher's key.
    54  func NewCipher(cipherFunc func([]byte) (cipher.Block, error), key []byte) (c *Cipher, err error) {
    55  	c = new(Cipher)
    56  	if c.k1, err = cipherFunc(key[:len(key)/2]); err != nil {
    57  		return
    58  	}
    59  	c.k2, err = cipherFunc(key[len(key)/2:])
    60  
    61  	if c.k1.BlockSize() != blockSize {
    62  		err = errors.New("xts: cipher does not have a block size of 16")
    63  	}
    64  
    65  	return
    66  }
    67  
    68  // Encrypt encrypts a sector of plaintext and puts the result into ciphertext.
    69  // Plaintext and ciphertext must overlap entirely or not at all.
    70  // Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
    71  func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
    72  	if len(ciphertext) < len(plaintext) {
    73  		panic("xts: ciphertext is smaller than plaintext")
    74  	}
    75  	if len(plaintext)%blockSize != 0 {
    76  		panic("xts: plaintext is not a multiple of the block size")
    77  	}
    78  	if alias.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
    79  		panic("xts: invalid buffer overlap")
    80  	}
    81  
    82  	tweak := tweakPool.Get().(*[blockSize]byte)
    83  	for i := range tweak {
    84  		tweak[i] = 0
    85  	}
    86  	binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
    87  
    88  	c.k2.Encrypt(tweak[:], tweak[:])
    89  
    90  	for len(plaintext) > 0 {
    91  		for j := range tweak {
    92  			ciphertext[j] = plaintext[j] ^ tweak[j]
    93  		}
    94  		c.k1.Encrypt(ciphertext, ciphertext)
    95  		for j := range tweak {
    96  			ciphertext[j] ^= tweak[j]
    97  		}
    98  		plaintext = plaintext[blockSize:]
    99  		ciphertext = ciphertext[blockSize:]
   100  
   101  		mul2(tweak)
   102  	}
   103  
   104  	tweakPool.Put(tweak)
   105  }
   106  
   107  // Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
   108  // Plaintext and ciphertext must overlap entirely or not at all.
   109  // Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
   110  func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
   111  	if len(plaintext) < len(ciphertext) {
   112  		panic("xts: plaintext is smaller than ciphertext")
   113  	}
   114  	if len(ciphertext)%blockSize != 0 {
   115  		panic("xts: ciphertext is not a multiple of the block size")
   116  	}
   117  	if alias.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
   118  		panic("xts: invalid buffer overlap")
   119  	}
   120  
   121  	tweak := tweakPool.Get().(*[blockSize]byte)
   122  	for i := range tweak {
   123  		tweak[i] = 0
   124  	}
   125  	binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
   126  
   127  	c.k2.Encrypt(tweak[:], tweak[:])
   128  
   129  	for len(ciphertext) > 0 {
   130  		for j := range tweak {
   131  			plaintext[j] = ciphertext[j] ^ tweak[j]
   132  		}
   133  		c.k1.Decrypt(plaintext, plaintext)
   134  		for j := range tweak {
   135  			plaintext[j] ^= tweak[j]
   136  		}
   137  		plaintext = plaintext[blockSize:]
   138  		ciphertext = ciphertext[blockSize:]
   139  
   140  		mul2(tweak)
   141  	}
   142  
   143  	tweakPool.Put(tweak)
   144  }
   145  
   146  // mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
   147  // x¹²⁸ + x⁷ + x² + x + 1.
   148  func mul2(tweak *[blockSize]byte) {
   149  	var carryIn byte
   150  	for j := range tweak {
   151  		carryOut := tweak[j] >> 7
   152  		tweak[j] = (tweak[j] << 1) + carryIn
   153  		carryIn = carryOut
   154  	}
   155  	if carryIn != 0 {
   156  		// If we have a carry bit then we need to subtract a multiple
   157  		// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
   158  		// By dropping the carry bit, we're subtracting the x^128 term
   159  		// so all that remains is to subtract x⁷ + x² + x + 1.
   160  		// Subtraction (and addition) in this representation is just
   161  		// XOR.
   162  		tweak[0] ^= 1<<7 | 1<<2 | 1<<1 | 1
   163  	}
   164  }
   165  

View as plain text