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 }