From 0a4c0a944bebb5f794b102ab5f2abc1cbeaf2520 Mon Sep 17 00:00:00 2001 From: starainrt Date: Sun, 10 Mar 2024 13:04:26 +0800 Subject: [PATCH] update starcrypto --- aes.go | 122 ++++++++ basehash.go => base648591.go | 0 crc32a.go => crc32.go | 18 +- crypt_test.go | 11 +- crypto.go | 588 +---------------------------------- ecdsa.go | 117 +++++++ file.go | 246 +++++++++++++++ go.mod | 2 +- go.sum | 48 ++- hash.go | 204 ++++++++++++ hmac.go | 87 ++++++ md5.go | 27 ++ ripe.go | 15 + rsa.go | 43 ++- sha.go | 62 ++++ sm3.go | 15 + sm3/sm3.go | 259 +++++++++++++++ sm3/sm3_test.go | 64 ++++ 18 files changed, 1323 insertions(+), 605 deletions(-) create mode 100644 aes.go rename basehash.go => base648591.go (100%) rename crc32a.go => crc32.go (93%) create mode 100644 ecdsa.go create mode 100644 file.go create mode 100644 hash.go create mode 100644 hmac.go create mode 100644 md5.go create mode 100644 ripe.go create mode 100644 sha.go create mode 100644 sm3.go create mode 100644 sm3/sm3.go create mode 100644 sm3/sm3_test.go diff --git a/aes.go b/aes.go new file mode 100644 index 0000000..4dab0d0 --- /dev/null +++ b/aes.go @@ -0,0 +1,122 @@ +package starcrypto + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "errors" + "io" +) + +const ( + PKCS5PADDING = "PKCS5" +) + +func CustomEncryptAesCFB(origData []byte, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + encrypted := make([]byte, aes.BlockSize+len(origData)) + iv := encrypted[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(encrypted[aes.BlockSize:], origData) + return encrypted, nil +} + +func CustomDecryptAesCFB(encrypted []byte, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + if len(encrypted) < aes.BlockSize { + return nil, errors.New("ciphertext too short") + } + iv := encrypted[:aes.BlockSize] + encrypted = encrypted[aes.BlockSize:] + + stream := cipher.NewCFBDecrypter(block, iv) + stream.XORKeyStream(encrypted, encrypted) + return encrypted, nil +} + +func CustomEncryptAesCFBNoBlock(origData []byte, key []byte, iv []byte) ([]byte, error) { + if len(iv) != 16 { + return nil, errors.New("iv length must be 16") + } + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + encrypted := make([]byte, len(origData)) + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(encrypted, origData) + return encrypted, err +} + +func CustomDecryptAesCFBNoBlock(encrypted []byte, key []byte, iv []byte) ([]byte, error) { + if len(iv) != 16 { + return nil, errors.New("iv length must be 16") + } + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + stream := cipher.NewCFBDecrypter(block, iv) + stream.XORKeyStream(encrypted, encrypted) + return encrypted, err +} + +func EncryptAesCBC(data, key []byte, iv []byte, paddingType string) ([]byte, error) { + var content []byte + aesBlockEncrypter, err := aes.NewCipher(key) + switch paddingType { + case PKCS5PADDING: + content = PKCS5Padding(data, aesBlockEncrypter.BlockSize()) + default: + return nil, errors.New("padding type not supported") + } + encrypted := make([]byte, len(content)) + if err != nil { + return nil, err + } + aesEncrypter := cipher.NewCBCEncrypter(aesBlockEncrypter, iv) + aesEncrypter.CryptBlocks(encrypted, content) + return encrypted, nil +} + +func PKCS5Padding(cipherText []byte, blockSize int) []byte { + padding := blockSize - len(cipherText)%blockSize + padText := bytes.Repeat([]byte{byte(padding)}, padding) + return append(cipherText, padText...) +} + +func PKCS5Trimming(encrypt []byte) []byte { + padding := encrypt[len(encrypt)-1] + if len(encrypt)-int(padding) < 0 { + return nil + } + return encrypt[:len(encrypt)-int(padding)] +} + +func DecryptAesCBC(src, key []byte, iv []byte, paddingType string) (data []byte, err error) { + decrypted := make([]byte, len(src)) + var aesBlockDecrypter cipher.Block + aesBlockDecrypter, err = aes.NewCipher(key) + if err != nil { + println(err.Error()) + return nil, err + } + aesDecrypter := cipher.NewCBCDecrypter(aesBlockDecrypter, iv) + aesDecrypter.CryptBlocks(decrypted, src) + switch paddingType { + case PKCS5PADDING: + return PKCS5Trimming(decrypted), nil + default: + return nil, errors.New("padding type not supported") + } +} diff --git a/basehash.go b/base648591.go similarity index 100% rename from basehash.go rename to base648591.go diff --git a/crc32a.go b/crc32.go similarity index 93% rename from crc32a.go rename to crc32.go index 305a5d9..7aac14e 100644 --- a/crc32a.go +++ b/crc32.go @@ -3,24 +3,38 @@ package starcrypto import ( "encoding/binary" "encoding/hex" + "hash/crc32" ) // CheckCRC32A calculates CRC32A (ITU I.363.5 algorithm, popularized by BZIP2) checksum. // This function will produce the same results as following PHP code: -// hexdec(hash('crc32', $data)) +// +// hexdec(hash('crc32', $data)) func CheckCRC32A(data []byte) uint32 { b := digest(data) return binary.BigEndian.Uint32(b) } +func Crc32Str(bstr []byte) string { + return String(Crc32(bstr)) +} + +// CRC32 输出CRC32校验值 +func Crc32(bstr []byte) []byte { + crcsum := crc32.NewIEEE() + crcsum.Write(bstr) + return crcsum.Sum(nil) +} + func Crc32A(data []byte) []byte { return digest(data) } // Crc32AStr is a convenience function that outputs CRC32A (ITU I.363.5 algorithm, popularized by BZIP2) checksum as a hex string. // This function will produce the same results as following PHP code: -// hash('crc32', $data) +// +// hash('crc32', $data) func Crc32AStr(data []byte) string { b := digest(data) diff --git a/crypt_test.go b/crypt_test.go index 1c360b0..a19e19d 100644 --- a/crypt_test.go +++ b/crypt_test.go @@ -6,7 +6,7 @@ import ( ) func TestRsaCrypt(t *testing.T) { - privKey, pubKey, err := GenerateKey(2048) + privKey, pubKey, err := GenerateRsaKey(2048) if err != nil { panic(err) } @@ -23,3 +23,12 @@ func TestRsaCrypt(t *testing.T) { t.Fail() } } + +func TestHmacSHA224(t *testing.T) { + key := []byte("hello world") + data := []byte("hello world") + code := HmacSHA224Str(key, data) + if "1414427f4b2889c3e86e637162c1add2bb888d1fc6c405d05fa5b66b" != code { + t.Fail() + } +} diff --git a/crypto.go b/crypto.go index 7fb93c8..1c8e69e 100644 --- a/crypto.go +++ b/crypto.go @@ -1,502 +1,28 @@ package starcrypto import ( - "bufio" - "crypto/aes" - "crypto/cipher" - "crypto/md5" "crypto/rand" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" "encoding/binary" "encoding/hex" - "errors" - "fmt" - "hash" - "hash/crc32" "io" - "io/ioutil" - rands "math/rand" "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "time" ) func String(bstr []byte) string { return hex.EncodeToString(bstr) } -// MD5 输出MD5校验值 -func Md5(bstr []byte) []byte { - md5sum := md5.New() - md5sum.Write(bstr) - return md5sum.Sum(nil) -} - -func Md5Str(bstr []byte) string { - return String(Md5(bstr)) -} - -// CRC32 输出CRC32校验值 -func Crc32(bstr []byte) []byte { - crcsum := crc32.NewIEEE() - crcsum.Write(bstr) - return crcsum.Sum(nil) -} - -func Crc32Str(bstr []byte) string { - return String(Crc32(bstr)) -} - -// SHA512 输出SHA512校验值 -func Sha512(bstr []byte) []byte { - shasum := sha512.New() - shasum.Write(bstr) - return shasum.Sum(nil) -} - -func Sha512Str(bstr []byte) string { - return String(Sha512(bstr)) -} - -// SHA384 输出SHA384校验值 -func Sha384(bstr []byte) []byte { - shasum := sha512.New384() - shasum.Write(bstr) - return shasum.Sum(nil) -} - -func Sha384Str(bstr []byte) string { - return String(Sha384(bstr)) -} - -// SHA256 输出SHA256校验值 -func Sha256(bstr []byte) []byte { - shasum := sha256.New() - shasum.Write(bstr) - return shasum.Sum(nil) -} - -func Sha256Str(bstr []byte) string { - return String(Sha256(bstr)) -} - -// SHA224 输出SHA224校验值 -func Sha224(bstr []byte) []byte { - shasum := sha256.New224() - shasum.Write(bstr) - return shasum.Sum(nil) -} - -func Sha224Str(bstr []byte) string { - return String(Sha224(bstr)) -} - -// SHA1 输出SHA1校验值 -func Sha1(bstr []byte) []byte { - shasum := sha1.New() - shasum.Write(bstr) - return shasum.Sum(nil) -} - -func Sha1Str(bstr []byte) string { - return String(Sha512(bstr)) -} - -// SumAll 可以对同一数据进行多种校验 -func SumAll(data []byte, method []string) (map[string][]byte, error) { - result := make(map[string][]byte) - methods := make(map[string]hash.Hash) - var iscrc bool - if len(method) == 0 { - method = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32", "md5"} - } - sum512 := sha512.New() - sum384 := sha512.New384() - sum256 := sha256.New() - sum224 := sha256.New224() - sum1 := sha1.New() - crcsum := crc32.NewIEEE() - md5sum := md5.New() - for _, v := range method { - switch v { - case "md5": - methods["md5"] = md5sum - case "crc32": - iscrc = true - case "sha1": - methods["sha1"] = sum1 - case "sha224": - methods["sha224"] = sum224 - case "sha256": - methods["sha256"] = sum256 - case "sha384": - methods["sha384"] = sum384 - case "sha512": - methods["sha512"] = sum512 - } - } - for _, v := range methods { - v.Write(data) - } - if iscrc { - crcsum.Write(data) - } - - for k, v := range methods { - result[k] = v.Sum(nil) - } - if iscrc { - result["crc32"] = crcsum.Sum(nil) - } - return result, nil -} - -// FileSum 输出文件内容校验值,method为单个校验方法,小写 -//例:FileSum("./test.txt","md5",shell(pect float64){fmt.Sprintf("已完成 %f\r",pect)}) -func FileSum(filepath, method string, shell func(float64)) (string, error) { - var sum hash.Hash - var sum32 hash.Hash32 - var issum32 bool - var result string - fp, err := os.Open(filepath) - if err != nil { - return "", err - } - switch method { - case "sha512": - sum = sha512.New() - case "sha384": - sum = sha512.New384() - case "sha256": - sum = sha256.New() - case "sha224": - sum = sha256.New224() - case "sha1": - sum = sha1.New() - case "crc32": - sum32 = crc32.NewIEEE() - issum32 = true - case "md5": - sum = md5.New() - default: - return "", errors.New("Cannot Recognize The Method:" + method) - } - writer := 0 - stat, _ := os.Stat(filepath) - filebig := float64(stat.Size()) - if !issum32 { - // if _, err := io.Copy(sum, fp); err != nil { - for { - buf := make([]byte, 1048574) - n, err := fp.Read(buf) - if err != nil { - if err == io.EOF { - break - } - return result, err - } - writer += n - pect := (float64(writer) / filebig) * 100 - go shell(pect) - sum.Write(buf[0:n]) - } - result = hex.EncodeToString(sum.Sum(nil)) - } else { - for { - buf := make([]byte, 1048574) - n, err := fp.Read(buf) - if err != nil { - if err == io.EOF { - break - } - return result, err - } - writer += n - pect := (float64(writer) / filebig) * 100 - go shell(pect) - sum32.Write(buf[0:n]) - } - result = hex.EncodeToString(sum32.Sum(nil)) - } - return result, nil -} - -// FileSumAll 可以对同一文件进行多种校验 -func FileSumAll(filepath string, method []string, shell func(float64)) (map[string]string, error) { - result := make(map[string]string) - methods := make(map[string]hash.Hash) - var iscrc bool - - if len(method) == 0 { - method = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32", "md5"} - } - fp, err := os.Open(filepath) - defer fp.Close() - if err != nil { - return result, err - } - stat, _ := os.Stat(filepath) - filebig := float64(stat.Size()) - sum512 := sha512.New() - sum384 := sha512.New384() - sum256 := sha256.New() - sum224 := sha256.New224() - sum1 := sha1.New() - crcsum := crc32.NewIEEE() - md5sum := md5.New() - for _, v := range method { - switch v { - case "md5": - methods["md5"] = md5sum - case "crc32": - iscrc = true - case "sha1": - methods["sha1"] = sum1 - case "sha224": - methods["sha224"] = sum224 - case "sha256": - methods["sha256"] = sum256 - case "sha384": - methods["sha384"] = sum384 - case "sha512": - methods["sha512"] = sum512 - } - } - - writer := 0 - for { - buf := make([]byte, 1048574) - n, err := fp.Read(buf) - if err != nil { - if err == io.EOF { - break - } - return result, err - } - writer += n - pect := (float64(writer) / filebig) * 100 - go shell(pect) - for _, v := range methods { - v.Write(buf[0:n]) - } - if iscrc { - crcsum.Write(buf[0:n]) - } - } - for k, v := range methods { - result[k] = hex.EncodeToString(v.Sum(nil)) - } - if iscrc { - result["crc32"] = hex.EncodeToString(crcsum.Sum(nil)) - } - return result, nil -} - -// Attach 合并src与dst文件并输出到output中 -func Attach(src, dst, output string) error { - fpsrc, err := os.Open(src) - if err != nil { - return err - } - defer fpsrc.Close() - fpdst, err := os.Open(dst) - if err != nil { - return err - } - defer fpdst.Close() - fpout, err := os.Create(output) - if err != nil { - return err - } - defer fpout.Close() - if _, err := io.Copy(fpout, fpsrc); err != nil { - return err - } - for { - buf := make([]byte, 1048574) - n, err := fpdst.Read(buf) - if err != nil { - if err == io.EOF { - break - } - return err - } - fpout.Write(buf[0:n]) - } - return nil -} - -// Detach 按bytenum字节大小分割src文件到dst1与dst2两个新文件中去 -func Detach(src string, bytenum int, dst1, dst2 string) error { - fpsrc, err := os.Open(src) - if err != nil { - return err - } - defer fpsrc.Close() - fpdst1, err := os.Create(dst1) - if err != nil { - return err - } - defer fpdst1.Close() - fpdst2, err := os.Create(dst2) - if err != nil { - return err - } - defer fpdst2.Close() - sumall := 0 - var buf []byte - for { - if bytenum-sumall < 1048576 { - buf = make([]byte, bytenum-sumall) - } else { - buf = make([]byte, 1048576) - } - n, err := fpsrc.Read(buf) - if err != nil { - return err - } - sumall += n - fpdst1.Write(buf[0:n]) - if sumall == bytenum { - break - } - } - for { - buf = make([]byte, 1048576) - n, err := fpsrc.Read(buf) - if err != nil { - if err == io.EOF { - break - } - return err - } - fpdst2.Write(buf[0:n]) - } - return nil -} - -// SplitFile 把src文件按要求分割到dst中去,dst应传入带*号字符串 -// 如果bynum=true 则把文件分割成num份 -// 如果bynum=false 则把文件按num字节分成多份 -func SplitFile(src, dst string, num int, bynum bool, shell func(float64)) error { - fpsrc, err := os.Open(src) - if err != nil { - return err - } - defer fpsrc.Close() - stat, _ := os.Stat(src) - filebig := float64(stat.Size()) - if bynum { - if int(filebig) < num { - return errors.New("file is too small to split") - } - } - balance := int(filebig/float64(num)) + 1 - if !bynum { - balance = num - } - nownum := 0 - fpdst, err := os.Create(strings.Replace(dst, "*", fmt.Sprint(nownum), -1)) - if err != nil { - return err - } - defer fpdst.Close() - var sum, tsum int = 0, 0 - var buf []byte - for { - if balance-sum < 1048576 { - buf = make([]byte, balance-sum) - } else { - buf = make([]byte, 1048576) - } - n, err := fpsrc.Read(buf) - if err != nil { - if err == io.EOF { - break - } - return err - } - sum += n - tsum += n - fpdst.Write(buf[0:n]) - go shell(float64(tsum) / filebig * 100) - if sum == balance { - fpdst.Close() - nownum++ - fpdst, err = os.Create(strings.Replace(dst, "*", fmt.Sprint(nownum), -1)) - if err != nil { - return err - } - sum = 0 - } - } - return nil -} - -// MergeFile 合并src文件到dst文件中去,src文件应传入带*号字符串 -func MergeFile(src, dst string, shell func(float64)) error { - tmp := strings.Replace(src, "*", "0", -1) - dir, err := ioutil.ReadDir(filepath.Dir(tmp)) - if err != nil { - return err - } - base := filepath.Base(src) - tmp = strings.Replace(base, "*", "(\\d+)", -1) - reg := regexp.MustCompile(tmp) - count := 0 - var filebig float64 - for _, v := range dir { - if reg.MatchString(v.Name()) { - count++ - filebig += float64(v.Size()) - } - } - fpdst, err := os.Create(dst) - defer fpdst.Close() - if err != nil { - return err - } - var sum int64 - for i := 0; i < count; i++ { - fpsrc, err := os.Open(strings.Replace(src, "*", strconv.Itoa(i), -1)) - if err != nil { - return err - } - for { - buf := make([]byte, 1048576) - n, err := fpsrc.Read(buf) - if err != nil { - if err == io.EOF { - break - } - return err - } - sum += int64(n) - go shell(float64(sum) / filebig * 100) - fpdst.Write(buf[0:n]) - } - fpsrc.Close() - } - return nil -} - -// VicqueEncodeV1 Best! func VicqueEncodeV1(srcdata []byte, key string) []byte { var keys []int - var saku, piku uint8 + var randCode1, randCode2 uint8 data := make([]byte, len(srcdata)) copy(data, srcdata) - binary.Read(rand.Reader, binary.LittleEndian, &saku) - binary.Read(rand.Reader, binary.LittleEndian, &piku) - keys = append(keys, len(key)+int(saku)) + binary.Read(rand.Reader, binary.LittleEndian, &randCode1) + binary.Read(rand.Reader, binary.LittleEndian, &randCode2) + keys = append(keys, len(key)+int(randCode1)) lens := len(data) for _, v := range key { - keys = append(keys, int(byte(v))+int(saku)-int(piku)) + keys = append(keys, int(byte(v))+int(randCode1)-int(randCode2)) } lenkey := len(keys) for k, v := range data { @@ -529,22 +55,21 @@ func VicqueEncodeV1(srcdata []byte, key string) []byte { data[k] = byte(t) data[lens-1-k] = byte(nv) } - data = append(data, byte(saku), byte(piku)) + data = append(data, byte(randCode1), byte(randCode2)) return data } -// VicqueDecodeV1 Best! func VicqueDecodeV1(srcdata []byte, key string) []byte { var keys []int - var saku, piku int + var randCode1, randCode2 int data := make([]byte, len(srcdata)) copy(data, srcdata) lens := len(data) - saku = int(data[lens-2]) - piku = int(data[lens-1]) - keys = append(keys, len(key)+int(saku)) + randCode1 = int(data[lens-2]) + randCode2 = int(data[lens-1]) + keys = append(keys, len(key)+int(randCode1)) for _, v := range key { - keys = append(keys, int(byte(v))+int(saku)-int(piku)) + keys = append(keys, int(byte(v))+int(randCode1)-int(randCode2)) } lenkey := len(keys) lens -= 2 @@ -581,7 +106,6 @@ func VicqueDecodeV1(srcdata []byte, key string) []byte { return data[:lens] } -// VicqueEncodeV1File best func VicqueEncodeV1File(src, dst, pwd string, shell func(float64)) error { fpsrc, err := os.Open(src) if err != nil { @@ -614,7 +138,6 @@ func VicqueEncodeV1File(src, dst, pwd string, shell func(float64)) error { return nil } -// VicqueDecodeV1File best func VicqueDecodeV1File(src, dst, pwd string, shell func(float64)) error { fpsrc, err := os.Open(src) if err != nil { @@ -646,92 +169,3 @@ func VicqueDecodeV1File(src, dst, pwd string, shell func(float64)) error { } return nil } - -// FillWithRandom 随机写filesize大小的文件,每次buf大小为bufcap,随机bufnum个字符 -func FillWithRandom(filepath string, filesize int, bufcap int, bufnum int, shell func(float64)) error { - var buf [][]byte - var buftmp []byte - rands.Seed(time.Now().Unix()) - if bufnum <= 0 { - bufnum = 1 - } - if bufcap > filesize { - bufcap = filesize - } - myfile, err := os.Create(filepath) - if err != nil { - return err - } - defer myfile.Close() - writer := bufio.NewWriter(myfile) - for i := 0; i < bufnum; i++ { - buftmp = []byte{} - for j := 0; j < bufcap; j++ { - buftmp = append(buftmp, byte(rands.Intn(256))) - } - buf = append(buf, buftmp) - } - sum := 0 - for { - if filesize-sum < bufcap { - writer.Write(buf[rands.Intn(bufnum)][0 : filesize-sum]) - sum += filesize - sum - } else { - writer.Write(buf[rands.Intn(bufnum)]) - sum += bufcap - } - go shell(float64(sum) / float64(filesize) * 100) - if sum >= filesize { - break - } - } - writer.Flush() - return nil -} - -// =================== CFB ====================== -func AesEncryptCFB(origData []byte, key []byte) (encrypted []byte) { - block, err := aes.NewCipher(key) - if err != nil { - panic(err) - } - encrypted = make([]byte, aes.BlockSize+len(origData)) - iv := encrypted[:aes.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - panic(err) - } - stream := cipher.NewCFBEncrypter(block, iv) - stream.XORKeyStream(encrypted[aes.BlockSize:], origData) - return encrypted -} -func AesDecryptCFB(encrypted []byte, key []byte) (decrypted []byte) { - block, _ := aes.NewCipher(key) - if len(encrypted) < aes.BlockSize { - panic("ciphertext too short") - } - iv := encrypted[:aes.BlockSize] - encrypted = encrypted[aes.BlockSize:] - - stream := cipher.NewCFBDecrypter(block, iv) - stream.XORKeyStream(encrypted, encrypted) - return encrypted -} - -func AesEncryptCFBNoBlock(origData []byte, key []byte) (encrypted []byte) { - block, err := aes.NewCipher(key) - if err != nil { - panic(err) - } - encrypted = make([]byte, len(origData)) - iv := Sha1(key)[:16] - stream := cipher.NewCFBEncrypter(block, iv) - stream.XORKeyStream(encrypted, origData) - return encrypted -} -func AesDecryptCFBNoBlock(encrypted []byte, key []byte) (decrypted []byte) { - block, _ := aes.NewCipher(key) - iv := Sha1(key)[:16] - stream := cipher.NewCFBDecrypter(block, iv) - stream.XORKeyStream(encrypted, encrypted) - return encrypted -} diff --git a/ecdsa.go b/ecdsa.go new file mode 100644 index 0000000..3e59be0 --- /dev/null +++ b/ecdsa.go @@ -0,0 +1,117 @@ +package starcrypto + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/pem" + "errors" + "golang.org/x/crypto/ssh" +) + +func GenerateEcdsaKey(pubkeyCurve elliptic.Curve) (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) { + // 随机挑选基点,生成私钥 + priv, err := ecdsa.GenerateKey(pubkeyCurve, rand.Reader) + if err != nil { + return nil, nil, err + } + return priv, &priv.PublicKey, nil + +} + +func EncodeEcdsaPrivateKey(private *ecdsa.PrivateKey, secret string) ([]byte, error) { + b, err := x509.MarshalECPrivateKey(private) + if err != nil { + return nil, err + } + if secret == "" { + return pem.EncodeToMemory(&pem.Block{ + Bytes: b, + Type: "EC PRIVATE KEY", + }), err + } + chiper := x509.PEMCipherAES256 + blk, err := x509.EncryptPEMBlock(rand.Reader, "EC PRIVATE KEY", b, []byte(secret), chiper) + if err != nil { + return nil, err + } + return pem.EncodeToMemory(blk), err +} + +func EncodeEcdsaPublicKey(public *ecdsa.PublicKey) ([]byte, error) { + publicBytes, err := x509.MarshalPKIXPublicKey(public) + if err != nil { + return nil, err + } + return pem.EncodeToMemory(&pem.Block{ + Bytes: publicBytes, + Type: "PUBLIC KEY", + }), nil +} + +func DecodeEcdsaPrivateKey(private []byte, password string) (*ecdsa.PrivateKey, error) { + var prikey *ecdsa.PrivateKey + var err error + var bytes []byte + blk, _ := pem.Decode(private) + if blk == nil { + return nil, errors.New("private key error!") + } + if password != "" { + tmp, err := x509.DecryptPEMBlock(blk, []byte(password)) + if err != nil { + return nil, err + } + bytes = tmp + } else { + bytes = blk.Bytes + } + prikey, err = x509.ParseECPrivateKey(bytes) + if err != nil { + tmp, err := x509.ParsePKCS8PrivateKey(bytes) + if err != nil { + return nil, err + } + prikey = tmp.(*ecdsa.PrivateKey) + } + return prikey, err +} + +func DecodeEcdsaPublicKey(pubStr []byte) (*ecdsa.PublicKey, error) { + blk, _ := pem.Decode(pubStr) + if blk == nil { + return nil, errors.New("public key error") + } + pub, err := x509.ParsePKIXPublicKey(blk.Bytes) + if err != nil { + return nil, err + } + return pub.(*ecdsa.PublicKey), nil +} + +func EncodeEcdsaSSHPublicKey(public *ecdsa.PublicKey) ([]byte, error) { + publicKey, err := ssh.NewPublicKey(public) + if err != nil { + return nil, err + } + return ssh.MarshalAuthorizedKey(publicKey), nil +} + +func GenerateEcdsaSSHKeyPair(pubkeyCurve elliptic.Curve, secret string) (string, string, error) { + pkey, pubkey, err := GenerateEcdsaKey(pubkeyCurve) + if err != nil { + return "", "", err + } + + pub, err := EncodeEcdsaSSHPublicKey(pubkey) + if err != nil { + return "", "", err + } + + priv, err := EncodeEcdsaPrivateKey(pkey, secret) + if err != nil { + return "", "", err + } + return string(priv), string(pub), nil +} diff --git a/file.go b/file.go new file mode 100644 index 0000000..1b1c276 --- /dev/null +++ b/file.go @@ -0,0 +1,246 @@ +package starcrypto + +import ( + "bufio" + "errors" + "fmt" + "io" + "io/ioutil" + "math/rand" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "time" +) + +// Attach 合并src与dst文件并输出到output中 +func Attach(src, dst, output string) error { + fpsrc, err := os.Open(src) + if err != nil { + return err + } + defer fpsrc.Close() + fpdst, err := os.Open(dst) + if err != nil { + return err + } + defer fpdst.Close() + fpout, err := os.Create(output) + if err != nil { + return err + } + defer fpout.Close() + if _, err := io.Copy(fpout, fpsrc); err != nil { + return err + } + for { + buf := make([]byte, 1048574) + n, err := fpdst.Read(buf) + if err != nil { + if err == io.EOF { + break + } + return err + } + fpout.Write(buf[0:n]) + } + return nil +} + +// Detach 按bytenum字节大小分割src文件到dst1与dst2两个新文件中去 +func Detach(src string, bytenum int, dst1, dst2 string) error { + fpsrc, err := os.Open(src) + if err != nil { + return err + } + defer fpsrc.Close() + fpdst1, err := os.Create(dst1) + if err != nil { + return err + } + defer fpdst1.Close() + fpdst2, err := os.Create(dst2) + if err != nil { + return err + } + defer fpdst2.Close() + sumall := 0 + var buf []byte + for { + if bytenum-sumall < 1048576 { + buf = make([]byte, bytenum-sumall) + } else { + buf = make([]byte, 1048576) + } + n, err := fpsrc.Read(buf) + if err != nil { + return err + } + sumall += n + fpdst1.Write(buf[0:n]) + if sumall == bytenum { + break + } + } + for { + buf = make([]byte, 1048576) + n, err := fpsrc.Read(buf) + if err != nil { + if err == io.EOF { + break + } + return err + } + fpdst2.Write(buf[0:n]) + } + return nil +} + +// SplitFile 把src文件按要求分割到dst中去,dst应传入带*号字符串 +// 如果bynum=true 则把文件分割成num份 +// 如果bynum=false 则把文件按num字节分成多份 +func SplitFile(src, dst string, num int, bynum bool, shell func(float64)) error { + fpsrc, err := os.Open(src) + if err != nil { + return err + } + defer fpsrc.Close() + stat, _ := os.Stat(src) + filebig := float64(stat.Size()) + if bynum { + if int(filebig) < num { + return errors.New("file is too small to split") + } + } + balance := int(filebig/float64(num)) + 1 + if !bynum { + balance = num + } + nownum := 0 + fpdst, err := os.Create(strings.Replace(dst, "*", fmt.Sprint(nownum), -1)) + if err != nil { + return err + } + defer fpdst.Close() + var sum, tsum int = 0, 0 + var buf []byte + for { + if balance-sum < 1048576 { + buf = make([]byte, balance-sum) + } else { + buf = make([]byte, 1048576) + } + n, err := fpsrc.Read(buf) + if err != nil { + if err == io.EOF { + break + } + return err + } + sum += n + tsum += n + fpdst.Write(buf[0:n]) + go shell(float64(tsum) / filebig * 100) + if sum == balance { + fpdst.Close() + nownum++ + fpdst, err = os.Create(strings.Replace(dst, "*", fmt.Sprint(nownum), -1)) + if err != nil { + return err + } + sum = 0 + } + } + return nil +} + +// MergeFile 合并src文件到dst文件中去,src文件应传入带*号字符串 +func MergeFile(src, dst string, shell func(float64)) error { + tmp := strings.Replace(src, "*", "0", -1) + dir, err := ioutil.ReadDir(filepath.Dir(tmp)) + if err != nil { + return err + } + base := filepath.Base(src) + tmp = strings.Replace(base, "*", "(\\d+)", -1) + reg := regexp.MustCompile(tmp) + count := 0 + var filebig float64 + for _, v := range dir { + if reg.MatchString(v.Name()) { + count++ + filebig += float64(v.Size()) + } + } + fpdst, err := os.Create(dst) + defer fpdst.Close() + if err != nil { + return err + } + var sum int64 + for i := 0; i < count; i++ { + fpsrc, err := os.Open(strings.Replace(src, "*", strconv.Itoa(i), -1)) + if err != nil { + return err + } + for { + buf := make([]byte, 1048576) + n, err := fpsrc.Read(buf) + if err != nil { + if err == io.EOF { + break + } + return err + } + sum += int64(n) + go shell(float64(sum) / filebig * 100) + fpdst.Write(buf[0:n]) + } + fpsrc.Close() + } + return nil +} + +// FillWithRandom 随机写filesize大小的文件,每次buf大小为bufcap,随机bufnum个字符 +func FillWithRandom(filepath string, filesize int, bufcap int, bufnum int, shell func(float64)) error { + var buf [][]byte + var buftmp []byte + rand.Seed(time.Now().Unix()) + if bufnum <= 0 { + bufnum = 1 + } + if bufcap > filesize { + bufcap = filesize + } + myfile, err := os.Create(filepath) + if err != nil { + return err + } + defer myfile.Close() + writer := bufio.NewWriter(myfile) + for i := 0; i < bufnum; i++ { + buftmp = []byte{} + for j := 0; j < bufcap; j++ { + buftmp = append(buftmp, byte(rand.Intn(256))) + } + buf = append(buf, buftmp) + } + sum := 0 + for { + if filesize-sum < bufcap { + writer.Write(buf[rand.Intn(bufnum)][0 : filesize-sum]) + sum += filesize - sum + } else { + writer.Write(buf[rand.Intn(bufnum)]) + sum += bufcap + } + go shell(float64(sum) / float64(filesize) * 100) + if sum >= filesize { + break + } + } + writer.Flush() + return nil +} diff --git a/go.mod b/go.mod index 42f157d..e441e45 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module b612.me/starcrypto go 1.16 -require golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000 +require golang.org/x/crypto v0.21.0 diff --git a/go.sum b/go.sum index e7799fa..78c3953 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,45 @@ -golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000 h1:SL+8VVnkqyshUSz5iNnXtrBQzvFF2SkROm6t5RczFAE= -golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/hash.go b/hash.go new file mode 100644 index 0000000..d9c7a86 --- /dev/null +++ b/hash.go @@ -0,0 +1,204 @@ +package starcrypto + +import ( + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/hex" + "errors" + "hash" + "hash/crc32" + "io" + "os" +) + +// SumAll 可以对同一数据进行多种校验 +func SumAll(data []byte, method []string) (map[string][]byte, error) { + result := make(map[string][]byte) + methods := make(map[string]hash.Hash) + var iscrc bool + if len(method) == 0 { + method = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32", "md5"} + } + sum512 := sha512.New() + sum384 := sha512.New384() + sum256 := sha256.New() + sum224 := sha256.New224() + sum1 := sha1.New() + crcsum := crc32.NewIEEE() + md5sum := md5.New() + for _, v := range method { + switch v { + case "md5": + methods["md5"] = md5sum + case "crc32": + iscrc = true + case "sha1": + methods["sha1"] = sum1 + case "sha224": + methods["sha224"] = sum224 + case "sha256": + methods["sha256"] = sum256 + case "sha384": + methods["sha384"] = sum384 + case "sha512": + methods["sha512"] = sum512 + } + } + for _, v := range methods { + v.Write(data) + } + if iscrc { + crcsum.Write(data) + } + + for k, v := range methods { + result[k] = v.Sum(nil) + } + if iscrc { + result["crc32"] = crcsum.Sum(nil) + } + return result, nil +} + +// FileSum 输出文件内容校验值,method为单个校验方法,小写 +// 例:FileSum("./test.txt","md5",shell(pect float64){fmt.Sprintf("已完成 %f\r",pect)}) +func FileSum(filepath, method string, shell func(float64)) (string, error) { + var sum hash.Hash + var sum32 hash.Hash32 + var issum32 bool + var result string + fp, err := os.Open(filepath) + if err != nil { + return "", err + } + switch method { + case "sha512": + sum = sha512.New() + case "sha384": + sum = sha512.New384() + case "sha256": + sum = sha256.New() + case "sha224": + sum = sha256.New224() + case "sha1": + sum = sha1.New() + case "crc32": + sum32 = crc32.NewIEEE() + issum32 = true + case "md5": + sum = md5.New() + default: + return "", errors.New("Cannot Recognize The Method:" + method) + } + writer := 0 + stat, _ := os.Stat(filepath) + filebig := float64(stat.Size()) + if !issum32 { + // if _, err := io.Copy(sum, fp); err != nil { + for { + buf := make([]byte, 1048574) + n, err := fp.Read(buf) + if err != nil { + if err == io.EOF { + break + } + return result, err + } + writer += n + pect := (float64(writer) / filebig) * 100 + go shell(pect) + sum.Write(buf[0:n]) + } + result = hex.EncodeToString(sum.Sum(nil)) + } else { + for { + buf := make([]byte, 1048574) + n, err := fp.Read(buf) + if err != nil { + if err == io.EOF { + break + } + return result, err + } + writer += n + pect := (float64(writer) / filebig) * 100 + go shell(pect) + sum32.Write(buf[0:n]) + } + result = hex.EncodeToString(sum32.Sum(nil)) + } + return result, nil +} + +// FileSumAll 可以对同一文件进行多种校验 +func FileSumAll(filepath string, method []string, shell func(float64)) (map[string]string, error) { + result := make(map[string]string) + methods := make(map[string]hash.Hash) + var iscrc bool + + if len(method) == 0 { + method = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32", "md5"} + } + fp, err := os.Open(filepath) + defer fp.Close() + if err != nil { + return result, err + } + stat, _ := os.Stat(filepath) + filebig := float64(stat.Size()) + sum512 := sha512.New() + sum384 := sha512.New384() + sum256 := sha256.New() + sum224 := sha256.New224() + sum1 := sha1.New() + crcsum := crc32.NewIEEE() + md5sum := md5.New() + for _, v := range method { + switch v { + case "md5": + methods["md5"] = md5sum + case "crc32": + iscrc = true + case "sha1": + methods["sha1"] = sum1 + case "sha224": + methods["sha224"] = sum224 + case "sha256": + methods["sha256"] = sum256 + case "sha384": + methods["sha384"] = sum384 + case "sha512": + methods["sha512"] = sum512 + } + } + + writer := 0 + for { + buf := make([]byte, 1048574) + n, err := fp.Read(buf) + if err != nil { + if err == io.EOF { + break + } + return result, err + } + writer += n + pect := (float64(writer) / filebig) * 100 + go shell(pect) + for _, v := range methods { + v.Write(buf[0:n]) + } + if iscrc { + crcsum.Write(buf[0:n]) + } + } + for k, v := range methods { + result[k] = hex.EncodeToString(v.Sum(nil)) + } + if iscrc { + result["crc32"] = hex.EncodeToString(crcsum.Sum(nil)) + } + return result, nil +} diff --git a/hmac.go b/hmac.go new file mode 100644 index 0000000..bf77fa4 --- /dev/null +++ b/hmac.go @@ -0,0 +1,87 @@ +package starcrypto + +import ( + "crypto/hmac" + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/hex" + "golang.org/x/crypto/md4" + "golang.org/x/crypto/ripemd160" + "hash" +) + +func chmac(message, key []byte, f func() hash.Hash) []byte { + h := hmac.New(f, []byte(key)) + h.Write([]byte(message)) + return h.Sum(nil) +} + +func chmacStr(message, key []byte, f func() hash.Hash) string { + return hex.EncodeToString(chmac(message, key, f)) +} + +func HmacMd4(message, key []byte) []byte { + return chmac(message, key, md4.New) +} + +func HmacMd4Str(message, key []byte) string { + return chmacStr(message, key, md4.New) +} + +func HmacMd5(message, key []byte) []byte { + return chmac(message, key, md5.New) +} + +func HmacMd5Str(message, key []byte) string { + return chmacStr(message, key, md5.New) +} + +func HmacSHA1(message, key []byte) []byte { + return chmac(message, key, sha1.New) +} + +func HmacSHA1Str(message, key []byte) string { + return chmacStr(message, key, sha1.New) +} + +func HmacSHA256(message, key []byte) []byte { + return chmac(message, key, sha256.New) +} + +func HmacSHA256Str(message, key []byte) string { + return chmacStr(message, key, sha256.New) +} + +func HmacSHA384(message, key []byte) []byte { + return chmac(message, key, sha512.New384) +} + +func HmacSHA384Str(message, key []byte) string { + return chmacStr(message, key, sha512.New384) +} + +func HmacSHA512(message, key []byte) []byte { + return chmac(message, key, sha512.New) +} + +func HmacSHA512Str(message, key []byte) string { + return chmacStr(message, key, sha512.New) +} + +func HmacSHA224(message, key []byte) []byte { + return chmac(message, key, sha256.New224) +} + +func HmacSHA224Str(message, key []byte) string { + return chmacStr(message, key, sha256.New224) +} + +func HmacRipeMd160(message, key []byte) []byte { + return chmac(message, key, ripemd160.New) +} + +func HmacRipeMd160Str(message, key []byte) string { + return chmacStr(message, key, ripemd160.New) +} diff --git a/md5.go b/md5.go new file mode 100644 index 0000000..d7da41a --- /dev/null +++ b/md5.go @@ -0,0 +1,27 @@ +package starcrypto + +import ( + "crypto/md5" + "golang.org/x/crypto/md4" +) + +// MD5 输出MD5校验值 +func Md5(bstr []byte) []byte { + md5sum := md5.New() + md5sum.Write(bstr) + return md5sum.Sum(nil) +} + +func Md5Str(bstr []byte) string { + return String(Md5(bstr)) +} + +func Md4(bstr []byte) []byte { + md4sum := md4.New() + md4sum.Write(bstr) + return md4sum.Sum(nil) +} + +func Md4Str(bstr []byte) string { + return String(Md4(bstr)) +} diff --git a/ripe.go b/ripe.go new file mode 100644 index 0000000..3f9d708 --- /dev/null +++ b/ripe.go @@ -0,0 +1,15 @@ +package starcrypto + +import ( + "golang.org/x/crypto/ripemd160" +) + +func RipeMd160(bstr []byte) []byte { + ripe := ripemd160.New() + ripe.Write(bstr) + return ripe.Sum(nil) +} + +func RipeMd160Str(bstr []byte) string { + return String(RipeMd160(bstr)) +} diff --git a/rsa.go b/rsa.go index 988ff47..4b6e99e 100644 --- a/rsa.go +++ b/rsa.go @@ -12,7 +12,7 @@ import ( "math/big" ) -func GenerateKey(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { +func GenerateRsaKey(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { private, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { return nil, nil, err @@ -21,14 +21,22 @@ func GenerateKey(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { } -func EncodePrivateKey(private *rsa.PrivateKey) []byte { - return pem.EncodeToMemory(&pem.Block{ - Bytes: x509.MarshalPKCS1PrivateKey(private), - Type: "RSA PRIVATE KEY", - }) +func EncodeRsaPrivateKey(private *rsa.PrivateKey, secret string) ([]byte, error) { + if secret == "" { + return pem.EncodeToMemory(&pem.Block{ + Bytes: x509.MarshalPKCS1PrivateKey(private), + Type: "RSA PRIVATE KEY", + }), nil + } + chiper := x509.PEMCipherAES256 + blk, err := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(private), []byte(secret), chiper) + if err != nil { + return nil, err + } + return pem.EncodeToMemory(blk), err } -func EncodePublicKey(public *rsa.PublicKey) ([]byte, error) { +func EncodeRsaPublicKey(public *rsa.PublicKey) ([]byte, error) { publicBytes, err := x509.MarshalPKIXPublicKey(public) if err != nil { return nil, err @@ -39,7 +47,7 @@ func EncodePublicKey(public *rsa.PublicKey) ([]byte, error) { }), nil } -func DecodePrivateKey(private []byte, password string) (*rsa.PrivateKey, error) { +func DecodeRsaPrivateKey(private []byte, password string) (*rsa.PrivateKey, error) { var prikey *rsa.PrivateKey var err error var bytes []byte @@ -67,7 +75,7 @@ func DecodePrivateKey(private []byte, password string) (*rsa.PrivateKey, error) return prikey, err } -func DecodePublicKey(pubStr []byte) (*rsa.PublicKey, error) { +func DecodeRsaPublicKey(pubStr []byte) (*rsa.PublicKey, error) { blk, _ := pem.Decode(pubStr) if blk == nil { return nil, errors.New("public key error") @@ -79,8 +87,7 @@ func DecodePublicKey(pubStr []byte) (*rsa.PublicKey, error) { return pub.(*rsa.PublicKey), nil } -//EncodeSSHKey -func EncodeSSHKey(public *rsa.PublicKey) ([]byte, error) { +func EncodeRsaSSHPublicKey(public *rsa.PublicKey) ([]byte, error) { publicKey, err := ssh.NewPublicKey(public) if err != nil { return nil, err @@ -88,20 +95,22 @@ func EncodeSSHKey(public *rsa.PublicKey) ([]byte, error) { return ssh.MarshalAuthorizedKey(publicKey), nil } -func MakeSSHKeyPair(bits int) (string, string, error) { - - pkey, pubkey, err := GenerateKey(bits) +func GenerateRsaSSHKeyPair(bits int, secret string) (string, string, error) { + pkey, pubkey, err := GenerateRsaKey(bits) if err != nil { return "", "", err } - pub, err := EncodeSSHKey(pubkey) + pub, err := EncodeRsaSSHPublicKey(pubkey) if err != nil { return "", "", err } - //glog.Info("privateKey=[%s]\n pubKey=[%s]",string(EncodePrivateKey(pkey)),string(pub)) - return string(EncodePrivateKey(pkey)), string(pub), nil + priv, err := EncodeRsaPrivateKey(pkey, secret) + if err != nil { + return "", "", err + } + return string(priv), string(pub), nil } // RSAEncrypt RSA公钥加密 diff --git a/sha.go b/sha.go new file mode 100644 index 0000000..408ede9 --- /dev/null +++ b/sha.go @@ -0,0 +1,62 @@ +package starcrypto + +import ( + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" +) + +// SHA512 输出SHA512校验值 +func Sha512(bstr []byte) []byte { + shasum := sha512.New() + shasum.Write(bstr) + return shasum.Sum(nil) +} + +func Sha512Str(bstr []byte) string { + return String(Sha512(bstr)) +} + +// SHA384 输出SHA384校验值 +func Sha384(bstr []byte) []byte { + shasum := sha512.New384() + shasum.Write(bstr) + return shasum.Sum(nil) +} + +func Sha384Str(bstr []byte) string { + return String(Sha384(bstr)) +} + +// SHA256 输出SHA256校验值 +func Sha256(bstr []byte) []byte { + shasum := sha256.New() + shasum.Write(bstr) + return shasum.Sum(nil) +} + +func Sha256Str(bstr []byte) string { + return String(Sha256(bstr)) +} + +// SHA224 输出SHA224校验值 +func Sha224(bstr []byte) []byte { + shasum := sha256.New224() + shasum.Write(bstr) + return shasum.Sum(nil) +} + +func Sha224Str(bstr []byte) string { + return String(Sha224(bstr)) +} + +// SHA1 输出SHA1校验值 +func Sha1(bstr []byte) []byte { + shasum := sha1.New() + shasum.Write(bstr) + return shasum.Sum(nil) +} + +func Sha1Str(bstr []byte) string { + return String(Sha512(bstr)) +} diff --git a/sm3.go b/sm3.go new file mode 100644 index 0000000..b70841c --- /dev/null +++ b/sm3.go @@ -0,0 +1,15 @@ +package starcrypto + +import ( + "b612.me/starcrypto/sm3" +) + +func SM3(bstr []byte) []byte { + sm3sum := sm3.New() + sm3sum.Write(bstr) + return sm3sum.Sum(nil) +} + +func SM3Str(bstr []byte) string { + return String(SM3(bstr)) +} diff --git a/sm3/sm3.go b/sm3/sm3.go new file mode 100644 index 0000000..7245dd6 --- /dev/null +++ b/sm3/sm3.go @@ -0,0 +1,259 @@ +/* +Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sm3 + +import ( + "encoding/binary" + "hash" +) + +type SM3 struct { + digest [8]uint32 // digest represents the partial evaluation of V + length uint64 // length of the message + unhandleMsg []byte // uint8 // +} + +func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z } + +func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) } + +func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z } + +func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) } + +func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) } + +func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) } + +func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return x<<(i%32) | x>>(32-i%32) } + +func (sm3 *SM3) pad() []byte { + msg := sm3.unhandleMsg + msg = append(msg, 0x80) // Append '1' + blockSize := 64 // Append until the resulting message length (in bits) is congruent to 448 (mod 512) + for len(msg)%blockSize != 56 { + msg = append(msg, 0x00) + } + // append message length + msg = append(msg, uint8(sm3.length>>56&0xff)) + msg = append(msg, uint8(sm3.length>>48&0xff)) + msg = append(msg, uint8(sm3.length>>40&0xff)) + msg = append(msg, uint8(sm3.length>>32&0xff)) + msg = append(msg, uint8(sm3.length>>24&0xff)) + msg = append(msg, uint8(sm3.length>>16&0xff)) + msg = append(msg, uint8(sm3.length>>8&0xff)) + msg = append(msg, uint8(sm3.length>>0&0xff)) + + if len(msg)%64 != 0 { + panic("------SM3 Pad: error msgLen =") + } + return msg +} + +func (sm3 *SM3) update(msg []byte) { + var w [68]uint32 + var w1 [64]uint32 + + a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] + for len(msg) >= 64 { + for i := 0; i < 16; i++ { + w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)]) + } + for i := 16; i < 68; i++ { + w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6] + } + for i := 0; i < 64; i++ { + w1[i] = w[i] ^ w[i+4] + } + A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h + for i := 0; i < 16; i++ { + SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7) + SS2 := SS1 ^ sm3.leftRotate(A, 12) + TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i] + TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i] + D = C + C = sm3.leftRotate(B, 9) + B = A + A = TT1 + H = G + G = sm3.leftRotate(F, 19) + F = E + E = sm3.p0(TT2) + } + for i := 16; i < 64; i++ { + SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7) + SS2 := SS1 ^ sm3.leftRotate(A, 12) + TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i] + TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i] + D = C + C = sm3.leftRotate(B, 9) + B = A + A = TT1 + H = G + G = sm3.leftRotate(F, 19) + F = E + E = sm3.p0(TT2) + } + a ^= A + b ^= B + c ^= C + d ^= D + e ^= E + f ^= F + g ^= G + h ^= H + msg = msg[64:] + } + sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] = a, b, c, d, e, f, g, h +} +func (sm3 *SM3) update2(msg []byte) [8]uint32 { + var w [68]uint32 + var w1 [64]uint32 + + a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] + for len(msg) >= 64 { + for i := 0; i < 16; i++ { + w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)]) + } + for i := 16; i < 68; i++ { + w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6] + } + for i := 0; i < 64; i++ { + w1[i] = w[i] ^ w[i+4] + } + A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h + for i := 0; i < 16; i++ { + SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7) + SS2 := SS1 ^ sm3.leftRotate(A, 12) + TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i] + TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i] + D = C + C = sm3.leftRotate(B, 9) + B = A + A = TT1 + H = G + G = sm3.leftRotate(F, 19) + F = E + E = sm3.p0(TT2) + } + for i := 16; i < 64; i++ { + SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7) + SS2 := SS1 ^ sm3.leftRotate(A, 12) + TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i] + TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i] + D = C + C = sm3.leftRotate(B, 9) + B = A + A = TT1 + H = G + G = sm3.leftRotate(F, 19) + F = E + E = sm3.p0(TT2) + } + a ^= A + b ^= B + c ^= C + d ^= D + e ^= E + f ^= F + g ^= G + h ^= H + msg = msg[64:] + } + var digest [8]uint32 + digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7] = a, b, c, d, e, f, g, h + return digest +} + +// 创建哈希计算实例 +func New() hash.Hash { + var sm3 SM3 + + sm3.Reset() + return &sm3 +} + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (sm3 *SM3) BlockSize() int { return 64 } + +// Size returns the number of bytes Sum will return. +func (sm3 *SM3) Size() int { return 32 } + +// Reset clears the internal state by zeroing bytes in the state buffer. +// This can be skipped for a newly-created hash state; the default zero-allocated state is correct. +func (sm3 *SM3) Reset() { + // Reset digest + sm3.digest[0] = 0x7380166f + sm3.digest[1] = 0x4914b2b9 + sm3.digest[2] = 0x172442d7 + sm3.digest[3] = 0xda8a0600 + sm3.digest[4] = 0xa96f30bc + sm3.digest[5] = 0x163138aa + sm3.digest[6] = 0xe38dee4d + sm3.digest[7] = 0xb0fb0e4e + + sm3.length = 0 // Reset numberic states + sm3.unhandleMsg = []byte{} +} + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (sm3 *SM3) Write(p []byte) (int, error) { + toWrite := len(p) + sm3.length += uint64(len(p) * 8) + msg := append(sm3.unhandleMsg, p...) + nblocks := len(msg) / sm3.BlockSize() + sm3.update(msg) + // Update unhandleMsg + sm3.unhandleMsg = msg[nblocks*sm3.BlockSize():] + + return toWrite, nil +} + +// 返回SM3哈希算法摘要值 +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (sm3 *SM3) Sum(in []byte) []byte { + _, _ = sm3.Write(in) + msg := sm3.pad() + //Finalize + digest := sm3.update2(msg) + + // save hash to in + needed := sm3.Size() + if cap(in)-len(in) < needed { + newIn := make([]byte, len(in), len(in)+needed) + copy(newIn, in) + in = newIn + } + out := in[len(in) : len(in)+needed] + for i := 0; i < 8; i++ { + binary.BigEndian.PutUint32(out[i*4:], digest[i]) + } + return out + +} + +func Sm3Sum(data []byte) []byte { + var sm3 SM3 + + sm3.Reset() + _, _ = sm3.Write(data) + return sm3.Sum(nil) +} diff --git a/sm3/sm3_test.go b/sm3/sm3_test.go new file mode 100644 index 0000000..16e0ee0 --- /dev/null +++ b/sm3/sm3_test.go @@ -0,0 +1,64 @@ +/* +Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sm3 + +import ( + "fmt" + "io/ioutil" + "os" + "testing" +) + +func byteToString(b []byte) string { + ret := "" + for i := 0; i < len(b); i++ { + ret += fmt.Sprintf("%02x", b[i]) + } + fmt.Println("ret = ", ret) + return ret +} +func TestSm3(t *testing.T) { + msg := []byte("test") + err := ioutil.WriteFile("ifile", msg, os.FileMode(0644)) // 生成测试文件 + if err != nil { + t.Fatal(err) + } + msg, err = ioutil.ReadFile("ifile") + if err != nil { + t.Fatal(err) + } + hw := New() + hw.Write(msg) + hash := hw.Sum(nil) + fmt.Println(hash) + fmt.Printf("hash = %d\n", len(hash)) + fmt.Printf("%s\n", byteToString(hash)) + hash1 := Sm3Sum(msg) + fmt.Println(hash1) + fmt.Printf("%s\n", byteToString(hash1)) + +} + +func BenchmarkSm3(t *testing.B) { + t.ReportAllocs() + msg := []byte("test") + hw := New() + for i := 0; i < t.N; i++ { + + hw.Sum(nil) + Sm3Sum(msg) + } +}