From 5edcb0f96694ae81fc49ce9f474d0762d08317ca Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Tue, 11 Mar 2025 11:43:49 +0800 Subject: [PATCH] sm4: move implementation detail to internal --- {sm4 => internal/sm4}/aesni_macros_amd64.s | 0 {sm4 => internal/sm4}/aesni_macros_arm64.s | 0 {sm4 => internal/sm4}/aesni_macros_ppc64x.s | 0 {sm4 => internal/sm4}/asm_amd64.s | 0 {sm4 => internal/sm4}/asm_arm64.s | 0 {sm4 => internal/sm4}/asm_ppc64x.s | 0 {sm4 => internal/sm4}/block.go | 0 {sm4 => internal/sm4}/cbc_amd64.s | 0 {sm4 => internal/sm4}/cbc_arm64.s | 0 {sm4 => internal/sm4}/cbc_cipher_asm.go | 0 {sm4 => internal/sm4}/cbc_cipher_test.go | 0 {sm4 => internal/sm4}/cbc_ppc64x.s | 0 {sm4 => internal/sm4}/cipher.go | 0 {sm4 => internal/sm4}/cipher_asm.go | 0 .../sm4}/cipher_asm_fuzzy_test.go | 0 {sm4 => internal/sm4}/cipher_asm_test.go | 0 {sm4 => internal/sm4}/cipher_generic.go | 0 {sm4 => internal/sm4}/cipher_ni.go | 0 {sm4 => internal/sm4}/cipher_test.go | 0 {sm4 => internal/sm4}/const.go | 0 {sm4 => internal/sm4}/ctr_cipher_asm.go | 0 {sm4 => internal/sm4}/ecb_amd64.s | 0 {sm4 => internal/sm4}/ecb_arm64.s | 0 {sm4 => internal/sm4}/ecb_cipher_asm.go | 0 {sm4 => internal/sm4}/ecb_cipher_asm_test.go | 0 {sm4 => internal/sm4}/ecb_ppc64x.s | 0 {sm4 => internal/sm4}/gcm_amd64.s | 0 {sm4 => internal/sm4}/gcm_arm64.s | 0 {sm4 => internal/sm4}/gcm_cipher_asm.go | 0 {sm4 => internal/sm4}/gcm_ppc64x.go | 0 {sm4 => internal/sm4}/gcm_ppc64x.s | 0 {sm4 => internal/sm4}/gcm_ppc64x_test.go | 0 {sm4 => internal/sm4}/gcm_sm4ni_arm64.s | 0 {sm4 => internal/sm4}/gen_arm64_ni.go | 0 {sm4 => internal/sm4}/modes.go | 0 {sm4 => internal/sm4}/sm4_gcm_asm.go | 0 {sm4 => internal/sm4}/sm4_xts.go | 0 {sm4 => internal/sm4}/sm4ni_gcm_asm.go | 0 {sm4 => internal/sm4}/sm4ni_macros_arm64.s | 0 {sm4 => internal/sm4}/sm4ni_xts.go | 0 {sm4 => internal/sm4}/xts_amd64.s | 0 {sm4 => internal/sm4}/xts_arm64.s | 0 {sm4 => internal/sm4}/xts_macros_arm64.s | 0 {sm4 => internal/sm4}/xts_sm4ni_arm64.s | 0 sm4/sm4.go | 31 +++++ sm4/sm4_test.go | 125 ++++++++++++++++++ 46 files changed, 156 insertions(+) rename {sm4 => internal/sm4}/aesni_macros_amd64.s (100%) rename {sm4 => internal/sm4}/aesni_macros_arm64.s (100%) rename {sm4 => internal/sm4}/aesni_macros_ppc64x.s (100%) rename {sm4 => internal/sm4}/asm_amd64.s (100%) rename {sm4 => internal/sm4}/asm_arm64.s (100%) rename {sm4 => internal/sm4}/asm_ppc64x.s (100%) rename {sm4 => internal/sm4}/block.go (100%) rename {sm4 => internal/sm4}/cbc_amd64.s (100%) rename {sm4 => internal/sm4}/cbc_arm64.s (100%) rename {sm4 => internal/sm4}/cbc_cipher_asm.go (100%) rename {sm4 => internal/sm4}/cbc_cipher_test.go (100%) rename {sm4 => internal/sm4}/cbc_ppc64x.s (100%) rename {sm4 => internal/sm4}/cipher.go (100%) rename {sm4 => internal/sm4}/cipher_asm.go (100%) rename {sm4 => internal/sm4}/cipher_asm_fuzzy_test.go (100%) rename {sm4 => internal/sm4}/cipher_asm_test.go (100%) rename {sm4 => internal/sm4}/cipher_generic.go (100%) rename {sm4 => internal/sm4}/cipher_ni.go (100%) rename {sm4 => internal/sm4}/cipher_test.go (100%) rename {sm4 => internal/sm4}/const.go (100%) rename {sm4 => internal/sm4}/ctr_cipher_asm.go (100%) rename {sm4 => internal/sm4}/ecb_amd64.s (100%) rename {sm4 => internal/sm4}/ecb_arm64.s (100%) rename {sm4 => internal/sm4}/ecb_cipher_asm.go (100%) rename {sm4 => internal/sm4}/ecb_cipher_asm_test.go (100%) rename {sm4 => internal/sm4}/ecb_ppc64x.s (100%) rename {sm4 => internal/sm4}/gcm_amd64.s (100%) rename {sm4 => internal/sm4}/gcm_arm64.s (100%) rename {sm4 => internal/sm4}/gcm_cipher_asm.go (100%) rename {sm4 => internal/sm4}/gcm_ppc64x.go (100%) rename {sm4 => internal/sm4}/gcm_ppc64x.s (100%) rename {sm4 => internal/sm4}/gcm_ppc64x_test.go (100%) rename {sm4 => internal/sm4}/gcm_sm4ni_arm64.s (100%) rename {sm4 => internal/sm4}/gen_arm64_ni.go (100%) rename {sm4 => internal/sm4}/modes.go (100%) rename {sm4 => internal/sm4}/sm4_gcm_asm.go (100%) rename {sm4 => internal/sm4}/sm4_xts.go (100%) rename {sm4 => internal/sm4}/sm4ni_gcm_asm.go (100%) rename {sm4 => internal/sm4}/sm4ni_macros_arm64.s (100%) rename {sm4 => internal/sm4}/sm4ni_xts.go (100%) rename {sm4 => internal/sm4}/xts_amd64.s (100%) rename {sm4 => internal/sm4}/xts_arm64.s (100%) rename {sm4 => internal/sm4}/xts_macros_arm64.s (100%) rename {sm4 => internal/sm4}/xts_sm4ni_arm64.s (100%) create mode 100644 sm4/sm4.go create mode 100644 sm4/sm4_test.go diff --git a/sm4/aesni_macros_amd64.s b/internal/sm4/aesni_macros_amd64.s similarity index 100% rename from sm4/aesni_macros_amd64.s rename to internal/sm4/aesni_macros_amd64.s diff --git a/sm4/aesni_macros_arm64.s b/internal/sm4/aesni_macros_arm64.s similarity index 100% rename from sm4/aesni_macros_arm64.s rename to internal/sm4/aesni_macros_arm64.s diff --git a/sm4/aesni_macros_ppc64x.s b/internal/sm4/aesni_macros_ppc64x.s similarity index 100% rename from sm4/aesni_macros_ppc64x.s rename to internal/sm4/aesni_macros_ppc64x.s diff --git a/sm4/asm_amd64.s b/internal/sm4/asm_amd64.s similarity index 100% rename from sm4/asm_amd64.s rename to internal/sm4/asm_amd64.s diff --git a/sm4/asm_arm64.s b/internal/sm4/asm_arm64.s similarity index 100% rename from sm4/asm_arm64.s rename to internal/sm4/asm_arm64.s diff --git a/sm4/asm_ppc64x.s b/internal/sm4/asm_ppc64x.s similarity index 100% rename from sm4/asm_ppc64x.s rename to internal/sm4/asm_ppc64x.s diff --git a/sm4/block.go b/internal/sm4/block.go similarity index 100% rename from sm4/block.go rename to internal/sm4/block.go diff --git a/sm4/cbc_amd64.s b/internal/sm4/cbc_amd64.s similarity index 100% rename from sm4/cbc_amd64.s rename to internal/sm4/cbc_amd64.s diff --git a/sm4/cbc_arm64.s b/internal/sm4/cbc_arm64.s similarity index 100% rename from sm4/cbc_arm64.s rename to internal/sm4/cbc_arm64.s diff --git a/sm4/cbc_cipher_asm.go b/internal/sm4/cbc_cipher_asm.go similarity index 100% rename from sm4/cbc_cipher_asm.go rename to internal/sm4/cbc_cipher_asm.go diff --git a/sm4/cbc_cipher_test.go b/internal/sm4/cbc_cipher_test.go similarity index 100% rename from sm4/cbc_cipher_test.go rename to internal/sm4/cbc_cipher_test.go diff --git a/sm4/cbc_ppc64x.s b/internal/sm4/cbc_ppc64x.s similarity index 100% rename from sm4/cbc_ppc64x.s rename to internal/sm4/cbc_ppc64x.s diff --git a/sm4/cipher.go b/internal/sm4/cipher.go similarity index 100% rename from sm4/cipher.go rename to internal/sm4/cipher.go diff --git a/sm4/cipher_asm.go b/internal/sm4/cipher_asm.go similarity index 100% rename from sm4/cipher_asm.go rename to internal/sm4/cipher_asm.go diff --git a/sm4/cipher_asm_fuzzy_test.go b/internal/sm4/cipher_asm_fuzzy_test.go similarity index 100% rename from sm4/cipher_asm_fuzzy_test.go rename to internal/sm4/cipher_asm_fuzzy_test.go diff --git a/sm4/cipher_asm_test.go b/internal/sm4/cipher_asm_test.go similarity index 100% rename from sm4/cipher_asm_test.go rename to internal/sm4/cipher_asm_test.go diff --git a/sm4/cipher_generic.go b/internal/sm4/cipher_generic.go similarity index 100% rename from sm4/cipher_generic.go rename to internal/sm4/cipher_generic.go diff --git a/sm4/cipher_ni.go b/internal/sm4/cipher_ni.go similarity index 100% rename from sm4/cipher_ni.go rename to internal/sm4/cipher_ni.go diff --git a/sm4/cipher_test.go b/internal/sm4/cipher_test.go similarity index 100% rename from sm4/cipher_test.go rename to internal/sm4/cipher_test.go diff --git a/sm4/const.go b/internal/sm4/const.go similarity index 100% rename from sm4/const.go rename to internal/sm4/const.go diff --git a/sm4/ctr_cipher_asm.go b/internal/sm4/ctr_cipher_asm.go similarity index 100% rename from sm4/ctr_cipher_asm.go rename to internal/sm4/ctr_cipher_asm.go diff --git a/sm4/ecb_amd64.s b/internal/sm4/ecb_amd64.s similarity index 100% rename from sm4/ecb_amd64.s rename to internal/sm4/ecb_amd64.s diff --git a/sm4/ecb_arm64.s b/internal/sm4/ecb_arm64.s similarity index 100% rename from sm4/ecb_arm64.s rename to internal/sm4/ecb_arm64.s diff --git a/sm4/ecb_cipher_asm.go b/internal/sm4/ecb_cipher_asm.go similarity index 100% rename from sm4/ecb_cipher_asm.go rename to internal/sm4/ecb_cipher_asm.go diff --git a/sm4/ecb_cipher_asm_test.go b/internal/sm4/ecb_cipher_asm_test.go similarity index 100% rename from sm4/ecb_cipher_asm_test.go rename to internal/sm4/ecb_cipher_asm_test.go diff --git a/sm4/ecb_ppc64x.s b/internal/sm4/ecb_ppc64x.s similarity index 100% rename from sm4/ecb_ppc64x.s rename to internal/sm4/ecb_ppc64x.s diff --git a/sm4/gcm_amd64.s b/internal/sm4/gcm_amd64.s similarity index 100% rename from sm4/gcm_amd64.s rename to internal/sm4/gcm_amd64.s diff --git a/sm4/gcm_arm64.s b/internal/sm4/gcm_arm64.s similarity index 100% rename from sm4/gcm_arm64.s rename to internal/sm4/gcm_arm64.s diff --git a/sm4/gcm_cipher_asm.go b/internal/sm4/gcm_cipher_asm.go similarity index 100% rename from sm4/gcm_cipher_asm.go rename to internal/sm4/gcm_cipher_asm.go diff --git a/sm4/gcm_ppc64x.go b/internal/sm4/gcm_ppc64x.go similarity index 100% rename from sm4/gcm_ppc64x.go rename to internal/sm4/gcm_ppc64x.go diff --git a/sm4/gcm_ppc64x.s b/internal/sm4/gcm_ppc64x.s similarity index 100% rename from sm4/gcm_ppc64x.s rename to internal/sm4/gcm_ppc64x.s diff --git a/sm4/gcm_ppc64x_test.go b/internal/sm4/gcm_ppc64x_test.go similarity index 100% rename from sm4/gcm_ppc64x_test.go rename to internal/sm4/gcm_ppc64x_test.go diff --git a/sm4/gcm_sm4ni_arm64.s b/internal/sm4/gcm_sm4ni_arm64.s similarity index 100% rename from sm4/gcm_sm4ni_arm64.s rename to internal/sm4/gcm_sm4ni_arm64.s diff --git a/sm4/gen_arm64_ni.go b/internal/sm4/gen_arm64_ni.go similarity index 100% rename from sm4/gen_arm64_ni.go rename to internal/sm4/gen_arm64_ni.go diff --git a/sm4/modes.go b/internal/sm4/modes.go similarity index 100% rename from sm4/modes.go rename to internal/sm4/modes.go diff --git a/sm4/sm4_gcm_asm.go b/internal/sm4/sm4_gcm_asm.go similarity index 100% rename from sm4/sm4_gcm_asm.go rename to internal/sm4/sm4_gcm_asm.go diff --git a/sm4/sm4_xts.go b/internal/sm4/sm4_xts.go similarity index 100% rename from sm4/sm4_xts.go rename to internal/sm4/sm4_xts.go diff --git a/sm4/sm4ni_gcm_asm.go b/internal/sm4/sm4ni_gcm_asm.go similarity index 100% rename from sm4/sm4ni_gcm_asm.go rename to internal/sm4/sm4ni_gcm_asm.go diff --git a/sm4/sm4ni_macros_arm64.s b/internal/sm4/sm4ni_macros_arm64.s similarity index 100% rename from sm4/sm4ni_macros_arm64.s rename to internal/sm4/sm4ni_macros_arm64.s diff --git a/sm4/sm4ni_xts.go b/internal/sm4/sm4ni_xts.go similarity index 100% rename from sm4/sm4ni_xts.go rename to internal/sm4/sm4ni_xts.go diff --git a/sm4/xts_amd64.s b/internal/sm4/xts_amd64.s similarity index 100% rename from sm4/xts_amd64.s rename to internal/sm4/xts_amd64.s diff --git a/sm4/xts_arm64.s b/internal/sm4/xts_arm64.s similarity index 100% rename from sm4/xts_arm64.s rename to internal/sm4/xts_arm64.s diff --git a/sm4/xts_macros_arm64.s b/internal/sm4/xts_macros_arm64.s similarity index 100% rename from sm4/xts_macros_arm64.s rename to internal/sm4/xts_macros_arm64.s diff --git a/sm4/xts_sm4ni_arm64.s b/internal/sm4/xts_sm4ni_arm64.s similarity index 100% rename from sm4/xts_sm4ni_arm64.s rename to internal/sm4/xts_sm4ni_arm64.s diff --git a/sm4/sm4.go b/sm4/sm4.go new file mode 100644 index 0000000..945783f --- /dev/null +++ b/sm4/sm4.go @@ -0,0 +1,31 @@ +// Package sm4 implements ShangMi(SM) sm4 symmetric encryption algorithm. +package sm4 + +import ( + "crypto/cipher" + "strconv" + + "github.com/emmansun/gmsm/internal/sm4" +) + +// BlockSize the sm4 block size in bytes. +const BlockSize = 16 + +type KeySizeError int + +func (k KeySizeError) Error() string { + return "sm4: invalid key size " + strconv.Itoa(int(k)) +} + +// NewCipher creates and returns a new [cipher.Block] implementation. +// The key argument should be the SM4 key, must be 16 bytes long. +func NewCipher(key []byte) (cipher.Block, error) { + k := len(key) + switch k { + default: + return nil, KeySizeError(k) + case 16: + break + } + return sm4.NewCipher(key) +} diff --git a/sm4/sm4_test.go b/sm4/sm4_test.go new file mode 100644 index 0000000..9a78017 --- /dev/null +++ b/sm4/sm4_test.go @@ -0,0 +1,125 @@ +package sm4 + +import ( + "reflect" + "testing" + + "github.com/emmansun/gmsm/internal/cryptotest" +) + +type CryptTest struct { + key []byte + in []byte + out []byte +} + +var encryptTests = []CryptTest{ + { + // Appendix 1. + []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}, + []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}, + []byte{0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46}, + }, +} + +func Test_sample1(t *testing.T) { + src := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10} + expected := []byte{0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46} + c, err := NewCipher(src) + if err != nil { + t.Fatal(err) + } + dst := make([]byte, 16) + c.Encrypt(dst, src) + if !reflect.DeepEqual(dst, expected) { + t.Errorf("expected=%x, result=%x\n", expected, dst) + } + c.Decrypt(dst, expected) + if !reflect.DeepEqual(dst, src) { + t.Errorf("expected=%x, result=%x\n", src, dst) + } +} + +func Test_sample2(t *testing.T) { + src := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10} + expected := []byte{0x59, 0x52, 0x98, 0xc7, 0xc6, 0xfd, 0x27, 0x1f, 0x04, 0x02, 0xf8, 0x04, 0xc3, 0x3d, 0x3f, 0x66} + c, err := NewCipher(src) + if err != nil { + t.Fatal(err) + } + dst := make([]byte, 16) + copy(dst, src) + n := 1000000 + if testing.Short() { + n = 1000 + expected = []byte{215, 53, 233, 28, 197, 104, 156, 243, 18, 188, 193, 239, 183, 64, 232, 19} + } + for i := 0; i < n; i++ { + c.Encrypt(dst, dst) + } + if !reflect.DeepEqual(dst, expected) { + t.Errorf("expected=%x, result=%x\n", expected, dst) + } +} + +func TestEncryptDecryptPanic(t *testing.T) { + key := make([]byte, 16) + src := make([]byte, 15) + dst := make([]byte, 16) + c, err := NewCipher(key) + if err != nil { + t.Fatal(err) + } + shouldPanic(t, func() { c.Encrypt(dst, src) }) + shouldPanic(t, func() { c.Encrypt(src, dst) }) + shouldPanic(t, func() { c.Decrypt(dst, src) }) + shouldPanic(t, func() { c.Decrypt(src, dst) }) + + src = make([]byte, 32) + shouldPanic(t, func() { c.Encrypt(src, src[1:]) }) + shouldPanic(t, func() { c.Encrypt(src[1:], src) }) + shouldPanic(t, func() { c.Decrypt(src, src[1:]) }) + shouldPanic(t, func() { c.Decrypt(src[1:], src) }) +} + +func shouldPanic(t *testing.T, f func()) { + t.Helper() + defer func() { _ = recover() }() + f() + t.Errorf("should have panicked") +} + +// Test SM4 against the general cipher.Block interface tester +func TestSM4Block(t *testing.T) { + t.Run("SM4", func(t *testing.T) { + cryptotest.TestBlock(t, 16, NewCipher) + }) +} + +func BenchmarkEncrypt(b *testing.B) { + tt := encryptTests[0] + c, err := NewCipher(tt.key) + if err != nil { + b.Fatal("NewCipher:", err) + } + out := make([]byte, len(tt.in)) + b.SetBytes(int64(len(out))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Encrypt(out, tt.in) + } +} + +func BenchmarkDecrypt(b *testing.B) { + tt := encryptTests[0] + c, err := NewCipher(tt.key) + if err != nil { + b.Fatal("NewCipher:", err) + } + out := make([]byte, len(tt.out)) + b.SetBytes(int64(len(out))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Decrypt(out, tt.out) + } +}