diff --git a/cipher/ccm.go b/cipher/ccm.go index a51a5a6..6ef4584 100644 --- a/cipher/ccm.go +++ b/cipher/ccm.go @@ -2,11 +2,14 @@ package cipher import ( goCipher "crypto/cipher" - "crypto/subtle" + goSubtle "crypto/subtle" "encoding/binary" "math" "errors" + + "github.com/emmansun/gmsm/internal/subtle" + "github.com/emmansun/gmsm/internal/xor" ) const ( @@ -109,14 +112,14 @@ func (c *ccm) deriveCounter(counter *[ccmBlockSize]byte, nonce []byte) { func (c *ccm) cmac(out, data []byte) { for len(data) >= ccmBlockSize { - XorBytes(out, out, data) + xor.XorBytes(out, out, data) c.cipher.Encrypt(out, out) data = data[ccmBlockSize:] } if len(data) > 0 { var block [ccmBlockSize]byte copy(block[:], data) - XorBytes(out, out, data) + xor.XorBytes(out, out, data) c.cipher.Encrypt(out, out) } } @@ -165,7 +168,7 @@ func (c *ccm) auth(nonce, plaintext, additionalData []byte, tagMask *[ccmBlockSi if len(plaintext) > 0 { c.cmac(out[:], plaintext) } - XorWords(out[:], out[:], tagMask[:]) + xor.XorWords(out[:], out[:], tagMask[:]) return out[:c.tagSize] } @@ -176,8 +179,8 @@ func (c *ccm) Seal(dst, nonce, plaintext, data []byte) []byte { if uint64(len(plaintext)) > uint64(c.MaxLength()) { panic("cipher: message too large for CCM") } - ret, out := SliceForAppend(dst, len(plaintext)+c.tagSize) - if InexactOverlap(out, plaintext) { + ret, out := subtle.SliceForAppend(dst, len(plaintext)+c.tagSize) + if subtle.InexactOverlap(out, plaintext) { panic("cipher: invalid buffer overlap") } @@ -222,8 +225,8 @@ func (c *ccm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { c.deriveCounter(&counter, nonce) c.cipher.Encrypt(tagMask[:], counter[:]) - ret, out := SliceForAppend(dst, len(ciphertext)) - if InexactOverlap(out, ciphertext) { + ret, out := subtle.SliceForAppend(dst, len(ciphertext)) + if subtle.InexactOverlap(out, ciphertext) { panic("cipher: invalid buffer overlap") } @@ -231,7 +234,7 @@ func (c *ccm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { ctr := goCipher.NewCTR(c.cipher, counter[:]) ctr.XORKeyStream(out, ciphertext) expectedTag := c.auth(nonce, out, data, &tagMask) - if subtle.ConstantTimeCompare(expectedTag, tag) != 1 { + if goSubtle.ConstantTimeCompare(expectedTag, tag) != 1 { // The AESNI code decrypts and authenticates concurrently, and // so overwrites dst in the event of a tag mismatch. That // behavior is mimicked here in order to be consistent across diff --git a/cipher/xts.go b/cipher/xts.go index cc4641d..86d5c6f 100644 --- a/cipher/xts.go +++ b/cipher/xts.go @@ -5,6 +5,9 @@ import ( "encoding/binary" "errors" "sync" + + "github.com/emmansun/gmsm/internal/subtle" + "github.com/emmansun/gmsm/internal/xor" ) const GF128_FDBK byte = 0x87 @@ -86,7 +89,7 @@ func (c *xts) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) { if len(plaintext) < blockSize { panic("xts: plaintext length is smaller than the block size") } - if InexactOverlap(ciphertext[:len(plaintext)], plaintext) { + if subtle.InexactOverlap(ciphertext[:len(plaintext)], plaintext) { panic("xts: invalid buffer overlap") } @@ -109,18 +112,18 @@ func (c *xts) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) { copy(tweaks[blockSize*i:], tweak[:]) mul2(tweak) } - XorBytes(ciphertext, plaintext, tweaks) + xor.XorBytes(ciphertext, plaintext, tweaks) concCipher.EncryptBlocks(ciphertext, ciphertext) - XorBytes(ciphertext, ciphertext, tweaks) + xor.XorBytes(ciphertext, ciphertext, tweaks) plaintext = plaintext[batchSize:] lastCiphertext = ciphertext[batchSize-blockSize:] ciphertext = ciphertext[batchSize:] } } for len(plaintext) >= blockSize { - XorBytes(ciphertext, plaintext, tweak[:]) + xor.XorBytes(ciphertext, plaintext, tweak[:]) c.k1.Encrypt(ciphertext, ciphertext) - XorBytes(ciphertext, ciphertext, tweak[:]) + xor.XorBytes(ciphertext, ciphertext, tweak[:]) plaintext = plaintext[blockSize:] lastCiphertext = ciphertext ciphertext = ciphertext[blockSize:] @@ -136,11 +139,11 @@ func (c *xts) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) { //Steal ciphertext to complete the block copy(x[remain:], lastCiphertext[remain:blockSize]) //Merge the tweak into the input block - XorBytes(x[:], x[:], tweak[:]) + xor.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[:]) + xor.XorBytes(lastCiphertext, x[:], tweak[:]) } tweakPool.Put(tweak) } @@ -155,7 +158,7 @@ func (c *xts) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) { if len(ciphertext) < blockSize { panic("xts: ciphertext length is smaller than the block size") } - if InexactOverlap(plaintext[:len(ciphertext)], ciphertext) { + if subtle.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) { panic("xts: invalid buffer overlap") } @@ -176,18 +179,18 @@ func (c *xts) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) { copy(tweaks[blockSize*i:], tweak[:]) mul2(tweak) } - XorBytes(plaintext, ciphertext, tweaks) + xor.XorBytes(plaintext, ciphertext, tweaks) concCipher.DecryptBlocks(plaintext, plaintext) - XorBytes(plaintext, plaintext, tweaks) + xor.XorBytes(plaintext, plaintext, tweaks) plaintext = plaintext[batchSize:] ciphertext = ciphertext[batchSize:] } } for len(ciphertext) >= 2*blockSize { - XorBytes(plaintext, ciphertext, tweak[:]) + xor.XorBytes(plaintext, ciphertext, tweak[:]) c.k1.Decrypt(plaintext, plaintext) - XorBytes(plaintext, plaintext, tweak[:]) + xor.XorBytes(plaintext, plaintext, tweak[:]) plaintext = plaintext[blockSize:] ciphertext = ciphertext[blockSize:] @@ -200,9 +203,9 @@ func (c *xts) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) { var tt [blockSize]byte copy(tt[:], tweak[:]) mul2(&tt) - XorBytes(x[:], ciphertext, tt[:]) + xor.XorBytes(x[:], ciphertext, tt[:]) c.k1.Decrypt(x[:], x[:]) - XorBytes(plaintext, x[:], tt[:]) + xor.XorBytes(plaintext, x[:], tt[:]) //Retrieve the length of the final block remain -= blockSize @@ -217,9 +220,9 @@ func (c *xts) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) { //The last block contains exactly 128 bits copy(x[:], ciphertext) } - XorBytes(x[:], x[:], tweak[:]) + xor.XorBytes(x[:], x[:], tweak[:]) c.k1.Decrypt(x[:], x[:]) - XorBytes(plaintext, x[:], tweak[:]) + xor.XorBytes(plaintext, x[:], tweak[:]) } tweakPool.Put(tweak) diff --git a/cipher/utils.go b/internal/subtle/aliasing.go similarity index 96% rename from cipher/utils.go rename to internal/subtle/aliasing.go index eee6a26..a774126 100644 --- a/cipher/utils.go +++ b/internal/subtle/aliasing.go @@ -1,4 +1,4 @@ -package cipher +package subtle import "unsafe" diff --git a/cipher/xor_amd64.go b/internal/xor/xor_amd64.go similarity index 93% rename from cipher/xor_amd64.go rename to internal/xor/xor_amd64.go index 07e4d0f..969eaf6 100644 --- a/cipher/xor_amd64.go +++ b/internal/xor/xor_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package cipher +package xor // XorBytes xors the bytes in a and b. The destination should have enough // space, otherwise xorBytes will panic. Returns the number of bytes xor'd. diff --git a/cipher/xor_amd64.s b/internal/xor/xor_amd64.s similarity index 100% rename from cipher/xor_amd64.s rename to internal/xor/xor_amd64.s diff --git a/cipher/xor_generic.go b/internal/xor/xor_generic.go similarity index 95% rename from cipher/xor_generic.go rename to internal/xor/xor_generic.go index b7451ea..9f76174 100644 --- a/cipher/xor_generic.go +++ b/internal/xor/xor_generic.go @@ -4,7 +4,7 @@ // +build !amd64 -package cipher +package xor import ( "runtime" diff --git a/sm4/cbc_amd64.go b/sm4/cbc_amd64.go index b7c7cce..e7f8509 100644 --- a/sm4/cbc_amd64.go +++ b/sm4/cbc_amd64.go @@ -3,7 +3,8 @@ package sm4 import ( "crypto/cipher" - smcipher "github.com/emmansun/gmsm/cipher" + "github.com/emmansun/gmsm/internal/subtle" + "github.com/emmansun/gmsm/internal/xor" ) // Assert that sm4CipherAsm implements the cbcDecAble interfaces. @@ -33,7 +34,7 @@ func (x *cbc) CryptBlocks(dst, src []byte) { if len(dst) < len(src) { panic("cipher: output smaller than input") } - if smcipher.InexactOverlap(dst[:len(src)], src) { + if subtle.InexactOverlap(dst[:len(src)], src) { panic("cipher: invalid buffer overlap") } if len(src) == 0 { @@ -46,10 +47,10 @@ func (x *cbc) CryptBlocks(dst, src []byte) { var src64 []byte = make([]byte, FourBlocksSize) for start > 0 { encryptBlocksAsm(&x.b.dec[0], &temp[0], &src[start:end][0]) - smcipher.XorBytes(dst[end-BlockSize:end], temp[FourBlocksSize-BlockSize:FourBlocksSize], src[end-2*BlockSize:end-BlockSize]) - smcipher.XorBytes(dst[end-2*BlockSize:end-BlockSize], temp[FourBlocksSize-2*BlockSize:FourBlocksSize-BlockSize], src[end-3*BlockSize:end-2*BlockSize]) - smcipher.XorBytes(dst[end-3*BlockSize:end-2*BlockSize], temp[FourBlocksSize-3*BlockSize:FourBlocksSize-2*BlockSize], src[end-4*BlockSize:end-3*BlockSize]) - smcipher.XorBytes(dst[end-4*BlockSize:end-3*BlockSize], temp[:BlockSize], src[end-5*BlockSize:end-4*BlockSize]) + xor.XorBytes(dst[end-BlockSize:end], temp[FourBlocksSize-BlockSize:FourBlocksSize], src[end-2*BlockSize:end-BlockSize]) + xor.XorBytes(dst[end-2*BlockSize:end-BlockSize], temp[FourBlocksSize-2*BlockSize:FourBlocksSize-BlockSize], src[end-3*BlockSize:end-2*BlockSize]) + xor.XorBytes(dst[end-3*BlockSize:end-2*BlockSize], temp[FourBlocksSize-3*BlockSize:FourBlocksSize-2*BlockSize], src[end-4*BlockSize:end-3*BlockSize]) + xor.XorBytes(dst[end-4*BlockSize:end-3*BlockSize], temp[:BlockSize], src[end-5*BlockSize:end-4*BlockSize]) end = start start -= FourBlocksSize @@ -59,10 +60,10 @@ func (x *cbc) CryptBlocks(dst, src []byte) { encryptBlocksAsm(&x.b.dec[0], &temp[0], &src[:end][0]) count := end / BlockSize for i := count; i > 1; i-- { - smcipher.XorBytes(dst[end-BlockSize:end], temp[end-BlockSize:end], src[end-2*BlockSize:end-BlockSize]) + xor.XorBytes(dst[end-BlockSize:end], temp[end-BlockSize:end], src[end-2*BlockSize:end-BlockSize]) end -= BlockSize } - smcipher.XorBytes(dst[0:end], temp[0:end], x.iv[:]) + xor.XorBytes(dst[0:end], temp[0:end], x.iv[:]) // Set the new iv to the first block we copied earlier. x.iv, x.tmp = x.tmp, x.iv } diff --git a/sm4/cipher.go b/sm4/cipher.go index 3e3a175..0f5a671 100644 --- a/sm4/cipher.go +++ b/sm4/cipher.go @@ -4,7 +4,7 @@ import ( "crypto/cipher" "fmt" - smcipher "github.com/emmansun/gmsm/cipher" + "github.com/emmansun/gmsm/internal/subtle" ) // BlockSize the sm4 block size in bytes. @@ -48,7 +48,7 @@ func (c *sm4Cipher) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("sm4: output not full block") } - if smcipher.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("sm4: invalid buffer overlap") } encryptBlockGo(c.enc, dst, src) @@ -61,7 +61,7 @@ func (c *sm4Cipher) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("sm4: output not full block") } - if smcipher.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("sm4: invalid buffer overlap") } decryptBlockGo(c.dec, dst, src) diff --git a/sm4/cipher_asm.go b/sm4/cipher_asm.go index 0540cfd..e9d4870 100644 --- a/sm4/cipher_asm.go +++ b/sm4/cipher_asm.go @@ -5,7 +5,7 @@ package sm4 import ( "crypto/cipher" - smcipher "github.com/emmansun/gmsm/cipher" + "github.com/emmansun/gmsm/internal/subtle" "golang.org/x/sys/cpu" ) @@ -52,7 +52,7 @@ func (c *sm4CipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("sm4: output not full block") } - if smcipher.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("sm4: invalid buffer overlap") } encryptBlockAsm(&c.enc[0], &dst[0], &src[0]) @@ -65,7 +65,7 @@ func (c *sm4CipherAsm) EncryptBlocks(dst, src []byte) { if len(dst) < FourBlocksSize { panic("sm4: output not full blocks") } - if smcipher.InexactOverlap(dst[:FourBlocksSize], src[:FourBlocksSize]) { + if subtle.InexactOverlap(dst[:FourBlocksSize], src[:FourBlocksSize]) { panic("sm4: invalid buffer overlap") } encryptBlocksAsm(&c.enc[0], &dst[0], &src[0]) @@ -78,7 +78,7 @@ func (c *sm4CipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("sm4: output not full block") } - if smcipher.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("sm4: invalid buffer overlap") } encryptBlockAsm(&c.dec[0], &dst[0], &src[0]) @@ -91,7 +91,7 @@ func (c *sm4CipherAsm) DecryptBlocks(dst, src []byte) { if len(dst) < FourBlocksSize { panic("sm4: output not full blocks") } - if smcipher.InexactOverlap(dst[:FourBlocksSize], src[:FourBlocksSize]) { + if subtle.InexactOverlap(dst[:FourBlocksSize], src[:FourBlocksSize]) { panic("sm4: invalid buffer overlap") } encryptBlocksAsm(&c.dec[0], &dst[0], &src[0]) diff --git a/sm4/ctr_amd64.go b/sm4/ctr_amd64.go index 27582a2..1d5782e 100644 --- a/sm4/ctr_amd64.go +++ b/sm4/ctr_amd64.go @@ -3,7 +3,8 @@ package sm4 import ( "crypto/cipher" - smcipher "github.com/emmansun/gmsm/cipher" + "github.com/emmansun/gmsm/internal/subtle" + "github.com/emmansun/gmsm/internal/xor" ) // Assert that sm4CipherAsm implements the ctrAble interface. @@ -80,14 +81,14 @@ func (x *ctr) XORKeyStream(dst, src []byte) { if len(dst) < len(src) { panic("cipher: output smaller than input") } - if smcipher.InexactOverlap(dst[:len(src)], src) { + if subtle.InexactOverlap(dst[:len(src)], src) { panic("cipher: invalid buffer overlap") } for len(src) > 0 { if x.outUsed >= len(x.out)-BlockSize { x.refill() } - n := smcipher.XorBytes(dst, src, x.out[x.outUsed:]) + n := xor.XorBytes(dst, src, x.out[x.outUsed:]) dst = dst[n:] src = src[n:] x.outUsed += n diff --git a/sm4/gcm_amd64.go b/sm4/gcm_amd64.go index 7ad1ea6..662aa18 100644 --- a/sm4/gcm_amd64.go +++ b/sm4/gcm_amd64.go @@ -2,11 +2,12 @@ package sm4 import ( "crypto/cipher" - "crypto/subtle" + goSubtle "crypto/subtle" "encoding/binary" "errors" - smcipher "github.com/emmansun/gmsm/cipher" + "github.com/emmansun/gmsm/internal/subtle" + "github.com/emmansun/gmsm/internal/xor" ) // Assert that sm4CipherAsm implements the gcmAble interface. @@ -82,8 +83,8 @@ func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte { panic("cipher: message too large for GCM") } - ret, out := smcipher.SliceForAppend(dst, len(plaintext)+g.tagSize) - if smcipher.InexactOverlap(out, plaintext) { + ret, out := subtle.SliceForAppend(dst, len(plaintext)+g.tagSize) + if subtle.InexactOverlap(out, plaintext) { panic("cipher: invalid buffer overlap") } @@ -133,12 +134,12 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { var expectedTag [gcmTagSize]byte g.auth(expectedTag[:], ciphertext, data, &tagMask) - ret, out := smcipher.SliceForAppend(dst, len(ciphertext)) - if smcipher.InexactOverlap(out, ciphertext) { + ret, out := subtle.SliceForAppend(dst, len(ciphertext)) + if subtle.InexactOverlap(out, ciphertext) { panic("cipher: invalid buffer overlap") } - if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { + if goSubtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { // The AESNI code decrypts and authenticates concurrently, and // so overwrites dst in the event of a tag mismatch. That // behavior is mimicked here in order to be consistent across @@ -275,7 +276,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) { encryptBlocksAsm(&g.cipher.enc[0], &mask[0], &couters[0]) gcmInc32(counter) - smcipher.XorWords(out, in, mask[:]) + xor.XorWords(out, in, mask[:]) out = out[FourBlocksSize:] in = in[FourBlocksSize:] } @@ -287,7 +288,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) { gcmInc32(counter) } encryptBlocksAsm(&g.cipher.enc[0], &mask[0], &couters[0]) - smcipher.XorBytes(out, in, mask[:blocks*gcmBlockSize]) + xor.XorBytes(out, in, mask[:blocks*gcmBlockSize]) } } @@ -329,5 +330,5 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize] binary.BigEndian.PutUint64(out, y.low) binary.BigEndian.PutUint64(out[8:], y.high) - smcipher.XorWords(out, out, tagMask[:]) + xor.XorWords(out, out, tagMask[:]) } diff --git a/sm4/sm4_gcm.go b/sm4/sm4_gcm.go index baebd81..ed79447 100644 --- a/sm4/sm4_gcm.go +++ b/sm4/sm4_gcm.go @@ -3,9 +3,9 @@ package sm4 import ( "crypto/cipher" - "crypto/subtle" + goSubtle "crypto/subtle" - smcipher "github.com/emmansun/gmsm/cipher" + "github.com/emmansun/gmsm/internal/subtle" ) // sm4CipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM @@ -82,8 +82,8 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { gcmSm4Data(&g.bytesProductTable, data, &tagOut) - ret, out := smcipher.SliceForAppend(dst, len(plaintext)+g.tagSize) - if smcipher.InexactOverlap(out[:len(plaintext)], plaintext) { + ret, out := subtle.SliceForAppend(dst, len(plaintext)+g.tagSize) + if subtle.InexactOverlap(out[:len(plaintext)], plaintext) { panic("cipher: invalid buffer overlap") } @@ -138,8 +138,8 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { var expectedTag [gcmTagSize]byte gcmSm4Data(&g.bytesProductTable, data, &expectedTag) - ret, out := smcipher.SliceForAppend(dst, len(ciphertext)) - if smcipher.InexactOverlap(out, ciphertext) { + ret, out := subtle.SliceForAppend(dst, len(ciphertext)) + if subtle.InexactOverlap(out, ciphertext) { panic("cipher: invalid buffer overlap") } if len(ciphertext) > 0 { @@ -147,7 +147,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { } gcmSm4Finish(&g.bytesProductTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data))) - if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { + if goSubtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { for i := range out { out[i] = 0 }