You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
starainrt/crypto.go

847 lines
18 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package starainrt
import (
"bufio"
"crypto"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"hash"
"hash/crc32"
"io"
"io/ioutil"
rands "math/rand"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
)
// StarCrypto 存储了单个校验方法的非编码元数据
type StarCrypto struct {
Sha1 []byte
Sha224 []byte
Sha256 []byte
Sha386 []byte
Sha512 []byte
Crc32 []byte
Md5 []byte
}
// Base64Encode 输出格式化后的Base64字符串
func (starcpto StarCrypto) Base64Encode(bstr []byte) string {
return base64.StdEncoding.EncodeToString(bstr)
}
// Base64Decode 输出解密前的Base64数据
func (starcpto StarCrypto) Base64Decode(str string) ([]byte, error) {
return base64.StdEncoding.DecodeString(str)
}
// MD5 输出MD5校验值
func (starcpto *StarCrypto) MD5(bstr []byte) string {
md5sum := md5.New()
md5sum.Write(bstr)
starcpto.Md5 = md5sum.Sum(nil)
return hex.EncodeToString(starcpto.Md5)
}
// CRC32 输出CRC32校验值
func (starcpto *StarCrypto) CRC32(bstr []byte) string {
crcsum := crc32.NewIEEE()
crcsum.Write(bstr)
starcpto.Crc32 = crcsum.Sum(nil)
return hex.EncodeToString(starcpto.Crc32)
}
// SHA512 输出SHA512校验值
func (starcpto *StarCrypto) SHA512(bstr []byte) string {
shasum := sha512.New()
shasum.Write(bstr)
starcpto.Sha512 = shasum.Sum(nil)
return hex.EncodeToString(starcpto.Sha512)
}
// SHA256 输出SHA256校验值
func (starcpto *StarCrypto) SHA256(bstr []byte) string {
shasum := sha256.New()
shasum.Write(bstr)
starcpto.Sha256 = shasum.Sum(nil)
return hex.EncodeToString(starcpto.Sha256)
}
// SHA1 输出SHA1校验值
func (starcpto *StarCrypto) SHA1(bstr []byte) string {
shasum := sha1.New()
shasum.Write(bstr)
starcpto.Sha1 = shasum.Sum(nil)
return hex.EncodeToString(starcpto.Sha1)
}
// SumAll 可以对同一数据进行多种校验
func (starcpto StarCrypto) SumAll(data []byte, method []string) (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"}
}
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] = hex.EncodeToString(v.Sum(nil))
}
if iscrc {
result["crc32"] = hex.EncodeToString(crcsum.Sum(nil))
}
return result, nil
}
// FileSum 输出文件内容校验值method为单个校验方法,小写
//例FileSum("./test.txt","md5",shell(pect float64){fmt.Sprintf("已完成 %f\r",pect)})
func (starcpto StarCrypto) FileSum(filepath, method string, shell func(float64)) (string, error) {
var sum hash.Hash
var sum32 hash.Hash32
var issum32 bool
var result string
if !Exists(filepath) {
return "", errors.New("file not exists")
}
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 (starcpto StarCrypto) 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"}
}
if !Exists(filepath) {
return result, errors.New("file not exists")
}
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 (starcpto StarCrypto) Attach(src, dst, output string) error {
if !Exists(src) {
return errors.New("source file not exists")
}
if !Exists(dst) {
return errors.New("dst file not exists")
}
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 (starcpto StarCrypto) Detach(src string, bytenum int, dst1, dst2 string) error {
if !Exists(src) {
return errors.New("source file not exists")
}
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
}
// Base64EncodeFile 用base64方法编码src文件到dst文件中去shell传入当前进度
func (starcpto StarCrypto) Base64EncodeFile(src, dst string, shell func(float64)) error {
if !Exists(src) {
return errors.New("source file not exists")
}
fpsrc, err := os.Open(src)
if err != nil {
return err
}
defer fpsrc.Close()
stat, _ := os.Stat(src)
filebig := float64(stat.Size())
sum := 0
fpdst, err := os.Create(dst)
if err != nil {
return err
}
defer fpdst.Close()
b64 := base64.NewEncoder(base64.StdEncoding, fpdst)
for {
buf := make([]byte, 1048575)
n, err := fpsrc.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return err
}
sum += n
go shell(float64(sum) / filebig * 100)
b64.Write(buf[0:n])
}
return nil
}
// Base64DecodeFile 用base64方法解码src文件到dst文件中去shell传入当前进度
func (starcpto StarCrypto) Base64DecodeFile(src, dst string, shell func(float64)) error {
if !Exists(src) {
return errors.New("source file not exists")
}
fpsrc, err := os.Open(src)
if err != nil {
return err
}
defer fpsrc.Close()
stat, _ := os.Stat(src)
filebig := float64(stat.Size())
sum := 0
defer fpsrc.Close()
fpdst, err := os.Create(dst)
if err != nil {
return err
}
defer fpdst.Close()
b64 := base64.NewDecoder(base64.StdEncoding, fpsrc)
for {
buf := make([]byte, 1048576)
n, err := b64.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return err
}
sum += n
go shell(float64(sum) / filebig * 100)
fpdst.Write(buf[0:n])
}
return nil
}
// SplitFile 把src文件按要求分割到dst中去,dst应传入带*号字符串
// 如果bynum=true 则把文件分割成num份
// 如果bynum=false 则把文件按num字节分成多份
func (starcpto StarCrypto) SplitFile(src, dst string, num int, bynum bool, shell func(float64)) error {
if !Exists(src) {
return errors.New("source file not exists")
}
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 (starcpto StarCrypto) 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
}
sum := 0
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 += n
go shell(float64(sum) / filebig * 100)
fpdst.Write(buf[0:n])
}
fpsrc.Close()
}
return nil
}
// RSAEncrypt RSA公钥加密
func (starcpto StarCrypto) RSAEncrypt(data, public []byte) ([]byte, error) {
blk, _ := pem.Decode(public)
if blk == nil {
return []byte{}, errors.New("public key error")
}
pubkey, err := x509.ParsePKIXPublicKey(blk.Bytes)
if err != nil {
return []byte{}, err
}
return rsa.EncryptPKCS1v15(rand.Reader, pubkey.(*rsa.PublicKey), data)
}
// RSADecrypt RSA私钥解密
func (starcpto StarCrypto) RSADecrypt(data, private []byte, password string) ([]byte, error) {
var prikey *rsa.PrivateKey
var err error
var bytes []byte
blk, _ := pem.Decode(private)
if blk == nil {
return []byte{}, errors.New("private key error")
}
if password != "" {
tmp, err := x509.DecryptPEMBlock(blk, []byte(password))
if err != nil {
return []byte{}, err
}
bytes = tmp
} else {
bytes = blk.Bytes
}
prikey, err = x509.ParsePKCS1PrivateKey(bytes)
if err != nil {
tmp, err := x509.ParsePKCS8PrivateKey(bytes)
if err != nil {
return []byte{}, err
}
prikey = tmp.(*rsa.PrivateKey)
}
return rsa.DecryptPKCS1v15(rand.Reader, prikey, data)
}
// RSASign RSA私钥签名加密
func (starcpto StarCrypto) RSASign(hashdata, private []byte, password string, hashtype crypto.Hash) ([]byte, error) {
var prikey *rsa.PrivateKey
var err error
var bytes []byte
blk, _ := pem.Decode(private)
if blk == nil {
return []byte{}, errors.New("private key error")
}
if password != "" {
tmp, err := x509.DecryptPEMBlock(blk, []byte(password))
if err != nil {
return []byte{}, err
}
bytes = tmp
} else {
bytes = blk.Bytes
}
prikey, err = x509.ParsePKCS1PrivateKey(bytes)
if err != nil {
tmp, err := x509.ParsePKCS8PrivateKey(bytes)
if err != nil {
return []byte{}, err
}
prikey = tmp.(*rsa.PrivateKey)
}
return rsa.SignPKCS1v15(rand.Reader, prikey, hashtype, hashdata)
}
// RSAVerify RSA公钥签名验证
func (starcpto StarCrypto) RSAVerify(data, hashdata, public []byte, hashtype crypto.Hash) error {
blk, _ := pem.Decode(public)
if blk == nil {
return errors.New("public key error")
}
pubkey, err := x509.ParsePKIXPublicKey(blk.Bytes)
if err != nil {
return err
}
return rsa.VerifyPKCS1v15(pubkey.(*rsa.PublicKey), hashtype, hashdata, data)
}
// VicqueEncodeV1 Best
func (starcpto StarCrypto) VicqueEncodeV1(srcdata []byte, key string) []byte {
var keys []int
var saku, piku 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))
lens := len(data)
for _, v := range key {
keys = append(keys, int(byte(v))+int(saku)-int(piku))
}
lenkey := len(keys)
for k, v := range data {
if k == lens/2 {
break
}
nv := int(v)
t := 0
if k%2 == 0 {
nv += keys[k%lenkey]
if nv > 255 {
nv -= 256
}
t = int(data[lens-1-k])
t += keys[k%lenkey]
if t > 255 {
t -= 256
}
} else {
nv -= keys[k%lenkey]
if nv < 0 {
nv += 256
}
t = int(data[lens-1-k])
t -= keys[k%lenkey]
if t > 255 {
t += 256
}
}
data[k] = byte(t)
data[lens-1-k] = byte(nv)
}
data = append(data, byte(saku), byte(piku))
return data
}
// VicqueDecodeV1 Best
func (starcpto StarCrypto) VicqueDecodeV1(srcdata []byte, key string) []byte {
var keys []int
var saku, piku 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))
for _, v := range key {
keys = append(keys, int(byte(v))+int(saku)-int(piku))
}
lenkey := len(keys)
lens -= 2
for k, v := range data {
if k == lens/2 {
break
}
nv := int(v)
t := 0
if k%2 == 0 {
nv -= keys[k%lenkey]
if nv < 0 {
nv += 256
}
t = int(data[lens-1-k])
t -= keys[k%lenkey]
if t > 255 {
t += 256
}
} else {
nv += keys[k%lenkey]
if nv > 255 {
nv -= 256
}
t = int(data[lens-1-k])
t += keys[k%lenkey]
if t > 255 {
t -= 256
}
}
data[k] = byte(t)
data[lens-1-k] = byte(nv)
}
return data[:lens]
}
// VicqueEncodeV1File best
func (starcpto StarCrypto) VicqueEncodeV1File(src, dst, pwd string, 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())
sum := 0
defer fpsrc.Close()
fpdst, err := os.Create(dst)
if err != nil {
return err
}
defer fpdst.Close()
for {
buf := make([]byte, 1048576)
n, err := fpsrc.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return err
}
sum += n
go shell(float64(sum) / filebig * 100)
data := starcpto.VicqueEncodeV1(buf[0:n], pwd)
fpdst.Write(data)
}
return nil
}
// VicqueDecodeV1File best
func (starcpto StarCrypto) VicqueDecodeV1File(src, dst, pwd string, 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())
sum := 0
defer fpsrc.Close()
fpdst, err := os.Create(dst)
if err != nil {
return err
}
defer fpdst.Close()
for {
buf := make([]byte, 1048578)
n, err := fpsrc.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return err
}
sum += n
go shell(float64(sum) / filebig * 100)
data := starcpto.VicqueDecodeV1(buf[0:n], pwd)
fpdst.Write(data)
}
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
}