]> 127.0.0.1 Git - part/.git/commitdiff
1 (#48) v0.28.20250424194925
authorqydysky <qydysky@foxmail.com>
Thu, 24 Apr 2025 19:49:18 +0000 (03:49 +0800)
committerGitHub <noreply@github.com>
Thu, 24 Apr 2025 19:49:18 +0000 (03:49 +0800)
* 1

* 1

.github/workflows/test1.yml
crypto/EasyCrypt.go
crypto/asymmetric/mlkem.go [new file with mode: 0644]
crypto/asymmetric/mlkem_test.go [new file with mode: 0644]
crypto/asymmetric/util.go [new file with mode: 0644]
crypto/asymmetric/x25519.go [new file with mode: 0644]
crypto/asymmetric/x25519_test.go [new file with mode: 0644]
crypto/crypto.go [new file with mode: 0644]
crypto/symmetric/chacha20poly1305.go [new file with mode: 0644]

index e68d54901f5c7169e025307e9c0dddc54f7404c4..1922382243cbfb04e5cef2ac20fc95ae3078c7dc 100644 (file)
@@ -41,7 +41,7 @@ jobs:
         go test -count 1 -timeout 10s -v -race github.com/qydysky/part/slice
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/bools
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/errors
-        go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto
+        go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto/...
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/flag -sss=ss -i32=32 -f34=34 -btrue=true -d1m=1m
 
   w-test:
@@ -80,7 +80,7 @@ jobs:
         go test -count 1 -timeout 10s -v -race github.com/qydysky/part/slice
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/bools
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/errors
-        go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto
+        go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto/...
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/flag -sss=ss -i32=32 -f34=34 -btrue=true -d1m=1m
 
   u-test:
@@ -119,5 +119,5 @@ jobs:
         go test -count 1 -timeout 10s -v -race github.com/qydysky/part/slice
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/bools
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/errors
-        go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto
+        go test -count 1 -timeout 5s -v -race github.com/qydysky/part/crypto/...
         go test -count 1 -timeout 5s -v -race github.com/qydysky/part/flag -sss=ss -i32=32 -f34=34 -btrue=true -d1m=1m
index bc3694e8e140163665cd8d1cc639aace6f99509a..b335dfed30dc7009bae0d470bc1ec8aa58c67710 100644 (file)
@@ -16,6 +16,7 @@ var (
        ErrPemType = errors.New(`ErrPemType`)
 )
 
+// Deprecated: 使用 asymmetric 包
 func NewKey() (pri, pub []byte, e error) {
        if p1, e := ecdh.X25519().GenerateKey(rand.Reader); e != nil {
                return nil, nil, e
@@ -30,6 +31,7 @@ func NewKey() (pri, pub []byte, e error) {
        }
 }
 
+// Deprecated: 使用 asymmetric 包
 func Encrypt(msg, pubKey []byte) (b []byte, e error) {
        c := ecdh.X25519()
        var (
@@ -70,6 +72,7 @@ func Encrypt(msg, pubKey []byte) (b []byte, e error) {
        return
 }
 
+// Deprecated: 使用 asymmetric 包
 func Decrypt(b, priKey []byte) (msg []byte, e error) {
        var (
                q1     *ecdh.PublicKey
diff --git a/crypto/asymmetric/mlkem.go b/crypto/asymmetric/mlkem.go
new file mode 100644 (file)
index 0000000..ac133a2
--- /dev/null
@@ -0,0 +1,73 @@
+package part
+
+import (
+       "crypto/mlkem"
+       "encoding/pem"
+
+       pc "github.com/qydysky/part/crypto"
+)
+
+type Mlkem struct{}
+
+var MlkemF pc.Asymmetric = Mlkem{}
+
+func (t Mlkem) GetType() string {
+       return `MLKEM`
+}
+func (t Mlkem) CheckType(b *pem.Block) (ok bool, isPriKey bool) {
+       isPriKey = b.Type == t.GetType()+PriKeySuf
+       if !isPriKey {
+               ok = b.Type == t.GetType()+PubKeySuf
+       } else {
+               ok = true
+       }
+       return
+}
+
+func (t Mlkem) Decrypt(priKey *pem.Block) (dec pc.AsymmetricDec, e error) {
+       if priKey.Type != t.GetType()+PriKeySuf {
+               return nil, ErrType
+       } else if d, err := mlkem.NewDecapsulationKey1024(priKey.Bytes); err != nil {
+               return nil, err
+       } else {
+               return func(sym pc.Symmetric, b, exchangeTxt []byte) (msg []byte, e error) {
+                       if sharedKey, err := d.Decapsulate(exchangeTxt); err != nil {
+                               return nil, err
+                       } else {
+                               return sym.Decrypt(b, sharedKey)
+                       }
+               }, nil
+       }
+}
+
+func (t Mlkem) Encrypt(pubKey *pem.Block) (enc pc.AsymmetricEnc, e error) {
+       if pubKey.Type != t.GetType()+PubKeySuf {
+               return nil, ErrType
+       } else if d, err := mlkem.NewEncapsulationKey1024(pubKey.Bytes); err != nil {
+               return nil, err
+       } else {
+               return func(sym pc.Symmetric, msg []byte) (b, exchangeTxt []byte, e error) {
+                       sharedKey, ciphertext := d.Encapsulate()
+                       b, e = sym.Encrypt(msg, sharedKey)
+                       if e != nil {
+                               return nil, nil, e
+                       }
+                       return b, ciphertext, nil
+               }, nil
+       }
+}
+
+func (t Mlkem) NewKey() (pri, pub *pem.Block, e error) {
+       var d *mlkem.DecapsulationKey1024
+       d, e = mlkem.GenerateKey1024()
+       if e != nil {
+               return
+       }
+       return &pem.Block{
+                       Type:  t.GetType() + PriKeySuf,
+                       Bytes: d.Bytes(),
+               }, &pem.Block{
+                       Type:  t.GetType() + PubKeySuf,
+                       Bytes: d.EncapsulationKey().Bytes(),
+               }, nil
+}
diff --git a/crypto/asymmetric/mlkem_test.go b/crypto/asymmetric/mlkem_test.go
new file mode 100644 (file)
index 0000000..11cadad
--- /dev/null
@@ -0,0 +1,39 @@
+package part
+
+import (
+       "bytes"
+       "crypto/rand"
+       "testing"
+
+       pcs "github.com/qydysky/part/crypto/symmetric"
+)
+
+func Test_Mlkem(t *testing.T) {
+       var buf = make([]byte, 100)
+       if n, e := rand.Read(buf); e != nil {
+               t.Fatal(e)
+       } else {
+               buf = buf[:n]
+       }
+
+       m := MlkemF
+       sym := pcs.Chacha20poly1305F
+       if pri, pub, e := MlkemF.NewKey(); e != nil {
+               t.Fatal(e)
+       } else {
+               if enc, e := m.Encrypt(pub); e != nil {
+                       t.Fatal(e)
+               } else if b, ex, e := enc(sym, buf); e != nil {
+                       t.Fatal()
+               } else {
+                       b, ex = Unpack(Pack(b, ex))
+                       if dec, e := m.Decrypt(pri); e != nil {
+                               t.Fatal(e)
+                       } else if msg, e := dec(sym, b, ex); e != nil {
+                               t.Fatal(e)
+                       } else if !bytes.Equal(msg, buf) {
+                               t.Fatal()
+                       }
+               }
+       }
+}
diff --git a/crypto/asymmetric/util.go b/crypto/asymmetric/util.go
new file mode 100644 (file)
index 0000000..7452ec0
--- /dev/null
@@ -0,0 +1,51 @@
+package part
+
+import (
+       "encoding/pem"
+       "errors"
+
+       pc "github.com/qydysky/part/crypto"
+)
+
+var (
+       PriKeySuf string = ` PRIVATE KEY`
+       PubKeySuf string = ` PUBLIC KEY`
+       ErrType   error  = errors.New(`ErrType`)
+)
+
+func ChoseAsymmetricByPem(b *pem.Block) pc.Asymmetric {
+       if ok, _ := X25519F.CheckType(b); ok {
+               return X25519F
+       } else if ok, _ := MlkemF.CheckType(b); ok {
+               return MlkemF
+       } else {
+               return nil
+       }
+}
+
+func Pack(b, exchangeTxt []byte) (a []byte) {
+       buf := make([]byte, 4+len(exchangeTxt)+len(b))
+       n := copy(buf, itob32(int32(len(exchangeTxt))))
+       n += copy(buf[n:], exchangeTxt)
+       copy(buf[n:], b)
+       return buf
+}
+
+func Unpack(a []byte) (b, exchangeTxt []byte) {
+       exL := btoi32(a[:4])
+       return a[4+exL:], a[4 : 4+exL]
+}
+
+func itob32(v int32) []byte {
+       //binary.BigEndian.PutUint32
+       b := make([]byte, 4)
+       b[0] = byte(v >> 24)
+       b[1] = byte(v >> 16)
+       b[2] = byte(v >> 8)
+       b[3] = byte(v)
+       return b
+}
+
+func btoi32(bu []byte) uint32 {
+       return uint32(bu[3]) | uint32(bu[2])<<8 | uint32(bu[1])<<16 | uint32(bu[0])<<24
+}
diff --git a/crypto/asymmetric/x25519.go b/crypto/asymmetric/x25519.go
new file mode 100644 (file)
index 0000000..c55ff21
--- /dev/null
@@ -0,0 +1,91 @@
+package part
+
+import (
+       "crypto/ecdh"
+       "crypto/rand"
+       "encoding/pem"
+
+       pc "github.com/qydysky/part/crypto"
+)
+
+var X25519F pc.Asymmetric = X25519{}
+
+type X25519 struct{}
+
+// CheckType implements part.Asymmetric.
+func (t X25519) CheckType(b *pem.Block) (ok bool, isPriKey bool) {
+       isPriKey = b.Type == t.GetType()+PriKeySuf
+       if !isPriKey {
+               ok = b.Type == t.GetType()+PubKeySuf
+       } else {
+               ok = true
+       }
+       return
+}
+
+func (t X25519) GetType() string {
+       return `ECDH` // 为了保证向后兼容,此处为ECDH
+}
+
+func (t X25519) Decrypt(priKey *pem.Block) (dec pc.AsymmetricDec, e error) {
+       if priKey.Type != t.GetType()+PriKeySuf {
+               return nil, ErrType
+       }
+
+       var p2 *ecdh.PrivateKey
+       if p2, e = ecdh.X25519().NewPrivateKey(priKey.Bytes); e != nil {
+               return
+       }
+
+       return func(sym pc.Symmetric, b, exchangeTxt []byte) (msg []byte, e error) {
+               if q1, err := ecdh.X25519().NewPublicKey(exchangeTxt); err != nil {
+                       return nil, err
+               } else if key, err := p2.ECDH(q1); err != nil {
+                       return nil, err
+               } else {
+                       return sym.Decrypt(b, key)
+               }
+       }, nil
+}
+
+func (t X25519) Encrypt(pubKey *pem.Block) (enc pc.AsymmetricEnc, e error) {
+       if pubKey.Type != t.GetType()+PubKeySuf {
+               return nil, ErrType
+       }
+
+       var (
+               p1  *ecdh.PrivateKey
+               q1  *ecdh.PublicKey
+               q2  *ecdh.PublicKey
+               key []byte
+       )
+       if p1, e = ecdh.X25519().GenerateKey(rand.Reader); e != nil {
+               return
+       }
+       q1 = p1.PublicKey()
+       if q2, e = ecdh.X25519().NewPublicKey(pubKey.Bytes); e != nil {
+               return
+       } else if key, e = p1.ECDH(q2); e != nil {
+               return
+       } else {
+               return func(sym pc.Symmetric, msg []byte) (b []byte, exchangeTxt []byte, e error) {
+                       b, e = sym.Encrypt(msg, key)
+                       exchangeTxt = q1.Bytes()
+                       return
+               }, nil
+       }
+}
+
+func (t X25519) NewKey() (pri, pub *pem.Block, e error) {
+       if d, e := ecdh.X25519().GenerateKey(rand.Reader); e != nil {
+               return nil, nil, e
+       } else {
+               return &pem.Block{
+                               Type:  t.GetType() + PriKeySuf,
+                               Bytes: d.Bytes(),
+                       }, &pem.Block{
+                               Type:  t.GetType() + PubKeySuf,
+                               Bytes: d.PublicKey().Bytes(),
+                       }, nil
+       }
+}
diff --git a/crypto/asymmetric/x25519_test.go b/crypto/asymmetric/x25519_test.go
new file mode 100644 (file)
index 0000000..5ac19a3
--- /dev/null
@@ -0,0 +1,39 @@
+package part
+
+import (
+       "bytes"
+       "crypto/rand"
+       "testing"
+
+       pcs "github.com/qydysky/part/crypto/symmetric"
+)
+
+func Test_X25519(t *testing.T) {
+       var buf = make([]byte, 100)
+       if n, e := rand.Read(buf); e != nil {
+               t.Fatal(e)
+       } else {
+               buf = buf[:n]
+       }
+
+       m := X25519F
+       sym := pcs.Chacha20poly1305F
+       if pri, pub, e := m.NewKey(); e != nil {
+               t.Fatal(e)
+       } else {
+               if enc, e := m.Encrypt(pub); e != nil {
+                       t.Fatal(e)
+               } else if b, ex, e := enc(sym, buf); e != nil {
+                       t.Fatal()
+               } else {
+                       b, ex = Unpack(Pack(b, ex))
+                       if dec, e := m.Decrypt(pri); e != nil {
+                               t.Fatal(e)
+                       } else if msg, e := dec(sym, b, ex); e != nil {
+                               t.Fatal(e)
+                       } else if !bytes.Equal(msg, buf) {
+                               t.Fatal()
+                       }
+               }
+       }
+}
diff --git a/crypto/crypto.go b/crypto/crypto.go
new file mode 100644 (file)
index 0000000..b40daca
--- /dev/null
@@ -0,0 +1,25 @@
+package part
+
+import (
+       "encoding/pem"
+)
+
+type Asymmetric interface {
+       GetType() string
+       CheckType(b *pem.Block) (ok bool, isPriKey bool)
+       NewKey() (pri, pub *pem.Block, e error)
+       Encrypt(pubKey *pem.Block) (enc AsymmetricEnc, e error)
+       Decrypt(priKey *pem.Block) (dec AsymmetricDec, e error)
+}
+
+// func(sym Symmetric, msg []byte) (b, exchangeTxt []byte, e error)
+type AsymmetricEnc func(sym Symmetric, msg []byte) (b, exchangeTxt []byte, e error)
+
+// func(sym Symmetric, b, exchangeTxt []byte) (msg []byte, e error)
+type AsymmetricDec func(sym Symmetric, b, exchangeTxt []byte) (msg []byte, e error)
+
+type Symmetric interface {
+       GetType() string
+       Encrypt(msg, key []byte) (b []byte, e error)
+       Decrypt(b, key []byte) (msg []byte, e error)
+}
diff --git a/crypto/symmetric/chacha20poly1305.go b/crypto/symmetric/chacha20poly1305.go
new file mode 100644 (file)
index 0000000..804c8e6
--- /dev/null
@@ -0,0 +1,42 @@
+package part
+
+import (
+       "crypto/rand"
+
+       pcrypto "github.com/qydysky/part/crypto"
+       "golang.org/x/crypto/chacha20poly1305"
+)
+
+type Chacha20poly1305 struct{}
+
+var Chacha20poly1305F pcrypto.Symmetric = Chacha20poly1305{}
+
+// GetType implements part.Symmetric.
+func (c Chacha20poly1305) GetType() string {
+       return `CHACHA20POLY1305`
+}
+
+// Decrypt implements part.Symmetric.
+func (c Chacha20poly1305) Decrypt(b []byte, key []byte) (msg []byte, e error) {
+       if aead, err := chacha20poly1305.NewX(key); err != nil {
+               return nil, err
+       } else {
+               nonce, ciphertext := b[:aead.NonceSize()], b[aead.NonceSize():]
+               return aead.Open(nil, nonce, ciphertext, nil)
+       }
+}
+
+// Encrypt implements part.Symmetric.
+func (c Chacha20poly1305) Encrypt(msg []byte, key []byte) (b []byte, e error) {
+       if aead, err := chacha20poly1305.NewX(key); err != nil {
+               return nil, err
+       } else {
+               nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(msg)+aead.Overhead())
+               if n, err := rand.Read(nonce); err != nil {
+                       return nil, err
+               } else {
+                       nonce = nonce[:n]
+                       return aead.Seal(nonce, nonce, msg, nil), nil
+               }
+       }
+}