Skip to content

Commit

Permalink
update LengthPreservingMode interface
Browse files Browse the repository at this point in the history
  • Loading branch information
emmansun committed Dec 4, 2023
1 parent e5effb8 commit e8f39ed
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 15 deletions.
2 changes: 1 addition & 1 deletion cipher/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func BenchmarkSM4HCTREncrypt1K(b *testing.B) {
b.SetBytes(int64(len(buf)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
hctr.Encrypt(buf, buf)
hctr.EncryptBytes(buf, buf)
}
}

Expand Down
31 changes: 19 additions & 12 deletions cipher/hctr.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,32 @@ import (
// A LengthPreservingMode represents a block cipher running in a length preserving mode (HCTR,
// HCTR2 etc).
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
// 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
// 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.
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
// entirely or not at all.
//
// If len(dst) < len(src), Decrypt should panic. It is acceptable
// to pass a dst bigger than src, and in that case, Decrypt will
// If len(dst) < len(src), DecryptBytes should panic. It is acceptable
// 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.
//
// 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.
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
Expand Down Expand Up @@ -101,6 +104,10 @@ type hctr struct {
productTable [16]hctrFieldElement
}

func (h *hctr) BlockSize() int {
return blockSize
}

// 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.
func NewHCTR(cipher _cipher.Block, tweak, hkey []byte) (LengthPreservingMode, error) {
Expand Down Expand Up @@ -164,7 +171,7 @@ func (h *hctr) mul(y *hctrFieldElement) {
func (h *hctr) updateBlock(block []byte, y *hctrFieldElement) {
y.low ^= binary.BigEndian.Uint64(block)
y.high ^= binary.BigEndian.Uint64(block[8:blockSize])
h.mul(y)
h.mul(y)
}

// Universal Hash Function.
Expand Down Expand Up @@ -200,7 +207,7 @@ func (h *hctr) uhash(m []byte, out *[blockSize]byte) {
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) {
panic("hctr: ciphertext is smaller than plaintext")
}
Expand All @@ -225,7 +232,7 @@ func (h *hctr) Encrypt(ciphertext, plaintext []byte) {
subtle.XORBytes(ciphertext, z2[:], z1[:])
}

func (h *hctr) Decrypt(plaintext, ciphertext []byte) {
func (h *hctr) DecryptBytes(plaintext, ciphertext []byte) {
if len(plaintext) < len(ciphertext) {
panic("hctr: plaintext is smaller than cihpertext")
}
Expand Down
4 changes: 2 additions & 2 deletions cipher/hctr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ func TestHCTR(t *testing.T) {
if err != nil {
t.Fatal(err)
}
hctr.Encrypt(got, plaintext)
hctr.EncryptBytes(got, plaintext)
if !bytes.Equal(got, ciphertext) {
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) {
t.Fatalf("%v case decrypt failed, got %x\n", i+1, got)
}
Expand Down

1 comment on commit e8f39ed

@emmansun
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

虽然和cipher.BlockMode类似,加解密方法签名一样,可以用一个方法签名,譬如CryptBytes(dst, src []byte),但是实现起来我感觉更加啰嗦:需要两个不同的构造函数;底层Block实现特定接口时,加解密需要分开判定,所以这里使用了分开的加解密方法。

Please sign in to comment.