github.com/emmansun/gmsm@v0.29.1/cipher/xts.go (about)

     1  package cipher
     2  
     3  import (
     4  	_cipher "crypto/cipher"
     5  	"encoding/binary"
     6  	"errors"
     7  
     8  	"github.com/emmansun/gmsm/internal/alias"
     9  	"github.com/emmansun/gmsm/internal/subtle"
    10  )
    11  
    12  const GF128_FDBK byte = 0x87
    13  
    14  type CipherCreator func([]byte) (_cipher.Block, error)
    15  
    16  type concurrentBlocks interface {
    17  	Concurrency() int
    18  	EncryptBlocks(dst, src []byte)
    19  	DecryptBlocks(dst, src []byte)
    20  }
    21  
    22  // Cipher contains an expanded key structure. It is unsafe for concurrent use.
    23  type xts struct {
    24  	b     _cipher.Block
    25  	tweak [blockSize]byte
    26  	isGB  bool // if true, follows GB/T 17964-2021
    27  }
    28  
    29  // blockSize is the block size that the underlying cipher must have. XTS is
    30  // only defined for 16-byte ciphers.
    31  const blockSize = 16
    32  
    33  type xtsEncrypter xts
    34  
    35  // xtsEncAble is an interface implemented by ciphers that have a specific
    36  // optimized implementation of XTS encryption, like sm4.
    37  // NewXTSEncrypter will check for this interface and return the specific
    38  // BlockMode if found.
    39  type xtsEncAble interface {
    40  	NewXTSEncrypter(encryptedTweak *[blockSize]byte, isGB bool) _cipher.BlockMode
    41  }
    42  
    43  // NewXTSEncrypter creates a Cipher given a function for creating the underlying
    44  // block cipher (which must have a block size of 16 bytes).
    45  func NewXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (_cipher.BlockMode, error) {
    46  	return newXTSEncrypter(cipherFunc, key, tweakKey, tweak, false)
    47  }
    48  
    49  // NewXTSEncrypterWithSector creates a Cipher given a function for creating the underlying
    50  // block cipher (which must have a block size of 16 bytes) with sector number.
    51  func NewXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (_cipher.BlockMode, error) {
    52  	tweak := make([]byte, blockSize)
    53  	binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
    54  	return NewXTSEncrypter(cipherFunc, key, tweakKey, tweak)
    55  }
    56  
    57  // NewGBXTSEncrypter creates a Cipher given a function for creating the underlying
    58  // block cipher (which must have a block size of 16 bytes).
    59  // It follows GB/T 17964-2021.
    60  func NewGBXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (_cipher.BlockMode, error) {
    61  	return newXTSEncrypter(cipherFunc, key, tweakKey, tweak, true)
    62  }
    63  
    64  // NewGBXTSEncrypterWithSector creates a Cipher given a function for creating the underlying
    65  // block cipher (which must have a block size of 16 bytes) with sector number.
    66  // It follows GB/T 17964-2021.
    67  func NewGBXTSEncrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (_cipher.BlockMode, error) {
    68  	tweak := make([]byte, blockSize)
    69  	binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
    70  	return NewGBXTSEncrypter(cipherFunc, key, tweakKey, tweak)
    71  }
    72  
    73  func newXTSEncrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte, isGB bool) (_cipher.BlockMode, error) {
    74  	if len(tweak) != blockSize {
    75  		return nil, errors.New("cipher: invalid tweak length")
    76  	}
    77  
    78  	k1, err := cipherFunc(key)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	if k1.BlockSize() != blockSize {
    83  		return nil, errors.New("cipher: cipher does not have a block size of 16")
    84  	}
    85  
    86  	k2, err := cipherFunc(tweakKey)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	if xtsable, ok := k1.(xtsEncAble); ok {
    92  		var encryptedTweak [blockSize]byte
    93  		k2.Encrypt(encryptedTweak[:], tweak)
    94  		return xtsable.NewXTSEncrypter(&encryptedTweak, isGB), nil
    95  	}
    96  
    97  	c := &xts{
    98  		b:    k1,
    99  		isGB: isGB,
   100  	}
   101  	k2.Encrypt(c.tweak[:], tweak)
   102  	return (*xtsEncrypter)(c), nil
   103  }
   104  
   105  type xtsDecrypter xts
   106  
   107  // xtsDecAble is an interface implemented by ciphers that have a specific
   108  // optimized implementation of XTS encryption, like sm4.
   109  // NewXTSDecrypter will check for this interface and return the specific
   110  // BlockMode if found.
   111  type xtsDecAble interface {
   112  	NewXTSDecrypter(encryptedTweak *[blockSize]byte, isGB bool) _cipher.BlockMode
   113  }
   114  
   115  // NewXTSDecrypter creates a Cipher given a function for creating the underlying
   116  // block cipher (which must have a block size of 16 bytes) for decryption.
   117  func NewXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (_cipher.BlockMode, error) {
   118  	return newXTSDecrypter(cipherFunc, key, tweakKey, tweak, false)
   119  }
   120  
   121  // NewXTSDecrypterWithSector creates a Cipher given a function for creating the underlying
   122  // block cipher (which must have a block size of 16 bytes) with sector number for decryption.
   123  func NewXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (_cipher.BlockMode, error) {
   124  	tweak := make([]byte, blockSize)
   125  	binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
   126  	return NewXTSDecrypter(cipherFunc, key, tweakKey, tweak)
   127  }
   128  
   129  // NewGBXTSDecrypter creates a Cipher given a function for creating the underlying
   130  // block cipher (which must have a block size of 16 bytes) for decryption.
   131  // It follows GB/T 17964-2021.
   132  func NewGBXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte) (_cipher.BlockMode, error) {
   133  	return newXTSDecrypter(cipherFunc, key, tweakKey, tweak, true)
   134  }
   135  
   136  // NewGBXTSDecrypterWithSector creates a Cipher given a function for creating the underlying
   137  // block cipher (which must have a block size of 16 bytes) with sector number for decryption.
   138  // It follows GB/T 17964-2021.
   139  func NewGBXTSDecrypterWithSector(cipherFunc CipherCreator, key, tweakKey []byte, sectorNum uint64) (_cipher.BlockMode, error) {
   140  	tweak := make([]byte, blockSize)
   141  	binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
   142  	return NewGBXTSDecrypter(cipherFunc, key, tweakKey, tweak)
   143  }
   144  
   145  func newXTSDecrypter(cipherFunc CipherCreator, key, tweakKey, tweak []byte, isGB bool) (_cipher.BlockMode, error) {
   146  	if len(tweak) != blockSize {
   147  		return nil, errors.New("cipher: invalid tweak length")
   148  	}
   149  
   150  	k1, err := cipherFunc(key)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	if k1.BlockSize() != blockSize {
   155  		return nil, errors.New("cipher: cipher does not have a block size of 16")
   156  	}
   157  
   158  	k2, err := cipherFunc(tweakKey)
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	if xtsable, ok := k1.(xtsDecAble); ok {
   164  		var encryptedTweak [blockSize]byte
   165  		k2.Encrypt(encryptedTweak[:], tweak)
   166  		return xtsable.NewXTSDecrypter(&encryptedTweak, isGB), nil
   167  	}
   168  
   169  	c := &xts{
   170  		b:    k1,
   171  		isGB: isGB,
   172  	}
   173  	k2.Encrypt(c.tweak[:], tweak)
   174  	return (*xtsDecrypter)(c), nil
   175  }
   176  
   177  func (c *xtsEncrypter) BlockSize() int {
   178  	return blockSize
   179  }
   180  
   181  // CryptBlocks encrypts a sector of plaintext and puts the result into ciphertext.
   182  // Plaintext and ciphertext must overlap entirely or not at all.
   183  // Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
   184  func (c *xtsEncrypter) CryptBlocks(ciphertext, plaintext []byte) {
   185  	if len(ciphertext) < len(plaintext) {
   186  		panic("cipher: ciphertext is smaller than plaintext")
   187  	}
   188  	if len(plaintext) < blockSize {
   189  		panic("cipher: plaintext length is smaller than the block size")
   190  	}
   191  	if alias.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
   192  		panic("cipher: invalid buffer overlap")
   193  	}
   194  
   195  	lastCiphertext := ciphertext
   196  
   197  	if concCipher, ok := c.b.(concurrentBlocks); ok {
   198  		batchSize := concCipher.Concurrency() * blockSize
   199  		var tweaks []byte = make([]byte, batchSize)
   200  		for len(plaintext) >= batchSize {
   201  			doubleTweaks(&c.tweak, tweaks, c.isGB)
   202  			subtle.XORBytes(ciphertext, plaintext, tweaks)
   203  			concCipher.EncryptBlocks(ciphertext, ciphertext)
   204  			subtle.XORBytes(ciphertext, ciphertext, tweaks)
   205  			plaintext = plaintext[batchSize:]
   206  			lastCiphertext = ciphertext[batchSize-blockSize:]
   207  			ciphertext = ciphertext[batchSize:]
   208  		}
   209  	}
   210  
   211  	for len(plaintext) >= blockSize {
   212  		subtle.XORBytes(ciphertext, plaintext, c.tweak[:])
   213  		c.b.Encrypt(ciphertext, ciphertext)
   214  		subtle.XORBytes(ciphertext, ciphertext, c.tweak[:])
   215  		plaintext = plaintext[blockSize:]
   216  		lastCiphertext = ciphertext
   217  		ciphertext = ciphertext[blockSize:]
   218  		mul2(&c.tweak, c.isGB)
   219  	}
   220  	// is there a final partial block to handle?
   221  	if remain := len(plaintext); remain > 0 {
   222  		var x [blockSize]byte
   223  		//Copy the final plaintext bytes
   224  		copy(x[:], plaintext)
   225  		//Steal ciphertext to complete the block
   226  		copy(x[remain:], lastCiphertext[remain:blockSize])
   227  		//Copy the final ciphertext bytes
   228  		copy(ciphertext, lastCiphertext[:remain])
   229  		//Merge the tweak into the input block
   230  		subtle.XORBytes(x[:], x[:], c.tweak[:])
   231  		//Encrypt the final block using K1
   232  		c.b.Encrypt(x[:], x[:])
   233  		//Merge the tweak into the output block
   234  		subtle.XORBytes(lastCiphertext, x[:], c.tweak[:])
   235  	}
   236  }
   237  
   238  func (c *xtsDecrypter) BlockSize() int {
   239  	return blockSize
   240  }
   241  
   242  // CryptBlocks decrypts a sector of ciphertext and puts the result into plaintext.
   243  // Plaintext and ciphertext must overlap entirely or not at all.
   244  // Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
   245  func (c *xtsDecrypter) CryptBlocks(plaintext, ciphertext []byte) {
   246  	if len(plaintext) < len(ciphertext) {
   247  		panic("cipher: plaintext is smaller than ciphertext")
   248  	}
   249  	if len(ciphertext) < blockSize {
   250  		panic("cipher: ciphertext length is smaller than the block size")
   251  	}
   252  	if alias.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
   253  		panic("cipher: invalid buffer overlap")
   254  	}
   255  
   256  	if concCipher, ok := c.b.(concurrentBlocks); ok {
   257  		batchSize := concCipher.Concurrency() * blockSize
   258  		var tweaks []byte = make([]byte, batchSize)
   259  
   260  		for len(ciphertext) >= batchSize {
   261  			doubleTweaks(&c.tweak, tweaks, c.isGB)
   262  			subtle.XORBytes(plaintext, ciphertext, tweaks)
   263  			concCipher.DecryptBlocks(plaintext, plaintext)
   264  			subtle.XORBytes(plaintext, plaintext, tweaks)
   265  			plaintext = plaintext[batchSize:]
   266  			ciphertext = ciphertext[batchSize:]
   267  		}
   268  	}
   269  
   270  	for len(ciphertext) >= 2*blockSize {
   271  		subtle.XORBytes(plaintext, ciphertext, c.tweak[:])
   272  		c.b.Decrypt(plaintext, plaintext)
   273  		subtle.XORBytes(plaintext, plaintext, c.tweak[:])
   274  		plaintext = plaintext[blockSize:]
   275  		ciphertext = ciphertext[blockSize:]
   276  
   277  		mul2(&c.tweak, c.isGB)
   278  	}
   279  
   280  	if remain := len(ciphertext); remain >= blockSize {
   281  		var x [blockSize]byte
   282  		if remain > blockSize {
   283  			var tt [blockSize]byte
   284  			copy(tt[:], c.tweak[:])
   285  			mul2(&tt, c.isGB)
   286  			subtle.XORBytes(x[:], ciphertext, tt[:])
   287  			c.b.Decrypt(x[:], x[:])
   288  			subtle.XORBytes(plaintext, x[:], tt[:])
   289  
   290  			//Retrieve the length of the final block
   291  			remain -= blockSize
   292  
   293  			//Copy the final ciphertext bytes
   294  			copy(x[:], ciphertext[blockSize:])
   295  			//Steal ciphertext to complete the block
   296  			copy(x[remain:], plaintext[remain:blockSize])
   297  			//Copy the final plaintext bytes
   298  			copy(plaintext[blockSize:], plaintext)
   299  
   300  			subtle.XORBytes(x[:], x[:], c.tweak[:])
   301  			c.b.Decrypt(x[:], x[:])
   302  			subtle.XORBytes(plaintext, x[:], c.tweak[:])
   303  		} else {
   304  			//The last block contains exactly 128 bits
   305  			subtle.XORBytes(plaintext, ciphertext, c.tweak[:])
   306  			c.b.Decrypt(plaintext, plaintext)
   307  			subtle.XORBytes(plaintext, plaintext, c.tweak[:])
   308  			// Maybe there are still ciphertext
   309  			mul2(&c.tweak, c.isGB)
   310  		}
   311  
   312  	}
   313  }
   314  
   315  // mul2Generic multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
   316  // x¹²⁸ + x⁷ + x² + x + 1.
   317  func mul2Generic(tweak *[blockSize]byte, isGB bool) {
   318  	var carryIn byte
   319  	if !isGB {
   320  		// the coefficient of x⁰ can be obtained by tweak[0] & 1
   321  		// the coefficient of x⁷ can be obtained by tweak[0] >> 7
   322  		// the coefficient of x¹²⁰ can be obtained by tweak[15] & 1
   323  		// the coefficient of x¹²⁷ can be obtained by tweak[15] >> 7
   324  		for j := range tweak {
   325  			carryOut := tweak[j] >> 7
   326  			tweak[j] = (tweak[j] << 1) + carryIn
   327  			carryIn = carryOut
   328  		}
   329  		if carryIn != 0 {
   330  			// If we have a carry bit then we need to subtract a multiple
   331  			// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
   332  			// By dropping the carry bit, we're subtracting the x^128 term
   333  			// so all that remains is to subtract x⁷ + x² + x + 1.
   334  			// Subtraction (and addition) in this representation is just
   335  			// XOR.
   336  			tweak[0] ^= GF128_FDBK // 1<<7 | 1<<2 | 1<<1 | 1
   337  		}
   338  	} else {
   339  		// GB/T 17964-2021, 
   340  		// the coefficient of x⁰ can be obtained by tweak[0] >> 7
   341  		// the coefficient of x⁷ can be obtained by tweak[0] & 1
   342  		// the coefficient of x¹²⁰ can be obtained by tweak[15] >> 7
   343  		// the coefficient of x¹²⁷ can be obtained by tweak[15] & 1
   344  		for j := range tweak {
   345  			carryOut := (tweak[j] << 7) & 0x80
   346  			tweak[j] = (tweak[j] >> 1) + carryIn
   347  			carryIn = carryOut
   348  		}
   349  		if carryIn != 0 {
   350  			tweak[0] ^= 0xE1 //  1<<7 | 1<<6 | 1<<5 | 1
   351  		}
   352  	}
   353  }