update LengthPreservingMode interface

This commit is contained in:
emmansun 2023-12-04 10:27:26 +08:00
parent e5effb8bb9
commit e8f39ed529
3 changed files with 22 additions and 15 deletions

View File

@ -21,7 +21,7 @@ func BenchmarkSM4HCTREncrypt1K(b *testing.B) {
b.SetBytes(int64(len(buf))) b.SetBytes(int64(len(buf)))
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
hctr.Encrypt(buf, buf) hctr.EncryptBytes(buf, buf)
} }
} }

View File

@ -12,29 +12,32 @@ import (
// A LengthPreservingMode represents a block cipher running in a length preserving mode (HCTR, // A LengthPreservingMode represents a block cipher running in a length preserving mode (HCTR,
// HCTR2 etc). // HCTR2 etc).
type LengthPreservingMode interface { type LengthPreservingMode interface {
// Encrypt encrypts a number of plaintext bytes. The length of // EncryptBytes encrypts a number of plaintext bytes. The length of
// src must be NOT smaller than block size. Dst and src must overlap // src must be NOT smaller than block size. Dst and src must overlap
// entirely or not at all. // entirely or not at all.
// //
// If len(dst) < len(src), Encrypt should panic. It is acceptable // If len(dst) < len(src), EncryptBytes should panic. It is acceptable
// to pass a dst bigger than src, and in that case, Encrypt will // to pass a dst bigger than src, and in that case, Encrypt will
// only update dst[:len(src)] and will not touch the rest of dst. // only update dst[:len(src)] and will not touch the rest of dst.
// //
// Multiple calls to Encrypt behave NOT same as if the concatenation of // Multiple calls to EncryptBytes behave NOT same as if the concatenation of
// the src buffers was passed in a single run. // the src buffers was passed in a single run.
Encrypt(dst, src []byte) EncryptBytes(dst, src []byte)
// Decrypt decrypts a number of ciphertext bytes. The length of // DecryptBytes decrypts a number of ciphertext bytes. The length of
// src must be NOT smaller than block size. Dst and src must overlap // src must be NOT smaller than block size. Dst and src must overlap
// entirely or not at all. // entirely or not at all.
// //
// If len(dst) < len(src), Decrypt should panic. It is acceptable // If len(dst) < len(src), DecryptBytes should panic. It is acceptable
// to pass a dst bigger than src, and in that case, Decrypt will // to pass a dst bigger than src, and in that case, DecryptBytes will
// only update dst[:len(src)] and will not touch the rest of dst. // only update dst[:len(src)] and will not touch the rest of dst.
// //
// Multiple calls to Decrypt behave NOT same as if the concatenation of // Multiple calls to DecryptBytes behave NOT same as if the concatenation of
// the src buffers was passed in a single run. // the src buffers was passed in a single run.
Decrypt(dst, src []byte) DecryptBytes(dst, src []byte)
// BlockSize returns the mode's block size.
BlockSize() int
} }
// hctrFieldElement represents a value in GF(2¹²⁸). In order to reflect the HCTR // hctrFieldElement represents a value in GF(2¹²⁸). In order to reflect the HCTR
@ -101,6 +104,10 @@ type hctr struct {
productTable [16]hctrFieldElement productTable [16]hctrFieldElement
} }
func (h *hctr) BlockSize() int {
return blockSize
}
// NewHCTR returns a [LengthPreservingMode] which encrypts/decrypts useing the given [Block] // NewHCTR returns a [LengthPreservingMode] which encrypts/decrypts useing the given [Block]
// in HCTR mode. The lenght of tweak and hash key must be the same as the [Block]'s block size. // in HCTR mode. The lenght of tweak and hash key must be the same as the [Block]'s block size.
func NewHCTR(cipher _cipher.Block, tweak, hkey []byte) (LengthPreservingMode, error) { func NewHCTR(cipher _cipher.Block, tweak, hkey []byte) (LengthPreservingMode, error) {
@ -164,7 +171,7 @@ func (h *hctr) mul(y *hctrFieldElement) {
func (h *hctr) updateBlock(block []byte, y *hctrFieldElement) { func (h *hctr) updateBlock(block []byte, y *hctrFieldElement) {
y.low ^= binary.BigEndian.Uint64(block) y.low ^= binary.BigEndian.Uint64(block)
y.high ^= binary.BigEndian.Uint64(block[8:blockSize]) y.high ^= binary.BigEndian.Uint64(block[8:blockSize])
h.mul(y) h.mul(y)
} }
// Universal Hash Function. // Universal Hash Function.
@ -200,7 +207,7 @@ func (h *hctr) uhash(m []byte, out *[blockSize]byte) {
binary.BigEndian.PutUint64(out[8:], y.high) binary.BigEndian.PutUint64(out[8:], y.high)
} }
func (h *hctr) Encrypt(ciphertext, plaintext []byte) { func (h *hctr) EncryptBytes(ciphertext, plaintext []byte) {
if len(ciphertext) < len(plaintext) { if len(ciphertext) < len(plaintext) {
panic("hctr: ciphertext is smaller than plaintext") panic("hctr: ciphertext is smaller than plaintext")
} }
@ -225,7 +232,7 @@ func (h *hctr) Encrypt(ciphertext, plaintext []byte) {
subtle.XORBytes(ciphertext, z2[:], z1[:]) subtle.XORBytes(ciphertext, z2[:], z1[:])
} }
func (h *hctr) Decrypt(plaintext, ciphertext []byte) { func (h *hctr) DecryptBytes(plaintext, ciphertext []byte) {
if len(plaintext) < len(ciphertext) { if len(plaintext) < len(ciphertext) {
panic("hctr: plaintext is smaller than cihpertext") panic("hctr: plaintext is smaller than cihpertext")
} }

View File

@ -62,12 +62,12 @@ func TestHCTR(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
hctr.Encrypt(got, plaintext) hctr.EncryptBytes(got, plaintext)
if !bytes.Equal(got, ciphertext) { if !bytes.Equal(got, ciphertext) {
t.Fatalf("%v case encrypt failed, got %x\n", i+1, got) t.Fatalf("%v case encrypt failed, got %x\n", i+1, got)
} }
hctr.Decrypt(got, ciphertext) hctr.DecryptBytes(got, ciphertext)
if !bytes.Equal(got, plaintext) { if !bytes.Equal(got, plaintext) {
t.Fatalf("%v case decrypt failed, got %x\n", i+1, got) t.Fatalf("%v case decrypt failed, got %x\n", i+1, got)
} }