init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+249
View File
@@ -0,0 +1,249 @@
// Package xts implements the XTS cipher mode as specified in IEEE P1619/D16.
//
// XTS mode is typically used for disk encryption, which presents a number of
// novel problems that make more common modes inapplicable. The disk is
// conceptually an array of sectors and we must be able to encrypt and decrypt
// a sector in isolation. However, an attacker must not be able to transpose
// two sectors of plaintext by transposing their ciphertext.
//
// XTS wraps a block cipher with Rogaway's XEX mode in order to build a
// tweakable block cipher. This allows each sector to have a unique tweak and
// effectively create a unique key for each sector.
//
// XTS does not provide any authentication. An attacker can manipulate the
// ciphertext and randomise a block (16 bytes) of the plaintext. This package
// does not implement ciphertext-stealing so sectors must be a multiple of 16
// bytes.
//
// Note that XTS is usually not appropriate for any use besides disk encryption.
// Most users should use an AEAD mode like GCM (from crypto/cipher.NewGCM) instead.
package blockmode
import (
"xdx.jelly/xgcl/gerrors"
"xdx.jelly/xgcl/internal/xor"
)
// xts 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 EcbBlockMode
tweak []byte
outBuf []byte
}
var _ TernaryCrypter = &xts{}
// xtsBlockSize is the block size that the underlying cipher must have. XTS is
// only defined for 16-byte ciphers.
const xtsBlockSize = 16
// NewXTS 需要使用两个16字节key, 对应入参需要两个EcbEncBlockMode。
func NewXTS(ecb1, ecb2 EcbBlockMode) *xts {
return &xts{
k1: ecb1,
k2: ecb2,
tweak: make([]byte, 0, xtsBlockSize),
outBuf: make([]byte, 0, 2*xtsBlockSize),
}
}
func (x *xts) EncryptInit(tw []byte) error {
if len(tw) != xtsBlockSize {
return gerrors.WithAnnotating(ErrXTSEncFailed, "input tweak must be 16 bytes long")
}
if cap(x.outBuf) < 2*xtsBlockSize {
x.outBuf = make([]byte, 0, 2*xtsBlockSize)
}
x.outBuf = x.outBuf[:0]
x.tweak = append(x.tweak[:0], tw...)
_ = x.k2.EcbEncCryptBlocks(x.tweak, x.tweak)
return nil
}
func (x *xts) Encrypt(dst []byte, src []byte) ([]byte, error) {
dst, err := x.EncryptUpdate(dst, src)
if err != nil {
return nil, err
}
return x.EncryptFinal(dst)
}
func (x *xts) fillTweakMask(mask []byte) {
for i := 0; i < len(mask); i += xtsBlockSize {
copy(mask[i:i+xtsBlockSize], x.tweak[:])
mul2(x.tweak)
}
}
func (x *xts) EncryptUpdate(dst []byte, in []byte) ([]byte, error) {
// how many data in hand
dataLen := len(x.outBuf) + len(in)
if dataLen < 2*xtsBlockSize {
x.outBuf = append(x.outBuf, in...)
return dst, nil
}
// how many blocks to process in this update
m := (dataLen - xtsBlockSize) >> 4
mask := make([]byte, m<<4)
x.fillTweakMask(mask)
ret, out := sliceForAppend(dst, m<<4)
n := xor.XorBytes(out, mask, x.outBuf)
// TODO wrong if len(in) = 1
n = xor.XorBytes(out[n:], mask[n:], in)
in = in[n:]
_ = x.k1.EcbEncCryptBlocks(out, out)
xor.XorBytes(out, out, mask)
n = 0
if len(x.outBuf) > m<<4 {
n = copy(x.outBuf[:xtsBlockSize], x.outBuf[m<<4:])
}
x.outBuf = x.outBuf[:n]
x.outBuf = append(x.outBuf, in...)
return ret, nil
}
func (x *xts) EncryptFinal(dst []byte) ([]byte, error) {
if len(x.outBuf) < xtsBlockSize {
return dst, gerrors.WithAnnotating(ErrXTSEncFailed, "plaintext must be at least 16 bytes")
}
in0 := x.outBuf[:xtsBlockSize]
in1 := x.outBuf[xtsBlockSize:]
ret, out := sliceForAppend(dst, len(x.outBuf))
out0 := out[:xtsBlockSize]
out1 := out[xtsBlockSize:]
mask := make([]byte, xtsBlockSize)
x.fillTweakMask(mask)
xor.XorBytes(out0, mask, in0)
_ = x.k1.EcbEncCryptBlocks(out0, out0)
xor.XorBytes(out0, out0, mask)
if len(in1) > 0 {
lastBlock := make([]byte, len(in1), xtsBlockSize)
copy(lastBlock, in1)
lastBlock = append(lastBlock, out0[len(in1):]...)
x.fillTweakMask(mask)
xor.XorBytes(lastBlock, mask, lastBlock)
_ = x.k1.EcbEncCryptBlocks(lastBlock, lastBlock)
xor.XorBytes(lastBlock, lastBlock, mask)
copy(mask, out0)
copy(out0, lastBlock)
copy(out1, mask)
}
return ret, nil
}
func (x *xts) DecryptInit(tw []byte) error {
if len(tw) != xtsBlockSize {
return gerrors.WithAnnotating(ErrXTSDecFailed, "input tweak must be 16 bytes long")
}
x.tweak = append(x.tweak[:0], tw...)
if cap(x.outBuf) < 2*xtsBlockSize {
x.outBuf = make([]byte, 0, 2*xtsBlockSize)
}
x.outBuf = x.outBuf[:0]
_ = x.k2.EcbEncCryptBlocks(x.tweak, x.tweak)
return nil
}
func (x *xts) Decrypt(dst []byte, in []byte) ([]byte, error) {
dst, err := x.DecryptUpdate(dst, in)
if err != nil {
return nil, err
}
return x.DecryptFinal(dst)
}
func (x *xts) DecryptUpdate(dst []byte, in []byte) ([]byte, error) {
// how many data in hand
dataLen := len(x.outBuf) + len(in)
if dataLen < 2*xtsBlockSize {
x.outBuf = append(x.outBuf, in...)
return dst, nil
}
// how many blocks to process in this update
m := (dataLen - xtsBlockSize) >> 4
mask := make([]byte, m<<4)
x.fillTweakMask(mask)
ret, out := sliceForAppend(dst, m<<4)
n := xor.XorBytes(out, mask, x.outBuf)
// TODO wrong if len(in) = 1
n = xor.XorBytes(out[n:], mask[n:], in)
in = in[n:]
_ = x.k1.EcbDecCryptBlocks(out, out)
xor.XorBytes(out, out, mask)
n = 0
if len(x.outBuf) > m<<4 {
n = copy(x.outBuf[:xtsBlockSize], x.outBuf[m<<4:])
}
x.outBuf = x.outBuf[:n]
x.outBuf = append(x.outBuf, in...)
return ret, nil
}
func (x *xts) DecryptFinal(dst []byte) ([]byte, error) {
if len(x.outBuf) < xtsBlockSize {
return dst, gerrors.WithAnnotating(ErrXTSEncFailed, "plaintext must be at least 16 bytes")
}
in0 := x.outBuf[:xtsBlockSize]
in1 := x.outBuf[xtsBlockSize:]
ret, out := sliceForAppend(dst, len(x.outBuf))
out0 := out[:xtsBlockSize]
out1 := out[xtsBlockSize:]
mask := make([]byte, xtsBlockSize*2)
x.fillTweakMask(mask)
mask0 := mask[:xtsBlockSize]
mask1 := mask[xtsBlockSize:]
if len(in1) == 0 {
xor.XorBytes(out0, mask0, in0)
_ = x.k1.EcbDecCryptBlocks(out0, out0)
xor.XorBytes(out0, out0, mask0)
} else {
xor.XorBytes(out0, mask1, in0)
_ = x.k1.EcbDecCryptBlocks(out0, out0)
xor.XorBytes(out0, out0, mask1)
lastBlock := make([]byte, len(in1), xtsBlockSize)
copy(lastBlock, in1)
lastBlock = append(lastBlock, out0[len(in1):]...)
xor.XorBytes(lastBlock, mask0, lastBlock)
_ = x.k1.EcbDecCryptBlocks(lastBlock, lastBlock)
xor.XorBytes(lastBlock, lastBlock, mask0)
copy(mask, out0)
copy(out0, lastBlock)
copy(out1, mask)
}
return ret, nil
}
// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
// x¹²⁸ + x⁷ + x² + x + 1.
func mul2(tweak []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] ^= 1<<7 | 1<<2 | 1<<1 | 1
}
}