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) + } +}