|
@@ -0,0 +1,295 @@
|
|
|
|
+package encrypter
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "crypto/rand"
|
|
|
|
+ "crypto/rsa"
|
|
|
|
+ "crypto/sha256"
|
|
|
|
+ "crypto/x509"
|
|
|
|
+ "encoding/base64"
|
|
|
|
+ "fmt"
|
|
|
|
+ "reflect"
|
|
|
|
+ "strings"
|
|
|
|
+
|
|
|
|
+ msgpack "gopkg.in/vmihailenco/msgpack.v2"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+// PrivateKey type
|
|
|
|
+type PrivateKey rsa.PrivateKey
|
|
|
|
+
|
|
|
|
+// PublicKey type
|
|
|
|
+type PublicKey rsa.PublicKey
|
|
|
|
+
|
|
|
|
+const (
|
|
|
|
+ keySize = 2048
|
|
|
|
+ decryptBlockSize = 256
|
|
|
|
+ encryptBlockSize = 190
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+// NewPrivateKey func
|
|
|
|
+func NewPrivateKey() *PrivateKey {
|
|
|
|
+ pk, err := rsa.GenerateKey(rand.Reader, keySize)
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(fmt.Errorf("Error create rsa.PrivateKey %v", err))
|
|
|
|
+ }
|
|
|
|
+ return (*PrivateKey)(pk)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ParsePrivateKey func
|
|
|
|
+func ParsePrivateKey(raw []byte) *PrivateKey {
|
|
|
|
+ k, err := x509.ParsePKCS1PrivateKey(raw)
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(fmt.Errorf("Error parse privateKey %v", err))
|
|
|
|
+ }
|
|
|
|
+ return (*PrivateKey)(k)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ParsePrivateKeyString func
|
|
|
|
+func ParsePrivateKeyString(str string) (*PrivateKey, error) {
|
|
|
|
+ raw, err := base64.RawURLEncoding.DecodeString(str)
|
|
|
|
+ if err != nil {
|
|
|
|
+ slog.Debugf("Error key decode %v", err)
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ k, err := x509.ParsePKCS1PrivateKey(raw)
|
|
|
|
+ if err != nil {
|
|
|
|
+ slog.Debugf("Error parse key %v", err)
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ return (*PrivateKey)(k), nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ParsePublicKey func
|
|
|
|
+func ParsePublicKey(raw []byte) *PublicKey {
|
|
|
|
+ k, err := x509.ParsePKIXPublicKey(raw)
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(fmt.Errorf("Error parse privateKey %v", err))
|
|
|
|
+ }
|
|
|
|
+ if p, ok := k.(*rsa.PublicKey); ok {
|
|
|
|
+ return (*PublicKey)(p)
|
|
|
|
+ }
|
|
|
|
+ panic(fmt.Errorf("Invalid type %s", reflect.TypeOf(k).String()))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ParsePublicKeyString func
|
|
|
|
+func ParsePublicKeyString(str string) (*PublicKey, error) {
|
|
|
|
+ raw, err := base64.RawURLEncoding.DecodeString(str)
|
|
|
|
+ if err != nil {
|
|
|
|
+ slog.Debugf("Error key decode %v", err)
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ k, err := x509.ParsePKIXPublicKey(raw)
|
|
|
|
+ if err != nil {
|
|
|
|
+ slog.Debugf("Error parse key %v", err)
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ if p, ok := k.(*rsa.PublicKey); ok {
|
|
|
|
+ return (*PublicKey)(p), nil
|
|
|
|
+ }
|
|
|
|
+ err = fmt.Errorf("Invalid type %s", reflect.TypeOf(k).String())
|
|
|
|
+ slog.Debugf("Error %v", err)
|
|
|
|
+ return nil, err
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+var _ msgpack.CustomEncoder = (*PrivateKey)(nil)
|
|
|
|
+var _ msgpack.CustomDecoder = (*PrivateKey)(nil)
|
|
|
|
+
|
|
|
|
+// EncodeMsgpack func
|
|
|
|
+func (s *PrivateKey) EncodeMsgpack(enc *msgpack.Encoder) error {
|
|
|
|
+ return enc.Encode(s.Raw())
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// DecodeMsgpack func
|
|
|
|
+func (s *PrivateKey) DecodeMsgpack(dec *msgpack.Decoder) error {
|
|
|
|
+ var raw []byte
|
|
|
|
+ err := dec.Decode(&raw)
|
|
|
|
+ if err != nil {
|
|
|
|
+ slog.Warnf("PrivateKey.DecodeMsgpack decode str %v", err)
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ sk, err := x509.ParsePKCS1PrivateKey(raw)
|
|
|
|
+ if err != nil {
|
|
|
|
+ slog.Warnf("PrivateKey.DecodeMsgpack parse pkcs key %v", err)
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ s.PublicKey = sk.PublicKey
|
|
|
|
+ s.D = sk.D
|
|
|
|
+ s.Primes = sk.Primes
|
|
|
|
+ s.Precomputed = sk.Precomputed
|
|
|
|
+ return nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Decrypt func
|
|
|
|
+func (s *PrivateKey) Decrypt(crypt []byte) (plain []byte, err error) {
|
|
|
|
+ for {
|
|
|
|
+ if len(crypt) <= decryptBlockSize {
|
|
|
|
+ bb, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, (*rsa.PrivateKey)(s), crypt, nil)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ return append(plain, bb...), err
|
|
|
|
+ }
|
|
|
|
+ bb, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, (*rsa.PrivateKey)(s), crypt[:decryptBlockSize], nil)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ plain = append(plain, bb...)
|
|
|
|
+ crypt = crypt[decryptBlockSize:]
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// MarshalJSON func
|
|
|
|
+func (s *PrivateKey) MarshalJSON() ([]byte, error) {
|
|
|
|
+ return []byte("\"" + base64.RawURLEncoding.EncodeToString(s.Raw()) + "\""), nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// UnmarshalJSON func
|
|
|
|
+func (s *PrivateKey) UnmarshalJSON(b []byte) error {
|
|
|
|
+ if b[0] != '"' && b[len(b)-1] != '"' {
|
|
|
|
+ return fmt.Errorf("Invalid key")
|
|
|
|
+ }
|
|
|
|
+ skey := strings.Replace(string(b[1:len(b)-1]), "\\n", "", -1)
|
|
|
|
+ bb, err := base64.RawURLEncoding.DecodeString(skey)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("Error parse privateKey %v [%s]", err, skey)
|
|
|
|
+ }
|
|
|
|
+ k, err := x509.ParsePKCS1PrivateKey(bb)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("Error parse privateKey %v [%s]", err, string(bb))
|
|
|
|
+ }
|
|
|
|
+ s.D = k.D
|
|
|
|
+ s.E = k.E
|
|
|
|
+ s.N = k.N
|
|
|
|
+ s.Primes = k.Primes
|
|
|
|
+ return ((*rsa.PrivateKey)(s)).Validate()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (s *PrivateKey) String() string {
|
|
|
|
+ bb := x509.MarshalPKCS1PrivateKey((*rsa.PrivateKey)(s))
|
|
|
|
+ return base64.RawURLEncoding.EncodeToString(bb)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Public func
|
|
|
|
+func (s *PrivateKey) Public() *PublicKey {
|
|
|
|
+ rp := (*rsa.PrivateKey)(s).PublicKey
|
|
|
|
+ return (*PublicKey)(&rp)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// EncryptKey func
|
|
|
|
+func (s *PrivateKey) EncryptKey(key *PublicKey) EncryptedPrivateKey {
|
|
|
|
+ bb, err := key.Encrypt(s.Raw())
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+ return (EncryptedPrivateKey)(bb)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Raw func
|
|
|
|
+func (s *PrivateKey) Raw() []byte {
|
|
|
|
+ return x509.MarshalPKCS1PrivateKey((*rsa.PrivateKey)(s))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Equal func
|
|
|
|
+func (s *PrivateKey) Equal(key *PrivateKey) bool {
|
|
|
|
+ if key == nil {
|
|
|
|
+ return s == nil
|
|
|
|
+ }
|
|
|
|
+ k1 := (*rsa.PrivateKey)(s)
|
|
|
|
+ k2 := (*rsa.PrivateKey)(key)
|
|
|
|
+ return k1.E == k2.E && k1.D.Cmp(k2.D) == 0 && k1.N.Cmp(k2.N) == 0
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+var _ msgpack.CustomEncoder = (*PublicKey)(nil)
|
|
|
|
+var _ msgpack.CustomDecoder = (*PublicKey)(nil)
|
|
|
|
+
|
|
|
|
+// EncodeMsgpack func
|
|
|
|
+func (s *PublicKey) EncodeMsgpack(enc *msgpack.Encoder) error {
|
|
|
|
+ return enc.Encode(s.Raw())
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// DecodeMsgpack func
|
|
|
|
+func (s *PublicKey) DecodeMsgpack(dec *msgpack.Decoder) error {
|
|
|
|
+ var raw []byte
|
|
|
|
+ err := dec.Decode(&raw)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ sko, err := x509.ParsePKIXPublicKey(raw)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ if sk, ok := sko.(*rsa.PublicKey); ok {
|
|
|
|
+ s.N = sk.N
|
|
|
|
+ s.E = sk.E
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+ return fmt.Errorf("Unkown type %s", reflect.TypeOf(sko))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Encrypt func
|
|
|
|
+func (s *PublicKey) Encrypt(data []byte) (crypt []byte, err error) {
|
|
|
|
+ for {
|
|
|
|
+ if len(data) <= encryptBlockSize {
|
|
|
|
+ bb, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, (*rsa.PublicKey)(s), data, nil)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ return append(crypt, bb...), err
|
|
|
|
+ }
|
|
|
|
+ bb, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, (*rsa.PublicKey)(s), data[:encryptBlockSize], nil)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ crypt = append(crypt, bb...)
|
|
|
|
+ data = data[encryptBlockSize:]
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// MarshalJSON func
|
|
|
|
+func (s *PublicKey) MarshalJSON() ([]byte, error) {
|
|
|
|
+ return []byte("\"" + base64.RawURLEncoding.EncodeToString(s.Raw()) + "\""), nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// UnmarshalJSON func
|
|
|
|
+func (s *PublicKey) UnmarshalJSON(b []byte) error {
|
|
|
|
+ if b[0] != '"' && b[len(b)-1] != '"' {
|
|
|
|
+ return fmt.Errorf("Invalid key")
|
|
|
|
+ }
|
|
|
|
+ skey := strings.Replace(string(b[1:len(b)-1]), "\\n", "", -1)
|
|
|
|
+ bb, err := base64.RawURLEncoding.DecodeString(skey)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("Error parse privateKey %v [%s]", err, skey)
|
|
|
|
+ }
|
|
|
|
+ k, err := x509.ParsePKIXPublicKey(bb)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("Error parse privateKey %v [%s]", err, string(bb))
|
|
|
|
+ }
|
|
|
|
+ if pk, ok := k.(*rsa.PublicKey); ok {
|
|
|
|
+ s.E = pk.E
|
|
|
|
+ s.N = pk.N
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+ return fmt.Errorf("Invalid type %s", reflect.TypeOf(k))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (s *PublicKey) String() string {
|
|
|
|
+ return base64.RawURLEncoding.EncodeToString(s.Raw())
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Raw func
|
|
|
|
+func (s *PublicKey) Raw() []byte {
|
|
|
|
+ bb, err := x509.MarshalPKIXPublicKey((*rsa.PublicKey)(s))
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+ return bb
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Equal func
|
|
|
|
+func (s *PublicKey) Equal(key *PublicKey) bool {
|
|
|
|
+ if key == nil {
|
|
|
|
+ return s == nil
|
|
|
|
+ }
|
|
|
|
+ k1 := (*rsa.PublicKey)(s)
|
|
|
|
+ k2 := (*rsa.PublicKey)(key)
|
|
|
|
+ return k1.E == k2.E && k1.N.Cmp(k2.N) == 0
|
|
|
|
+}
|