mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 20:26:19 +08:00
MAGIC - xts mode
This commit is contained in:
parent
ddea2f74c8
commit
b1184c24cf
246
cipher/xts.go
Normal file
246
cipher/xts.go
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
package cipher
|
||||||
|
|
||||||
|
import (
|
||||||
|
_cipher "crypto/cipher"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GF128_FDBK byte = 0x87
|
||||||
|
|
||||||
|
type CipherCreator func([]byte) (_cipher.Block, error)
|
||||||
|
|
||||||
|
type concurrentBlocks interface {
|
||||||
|
Concurrency() int
|
||||||
|
EncryptBlocks(dst, src []byte)
|
||||||
|
DecryptBlocks(dst, src []byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A XTSBlockMode represents a block cipher running in a XTS mode
|
||||||
|
type XTSBlockMode interface {
|
||||||
|
// BlockSize returns the mode's block size.
|
||||||
|
BlockSize() int
|
||||||
|
|
||||||
|
// Encrypt encrypts or decrypts a number of blocks. The length of
|
||||||
|
// src must be a multiple of the block size. Dst and src must overlap
|
||||||
|
// entirely or not at all.
|
||||||
|
//
|
||||||
|
Encrypt(dst, src []byte, sectorNum uint64)
|
||||||
|
|
||||||
|
// Decrypt decrypts a number of blocks. The length of
|
||||||
|
// src must be a multiple of the block size. Dst and src must overlap
|
||||||
|
// entirely or not at all.
|
||||||
|
//
|
||||||
|
Decrypt(dst, src []byte, sectorNum uint64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cipher contains an expanded key structure. It is safe for concurrent use if
|
||||||
|
// the underlying block cipher is safe for concurrent use.
|
||||||
|
type xts struct {
|
||||||
|
k1, k2 _cipher.Block
|
||||||
|
}
|
||||||
|
|
||||||
|
// blockSize is the block size that the underlying cipher must have. XTS is
|
||||||
|
// only defined for 16-byte ciphers.
|
||||||
|
const blockSize = 16
|
||||||
|
|
||||||
|
var tweakPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return new([blockSize]byte)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewXTS creates a Cipher given a function for creating the underlying
|
||||||
|
// block cipher (which must have a block size of 16 bytes). The key must be
|
||||||
|
// twice the length of the underlying cipher's key.
|
||||||
|
func NewXTS(cipherFunc CipherCreator, key []byte) (XTSBlockMode, error) {
|
||||||
|
k1, err := cipherFunc(key[:len(key)/2])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
k2, err := cipherFunc(key[len(key)/2:])
|
||||||
|
c := &xts{
|
||||||
|
k1,
|
||||||
|
k2,
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.k1.BlockSize() != blockSize {
|
||||||
|
err = errors.New("xts: cipher does not have a block size of 16")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *xts) BlockSize() int {
|
||||||
|
return blockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt encrypts a sector of plaintext and puts the result into ciphertext.
|
||||||
|
// Plaintext and ciphertext must overlap entirely or not at all.
|
||||||
|
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
|
||||||
|
func (c *xts) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
|
||||||
|
if len(ciphertext) < len(plaintext) {
|
||||||
|
panic("xts: ciphertext is smaller than plaintext")
|
||||||
|
}
|
||||||
|
if len(plaintext) < blockSize {
|
||||||
|
panic("xts: plaintext length is smaller than the block size")
|
||||||
|
}
|
||||||
|
if InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
|
||||||
|
panic("xts: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
|
||||||
|
tweak := tweakPool.Get().(*[blockSize]byte)
|
||||||
|
|
||||||
|
for i := range tweak {
|
||||||
|
tweak[i] = 0
|
||||||
|
}
|
||||||
|
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
|
||||||
|
c.k2.Encrypt(tweak[:], tweak[:])
|
||||||
|
|
||||||
|
lastCiphertext := ciphertext
|
||||||
|
|
||||||
|
if concCipher, ok := c.k1.(concurrentBlocks); ok {
|
||||||
|
batchSize := concCipher.Concurrency() * blockSize
|
||||||
|
var tweaks []byte = make([]byte, batchSize)
|
||||||
|
|
||||||
|
for len(plaintext) >= batchSize {
|
||||||
|
for i := 0; i < concCipher.Concurrency(); i++ {
|
||||||
|
copy(tweaks[blockSize*i:], tweak[:])
|
||||||
|
mul2(tweak)
|
||||||
|
}
|
||||||
|
XorBytes(ciphertext, plaintext, tweaks)
|
||||||
|
concCipher.EncryptBlocks(ciphertext, ciphertext)
|
||||||
|
XorBytes(ciphertext, ciphertext, tweaks)
|
||||||
|
plaintext = plaintext[batchSize:]
|
||||||
|
lastCiphertext = ciphertext[batchSize-blockSize:]
|
||||||
|
ciphertext = ciphertext[batchSize:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for len(plaintext) >= blockSize {
|
||||||
|
XorBytes(ciphertext, plaintext, tweak[:])
|
||||||
|
c.k1.Encrypt(ciphertext, ciphertext)
|
||||||
|
XorBytes(ciphertext, ciphertext, tweak[:])
|
||||||
|
plaintext = plaintext[blockSize:]
|
||||||
|
lastCiphertext = ciphertext
|
||||||
|
ciphertext = ciphertext[blockSize:]
|
||||||
|
mul2(tweak)
|
||||||
|
}
|
||||||
|
// is there a final partial block to handle?
|
||||||
|
if remain := len(plaintext); remain > 0 {
|
||||||
|
var x [blockSize]byte
|
||||||
|
//Copy the final ciphertext bytes
|
||||||
|
copy(ciphertext, lastCiphertext[:remain])
|
||||||
|
//Copy the final plaintext bytes
|
||||||
|
copy(x[:], plaintext)
|
||||||
|
//Steal ciphertext to complete the block
|
||||||
|
copy(x[remain:], lastCiphertext[remain:blockSize])
|
||||||
|
//Merge the tweak into the input block
|
||||||
|
XorBytes(x[:], x[:], tweak[:])
|
||||||
|
//Encrypt the final block using K1
|
||||||
|
c.k1.Encrypt(x[:], x[:])
|
||||||
|
//Merge the tweak into the output block
|
||||||
|
XorBytes(lastCiphertext, x[:], tweak[:])
|
||||||
|
}
|
||||||
|
tweakPool.Put(tweak)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
|
||||||
|
// Plaintext and ciphertext must overlap entirely or not at all.
|
||||||
|
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
|
||||||
|
func (c *xts) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
|
||||||
|
if len(plaintext) < len(ciphertext) {
|
||||||
|
panic("xts: plaintext is smaller than ciphertext")
|
||||||
|
}
|
||||||
|
if len(ciphertext) < blockSize {
|
||||||
|
panic("xts: ciphertext length is smaller than the block size")
|
||||||
|
}
|
||||||
|
if InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
|
||||||
|
panic("xts: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
|
||||||
|
tweak := tweakPool.Get().(*[blockSize]byte)
|
||||||
|
for i := range tweak {
|
||||||
|
tweak[i] = 0
|
||||||
|
}
|
||||||
|
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
|
||||||
|
|
||||||
|
c.k2.Encrypt(tweak[:], tweak[:])
|
||||||
|
|
||||||
|
if concCipher, ok := c.k1.(concurrentBlocks); ok {
|
||||||
|
batchSize := concCipher.Concurrency() * blockSize
|
||||||
|
var tweaks []byte = make([]byte, batchSize)
|
||||||
|
|
||||||
|
for len(ciphertext) >= batchSize {
|
||||||
|
for i := 0; i < concCipher.Concurrency(); i++ {
|
||||||
|
copy(tweaks[blockSize*i:], tweak[:])
|
||||||
|
mul2(tweak)
|
||||||
|
}
|
||||||
|
XorBytes(plaintext, ciphertext, tweaks)
|
||||||
|
concCipher.DecryptBlocks(plaintext, plaintext)
|
||||||
|
XorBytes(plaintext, plaintext, tweaks)
|
||||||
|
plaintext = plaintext[batchSize:]
|
||||||
|
ciphertext = ciphertext[batchSize:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(ciphertext) >= 2*blockSize {
|
||||||
|
XorBytes(plaintext, ciphertext, tweak[:])
|
||||||
|
c.k1.Decrypt(plaintext, plaintext)
|
||||||
|
XorBytes(plaintext, plaintext, tweak[:])
|
||||||
|
plaintext = plaintext[blockSize:]
|
||||||
|
ciphertext = ciphertext[blockSize:]
|
||||||
|
|
||||||
|
mul2(tweak)
|
||||||
|
}
|
||||||
|
|
||||||
|
if remain := len(ciphertext); remain >= blockSize {
|
||||||
|
var x [blockSize]byte
|
||||||
|
if remain > blockSize {
|
||||||
|
var tt [blockSize]byte
|
||||||
|
copy(tt[:], tweak[:])
|
||||||
|
mul2(&tt)
|
||||||
|
XorBytes(x[:], ciphertext, tt[:])
|
||||||
|
c.k1.Decrypt(x[:], x[:])
|
||||||
|
XorBytes(plaintext, x[:], tt[:])
|
||||||
|
|
||||||
|
//Retrieve the length of the final block
|
||||||
|
remain -= blockSize
|
||||||
|
|
||||||
|
//Copy the final plaintext bytes
|
||||||
|
copy(plaintext[blockSize:], plaintext)
|
||||||
|
//Copy the final ciphertext bytes
|
||||||
|
copy(x[:], ciphertext[blockSize:])
|
||||||
|
//Steal ciphertext to complete the block
|
||||||
|
copy(x[remain:], plaintext[remain:blockSize])
|
||||||
|
} else {
|
||||||
|
//The last block contains exactly 128 bits
|
||||||
|
copy(x[:], ciphertext)
|
||||||
|
}
|
||||||
|
XorBytes(x[:], x[:], tweak[:])
|
||||||
|
c.k1.Decrypt(x[:], x[:])
|
||||||
|
XorBytes(plaintext, x[:], tweak[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
tweakPool.Put(tweak)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
|
||||||
|
// x¹²⁸ + x⁷ + x² + x + 1.
|
||||||
|
func mul2(tweak *[blockSize]byte) {
|
||||||
|
var carryIn byte
|
||||||
|
for j := range tweak {
|
||||||
|
carryOut := tweak[j] >> 7
|
||||||
|
tweak[j] = (tweak[j] << 1) + carryIn
|
||||||
|
carryIn = carryOut
|
||||||
|
}
|
||||||
|
if carryIn != 0 {
|
||||||
|
// If we have a carry bit then we need to subtract a multiple
|
||||||
|
// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
|
||||||
|
// By dropping the carry bit, we're subtracting the x^128 term
|
||||||
|
// so all that remains is to subtract x⁷ + x² + x + 1.
|
||||||
|
// Subtraction (and addition) in this representation is just
|
||||||
|
// XOR.
|
||||||
|
tweak[0] ^= GF128_FDBK // 1<<7 | 1<<2 | 1<<1 | 1
|
||||||
|
}
|
||||||
|
}
|
115
cipher/xts_test.go
Normal file
115
cipher/xts_test.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package cipher
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These test vectors have been taken from IEEE P1619/D16, Annex B.
|
||||||
|
var xtsTestVectors = []struct {
|
||||||
|
key string
|
||||||
|
sector uint64
|
||||||
|
plaintext string
|
||||||
|
ciphertext string
|
||||||
|
}{
|
||||||
|
{ // XTS-AES-128 applied for a data unit of 32 bytes
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
0,
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"917cf69ebd68b2ec9b9fe9a3eadda692cd43d2f59598ed858c02c2652fbf922e",
|
||||||
|
}, {
|
||||||
|
"1111111111111111111111111111111122222222222222222222222222222222",
|
||||||
|
0x3333333333,
|
||||||
|
"4444444444444444444444444444444444444444444444444444444444444444",
|
||||||
|
"c454185e6a16936e39334038acef838bfb186fff7480adc4289382ecd6d394f0",
|
||||||
|
}, {
|
||||||
|
"fffefdfcfbfaf9f8f7f6f5f4f3f2f1f022222222222222222222222222222222",
|
||||||
|
0x3333333333,
|
||||||
|
"4444444444444444444444444444444444444444444444444444444444444444",
|
||||||
|
"af85336b597afc1a900b2eb21ec949d292df4c047e0b21532186a5971a227a89",
|
||||||
|
}, { // XTS-AES-128 applied for a data unit of 512 bytes
|
||||||
|
"2718281828459045235360287471352631415926535897932384626433832795",
|
||||||
|
0,
|
||||||
|
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
|
||||||
|
"27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568",
|
||||||
|
}, { // Vector 5
|
||||||
|
"2718281828459045235360287471352631415926535897932384626433832795",
|
||||||
|
1,
|
||||||
|
"27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568",
|
||||||
|
"264d3ca8512194fec312c8c9891f279fefdd608d0c027b60483a3fa811d65ee59d52d9e40ec5672d81532b38b6b089ce951f0f9c35590b8b978d175213f329bb1c2fd30f2f7f30492a61a532a79f51d36f5e31a7c9a12c286082ff7d2394d18f783e1a8e72c722caaaa52d8f065657d2631fd25bfd8e5baad6e527d763517501c68c5edc3cdd55435c532d7125c8614deed9adaa3acade5888b87bef641c4c994c8091b5bcd387f3963fb5bc37aa922fbfe3df4e5b915e6eb514717bdd2a74079a5073f5c4bfd46adf7d282e7a393a52579d11a028da4d9cd9c77124f9648ee383b1ac763930e7162a8d37f350b2f74b8472cf09902063c6b32e8c2d9290cefbd7346d1c779a0df50edcde4531da07b099c638e83a755944df2aef1aa31752fd323dcb710fb4bfbb9d22b925bc3577e1b8949e729a90bbafeacf7f7879e7b1147e28ba0bae940db795a61b15ecf4df8db07b824bb062802cc98a9545bb2aaeed77cb3fc6db15dcd7d80d7d5bc406c4970a3478ada8899b329198eb61c193fb6275aa8ca340344a75a862aebe92eee1ce032fd950b47d7704a3876923b4ad62844bf4a09c4dbe8b4397184b7471360c9564880aedddb9baa4af2e75394b08cd32ff479c57a07d3eab5d54de5f9738b8d27f27a9f0ab11799d7b7ffefb2704c95c6ad12c39f1e867a4b7b1d7818a4b753dfd2a89ccb45e001a03a867b187f225dd",
|
||||||
|
}, { // Vector 10, XTS-AES-256 applied for a data unit of 512 bytes
|
||||||
|
"27182818284590452353602874713526624977572470936999595749669676273141592653589793238462643383279502884197169399375105820974944592",
|
||||||
|
0xff,
|
||||||
|
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
|
||||||
|
"1c3b3a102f770386e4836c99e370cf9bea00803f5e482357a4ae12d414a3e63b5d31e276f8fe4a8d66b317f9ac683f44680a86ac35adfc3345befecb4bb188fd5776926c49a3095eb108fd1098baec70aaa66999a72a82f27d848b21d4a741b0c5cd4d5fff9dac89aeba122961d03a757123e9870f8acf1000020887891429ca2a3e7a7d7df7b10355165c8b9a6d0a7de8b062c4500dc4cd120c0f7418dae3d0b5781c34803fa75421c790dfe1de1834f280d7667b327f6c8cd7557e12ac3a0f93ec05c52e0493ef31a12d3d9260f79a289d6a379bc70c50841473d1a8cc81ec583e9645e07b8d9670655ba5bbcfecc6dc3966380ad8fecb17b6ba02469a020a84e18e8f84252070c13e9f1f289be54fbc481457778f616015e1327a02b140f1505eb309326d68378f8374595c849d84f4c333ec4423885143cb47bd71c5edae9be69a2ffeceb1bec9de244fbe15992b11b77c040f12bd8f6a975a44a0f90c29a9abc3d4d893927284c58754cce294529f8614dcd2aba991925fedc4ae74ffac6e333b93eb4aff0479da9a410e4450e0dd7ae4c6e2910900575da401fc07059f645e8b7e9bfdef33943054ff84011493c27b3429eaedb4ed5376441a77ed43851ad77f16f541dfd269d50d6a5f14fb0aab1cbb4c1550be97f7ab4066193c4caa773dad38014bd2092fa755c824bb5e54c4f36ffda9fcea70b9c6e693e148c151",
|
||||||
|
}, { // XTS-AES-128 applied for a data unit that is not a multiple of 16 bytes, but should be a complte byte
|
||||||
|
"c46acc2e7e013cb71cdbf750cf76b000249fbf4fb6cd17607773c23ffa2c4330",
|
||||||
|
94,
|
||||||
|
"7e9c2289cba460e470222953439cdaa892a5433d4dab2a3f67",
|
||||||
|
"9af624641d42b036377ef37b4a158f49e49f6ee308ad449ecf",
|
||||||
|
}, {
|
||||||
|
"56ffcc9bbbdf413f0fc0f888f44b7493bb1925a39b8adf02d9009bb16db0a887",
|
||||||
|
144,
|
||||||
|
"9a839cc14363bafcfc0cc93b14f8e769d35b94cc98267438e3",
|
||||||
|
"fbd8dcfc4d662259f48b151728c3b37233a35127a77051ee9d",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"7454a43b87b1cf0dec95032c22873be3cace3bb795568854c1a008c07c5813f3",
|
||||||
|
108,
|
||||||
|
"41088fa15195b2733fe824d2c1fdc8306080863945fb2a73cf",
|
||||||
|
"f916d877f817ae390f42dc54723bda0ad3ba5f331a72d05ccb",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromHex(s string) []byte {
|
||||||
|
ret, err := hex.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
panic("xts: invalid hex in test")
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXTS(t *testing.T) {
|
||||||
|
for i, test := range xtsTestVectors {
|
||||||
|
c, err := NewXTS(aes.NewCipher, fromHex(test.key))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("#%d: failed to create cipher: %s", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
plaintext := fromHex(test.plaintext)
|
||||||
|
ciphertext := make([]byte, len(plaintext))
|
||||||
|
|
||||||
|
c.Encrypt(ciphertext, plaintext, test.sector)
|
||||||
|
expectedCiphertext := fromHex(test.ciphertext)
|
||||||
|
if !bytes.Equal(ciphertext, expectedCiphertext) {
|
||||||
|
t.Errorf("#%d: encrypted failed, got: %x, want: %x", i, ciphertext, expectedCiphertext)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted := make([]byte, len(ciphertext))
|
||||||
|
c.Decrypt(decrypted, ciphertext, test.sector)
|
||||||
|
if !bytes.Equal(decrypted, plaintext) {
|
||||||
|
t.Errorf("#%d: decryption failed, got: %x, want: %x", i, decrypted, plaintext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShorterCiphertext(t *testing.T) {
|
||||||
|
c, err := NewXTS(aes.NewCipher, make([]byte, 32))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewCipher failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext := make([]byte, 32)
|
||||||
|
encrypted := make([]byte, 48)
|
||||||
|
decrypted := make([]byte, 48)
|
||||||
|
|
||||||
|
c.Encrypt(encrypted, plaintext, 0)
|
||||||
|
c.Decrypt(decrypted, encrypted[:len(plaintext)], 0)
|
||||||
|
|
||||||
|
if !bytes.Equal(plaintext, decrypted[:len(plaintext)]) {
|
||||||
|
t.Errorf("En/Decryption is not inverse")
|
||||||
|
}
|
||||||
|
}
|
@ -39,8 +39,12 @@ func newCipher(key []byte) (cipher.Block, error) {
|
|||||||
|
|
||||||
const FourBlocksSize = 64
|
const FourBlocksSize = 64
|
||||||
|
|
||||||
|
const BatchBlocks = 4
|
||||||
|
|
||||||
func (c *sm4CipherAsm) BlockSize() int { return BlockSize }
|
func (c *sm4CipherAsm) BlockSize() int { return BlockSize }
|
||||||
|
|
||||||
|
func (c *sm4CipherAsm) Concurrency() int { return BatchBlocks }
|
||||||
|
|
||||||
func (c *sm4CipherAsm) Encrypt(dst, src []byte) {
|
func (c *sm4CipherAsm) Encrypt(dst, src []byte) {
|
||||||
if len(src) < BlockSize {
|
if len(src) < BlockSize {
|
||||||
panic("sm4: input not full block")
|
panic("sm4: input not full block")
|
||||||
@ -54,6 +58,19 @@ func (c *sm4CipherAsm) Encrypt(dst, src []byte) {
|
|||||||
encryptBlockAsm(&c.enc[0], &dst[0], &src[0])
|
encryptBlockAsm(&c.enc[0], &dst[0], &src[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *sm4CipherAsm) EncryptBlocks(dst, src []byte) {
|
||||||
|
if len(src) < FourBlocksSize {
|
||||||
|
panic("sm4: input not full blocks")
|
||||||
|
}
|
||||||
|
if len(dst) < FourBlocksSize {
|
||||||
|
panic("sm4: output not full blocks")
|
||||||
|
}
|
||||||
|
if smcipher.InexactOverlap(dst[:FourBlocksSize], src[:FourBlocksSize]) {
|
||||||
|
panic("sm4: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
encryptBlocksAsm(&c.enc[0], &dst[0], &src[0])
|
||||||
|
}
|
||||||
|
|
||||||
func (c *sm4CipherAsm) Decrypt(dst, src []byte) {
|
func (c *sm4CipherAsm) Decrypt(dst, src []byte) {
|
||||||
if len(src) < BlockSize {
|
if len(src) < BlockSize {
|
||||||
panic("sm4: input not full block")
|
panic("sm4: input not full block")
|
||||||
@ -67,6 +84,19 @@ func (c *sm4CipherAsm) Decrypt(dst, src []byte) {
|
|||||||
encryptBlockAsm(&c.dec[0], &dst[0], &src[0])
|
encryptBlockAsm(&c.dec[0], &dst[0], &src[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *sm4CipherAsm) DecryptBlocks(dst, src []byte) {
|
||||||
|
if len(src) < FourBlocksSize {
|
||||||
|
panic("sm4: input not full blocks")
|
||||||
|
}
|
||||||
|
if len(dst) < FourBlocksSize {
|
||||||
|
panic("sm4: output not full blocks")
|
||||||
|
}
|
||||||
|
if smcipher.InexactOverlap(dst[:FourBlocksSize], src[:FourBlocksSize]) {
|
||||||
|
panic("sm4: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
encryptBlocksAsm(&c.dec[0], &dst[0], &src[0])
|
||||||
|
}
|
||||||
|
|
||||||
// expandKey is used by BenchmarkExpand to ensure that the asm implementation
|
// expandKey is used by BenchmarkExpand to ensure that the asm implementation
|
||||||
// of key expansion is used for the benchmark when it is available.
|
// of key expansion is used for the benchmark when it is available.
|
||||||
func expandKey(key []byte, enc, dec []uint32) {
|
func expandKey(key []byte, enc, dec []uint32) {
|
||||||
|
@ -361,3 +361,55 @@ func benchmarkSM4CCMOpen(b *testing.B, buf []byte) {
|
|||||||
sm4gcm, _ := smcipher.NewCCM(c)
|
sm4gcm, _ := smcipher.NewCCM(c)
|
||||||
benchmarkGCMOpen(b, sm4gcm, buf)
|
benchmarkGCMOpen(b, sm4gcm, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func benchmarkXTS(b *testing.B, cipherFunc func([]byte) (cipher.Block, error), length, keylen int64) {
|
||||||
|
c, err := smcipher.NewXTS(cipherFunc, make([]byte, keylen))
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("NewCipher failed: %s", err)
|
||||||
|
}
|
||||||
|
plaintext := make([]byte, length)
|
||||||
|
encrypted := make([]byte, length)
|
||||||
|
//decrypted := make([]byte, length)
|
||||||
|
b.SetBytes(int64(len(plaintext)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
c.Encrypt(encrypted, plaintext, 0)
|
||||||
|
//c.Decrypt(decrypted, encrypted[:len(plaintext)], 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAES128XTSEncrypt512(b *testing.B) {
|
||||||
|
benchmarkXTS(b, aes.NewCipher, 512, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAES128XTSEncrypt1K(b *testing.B) {
|
||||||
|
benchmarkXTS(b, aes.NewCipher, 1024, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAES128XTSEncrypt4K(b *testing.B) {
|
||||||
|
benchmarkXTS(b, aes.NewCipher, 4096, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAES256XTSEncrypt512(b *testing.B) {
|
||||||
|
benchmarkXTS(b, aes.NewCipher, 512, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAES256XTSEncrypt1K(b *testing.B) {
|
||||||
|
benchmarkXTS(b, aes.NewCipher, 1024, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAES256XTSEncrypt4K(b *testing.B) {
|
||||||
|
benchmarkXTS(b, aes.NewCipher, 4096, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSM4XTSEncrypt512(b *testing.B) {
|
||||||
|
benchmarkXTS(b, sm4.NewCipher, 512, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSM4XTSEncrypt1K(b *testing.B) {
|
||||||
|
benchmarkXTS(b, sm4.NewCipher, 1024, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSM4XTSEncrypt4K(b *testing.B) {
|
||||||
|
benchmarkXTS(b, sm4.NewCipher, 4096, 32)
|
||||||
|
}
|
||||||
|
93
sm4_test/xts_sm4_test.go
Normal file
93
sm4_test/xts_sm4_test.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package sm4_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/cipher"
|
||||||
|
"github.com/emmansun/gmsm/sm4"
|
||||||
|
)
|
||||||
|
|
||||||
|
var xtsTestVectors = []struct {
|
||||||
|
key string
|
||||||
|
sector uint64
|
||||||
|
plaintext string
|
||||||
|
ciphertext string
|
||||||
|
}{
|
||||||
|
{ // XTS-SM4-128 applied for a data unit of 32 bytes
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
0,
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"d9b421f731c894fdc35b77291fe4e3b02a1fb76698d59f0e51376c4ada5bc75d",
|
||||||
|
}, {
|
||||||
|
"1111111111111111111111111111111122222222222222222222222222222222",
|
||||||
|
0x3333333333,
|
||||||
|
"4444444444444444444444444444444444444444444444444444444444444444",
|
||||||
|
"a74d726c11196a32be04e001ff29d0c7932f9f3ec29bfcb64dd17f63cbd3ea31",
|
||||||
|
}, {
|
||||||
|
"fffefdfcfbfaf9f8f7f6f5f4f3f2f1f022222222222222222222222222222222",
|
||||||
|
0x3333333333,
|
||||||
|
"4444444444444444444444444444444444444444444444444444444444444444",
|
||||||
|
"7f76088effadf70c02ea9f95da0628d351bfcb9eac0563bcf17b710dab0a9826",
|
||||||
|
}, { // XTS-SM4-128 applied for a data unit of 512 bytes
|
||||||
|
"2718281828459045235360287471352631415926535897932384626433832795",
|
||||||
|
0,
|
||||||
|
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
|
||||||
|
"54dd65b6326faea8fad1a83c63614af39f721d8dfe177a30b66abf6a449980e1cdbe06afb73336f37a4d39de964a30d7d04a3799169c60258f6b748a61861aa5ec92a2c15b2b7c615a42aba499bbd6b71db9c789b2182089a25dd3df800ed1864d19f7ed45fd17a9480b0fb82d9b7fc3ed57e9a1140eaa778dd2dd679e3edc3dc4d55c950ebc531d9592f7c4638256d56518292a20af98fdd3a63600350a70ab5a40f4c285037ca01f251f19ecae0329ff77ad88cd5a4cdea2aeabc22148ffbd239bd10515bde1131dec8404e443dc763140d5f22bf33e0c6872d6b81d630f6f00cdd058fe80f9cbfb77707f93cee2ca92b915b8304027c190a84e2d65e018cc6a387d3766acdb28253284e8db9acf8f52280ddc6d0033d2ccaaa4f9aeff123669bc024fd6768edf8bc1f8d622c19c609ef97f609190cd110241e7fb084ed8942da1f9b9cf1b514b61a388b30ea61a4a745b381ee7ad6c4db1275453b8413f98df6e4a40986ee4b59af5dfaecd301265179067a00d7ca35ab95abd617adea28ec1c26a97de28b8bfe30120d6aefbd258c59e42d161e8065a78106bdca5cd90fb3aac4e93866c8a7f9676860a79145bd92e02e819a90be0b97cc522b32106856fdf0e54d88e4624155a2f1c14eaeaa163f858e99a806e791acd82f1b0e29f0028a4c38e976f571a93f4fd57d787c24db0e01ca304e5a5c4dd50cf8bdbf491e57c",
|
||||||
|
}, { // Vector 5
|
||||||
|
"2718281828459045235360287471352631415926535897932384626433832795",
|
||||||
|
1,
|
||||||
|
"27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568",
|
||||||
|
"0e36ba273dd121afc77e0d8c00aa4a662b21f363470d333f2fe2ddcbcc51ecd523022f5fa7970062800cd3859cacead369263681543db431f3844a3638e837cf025cecc3b778e14ac1fd02bb684d0e3cc3d05758cf4b3827bae92f9f09a45487e0a830154a4206a14c4077bcc928e6039b78cdf8f915236c5a4efc21a0ba7173232cef6f18f8b53be5e1eb37282bed31a24f322cf1bba02dfd2583ce216a73726915116fd8ce46d58aa562b5a5d88076792d6e35cba40552db6a19776eaf255c3fc927adc41cb83a83884f98176267f37e543ce34fa32960d1d05aa05ff04103037a730175f1d59a32b64f308925fc9fa9c60421b4ab438e14504227cba20c8c06b508554fb02e52b92a1cd0a8e386511bc4c2fb62998d0ac5d9e7614080a10039b8cddf24a644b3e0aa02bb5d6c0897a84bfe0d12690cbd9fb92fd39b5b9504deeeaab0c5b9839b6283b87abe6439d28f0afb0508104fd4db9fd6e0301c6a488e76fd2a4801d2b7df57e0179506e9a8dbd7312be3922ea4e7339227061485452296dabc3b0f178a2e4ba012bbb6e836dec5d25abaa0f399ca622c5f075dfae7b2ffef4e396cd74b9bc3aeb7c212a5fd5c42b73fcf92e1f4ca458bb50e7257c4ffea253f30f7eaf9a6762ce15177f55ba250a4293d6ecdbd2e9a80c942b38dbdbd74773245a7a7db6b91d1f6c74bd32b7a7a193a2d260d266b64dd19b959ae42",
|
||||||
|
}, { // XTS-SM4-128 applied for a data unit that is not a multiple of 16 bytes, but should be a complte byte
|
||||||
|
"c46acc2e7e013cb71cdbf750cf76b000249fbf4fb6cd17607773c23ffa2c4330",
|
||||||
|
94,
|
||||||
|
"7e9c2289cba460e470222953439cdaa892a5433d4dab2a3f67",
|
||||||
|
"c3cf5445c64aa518f4abce2848faddfb4605d9fb66f1f12c0c",
|
||||||
|
}, {
|
||||||
|
"56ffcc9bbbdf413f0fc0f888f44b7493bb1925a39b8adf02d9009bb16db0a887",
|
||||||
|
144,
|
||||||
|
"9a839cc14363bafcfc0cc93b14f8e769d35b94cc98267438e3",
|
||||||
|
"af027012c829206c32a31706999d046f10a83bcacbc5c96353",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"7454a43b87b1cf0dec95032c22873be3cace3bb795568854c1a008c07c5813f3",
|
||||||
|
108,
|
||||||
|
"41088fa15195b2733fe824d2c1fdc8306080863945fb2a73cf",
|
||||||
|
"614ee9311a53791889338eb2f66fedff7dc15126349bed1465",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromHex(s string) []byte {
|
||||||
|
ret, err := hex.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
panic("xts: invalid hex in test")
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXTS(t *testing.T) {
|
||||||
|
for i, test := range xtsTestVectors {
|
||||||
|
c, err := cipher.NewXTS(sm4.NewCipher, fromHex(test.key))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("#%d: failed to create cipher: %s", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
plaintext := fromHex(test.plaintext)
|
||||||
|
ciphertext := make([]byte, len(plaintext))
|
||||||
|
|
||||||
|
c.Encrypt(ciphertext, plaintext, test.sector)
|
||||||
|
expectedCiphertext := fromHex(test.ciphertext)
|
||||||
|
if !bytes.Equal(ciphertext, expectedCiphertext) {
|
||||||
|
t.Errorf("#%d: encrypted failed, got: %x, want: %x", i, ciphertext, expectedCiphertext)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted := make([]byte, len(ciphertext))
|
||||||
|
c.Decrypt(decrypted, ciphertext, test.sector)
|
||||||
|
if !bytes.Equal(decrypted, plaintext) {
|
||||||
|
t.Errorf("#%d: decryption failed, got: %x, want: %x", i, decrypted, plaintext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user