-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e6ece0c
commit 025af96
Showing
2 changed files
with
298 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package utils | ||
|
||
import ( | ||
"crypto" | ||
"crypto/hmac" | ||
"crypto/md5" | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/sha1" | ||
"crypto/x509" | ||
"encoding/base64" | ||
"encoding/hex" | ||
"hash" | ||
"io" | ||
rand2 "math/rand" | ||
"net/url" | ||
"time" | ||
) | ||
|
||
type uuid [16]byte | ||
|
||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||
|
||
var hookRead = func(fn func(p []byte) (n int, err error)) func(p []byte) (n int, err error) { | ||
return fn | ||
} | ||
|
||
var hookRSA = func(fn func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)) func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) { | ||
return fn | ||
} | ||
|
||
// GetUUID returns a uuid | ||
func GetUUID() (uuidHex string) { | ||
uuid := newUUID() | ||
uuidHex = hex.EncodeToString(uuid[:]) | ||
return | ||
} | ||
|
||
// RandStringBytes returns a rand string | ||
func RandStringBytes(n int) string { | ||
b := make([]byte, n) | ||
for i := range b { | ||
b[i] = letterBytes[rand2.Intn(len(letterBytes))] | ||
} | ||
return string(b) | ||
} | ||
|
||
// ShaHmac1 return a string which has been hashed | ||
func ShaHmac1(source, secret string) string { | ||
key := []byte(secret) | ||
hmac := hmac.New(sha1.New, key) | ||
hmac.Write([]byte(source)) | ||
signedBytes := hmac.Sum(nil) | ||
signedString := base64.StdEncoding.EncodeToString(signedBytes) | ||
return signedString | ||
} | ||
|
||
// Sha256WithRsa return a string which has been hashed with Rsa | ||
func Sha256WithRsa(source, secret string) string { | ||
decodeString, err := base64.StdEncoding.DecodeString(secret) | ||
if err != nil { | ||
panic(err) | ||
} | ||
private, err := x509.ParsePKCS8PrivateKey(decodeString) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
h := crypto.Hash.New(crypto.SHA256) | ||
h.Write([]byte(source)) | ||
hashed := h.Sum(nil) | ||
signature, err := hookRSA(rsa.SignPKCS1v15)(rand.Reader, private.(*rsa.PrivateKey), | ||
crypto.SHA256, hashed) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
return base64.StdEncoding.EncodeToString(signature) | ||
} | ||
|
||
// GetMD5Base64 returns a string which has been base64 | ||
func GetMD5Base64(bytes []byte) (base64Value string) { | ||
md5Ctx := md5.New() | ||
md5Ctx.Write(bytes) | ||
md5Value := md5Ctx.Sum(nil) | ||
base64Value = base64.StdEncoding.EncodeToString(md5Value) | ||
return | ||
} | ||
|
||
// GetTimeInFormatISO8601 returns a time string | ||
func GetTimeInFormatISO8601() (timeStr string) { | ||
gmt := time.FixedZone("GMT", 0) | ||
|
||
return time.Now().In(gmt).Format("2006-01-02T15:04:05Z") | ||
} | ||
|
||
// GetURLFormedMap returns a url encoded string | ||
func GetURLFormedMap(source map[string]string) (urlEncoded string) { | ||
urlEncoder := url.Values{} | ||
for key, value := range source { | ||
urlEncoder.Add(key, value) | ||
} | ||
urlEncoded = urlEncoder.Encode() | ||
return | ||
} | ||
|
||
func newUUID() uuid { | ||
ns := uuid{} | ||
safeRandom(ns[:]) | ||
u := newFromHash(md5.New(), ns, RandStringBytes(16)) | ||
u[6] = (u[6] & 0x0f) | (byte(2) << 4) | ||
u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) | ||
|
||
return u | ||
} | ||
|
||
func newFromHash(h hash.Hash, ns uuid, name string) uuid { | ||
u := uuid{} | ||
h.Write(ns[:]) | ||
h.Write([]byte(name)) | ||
copy(u[:], h.Sum(nil)) | ||
|
||
return u | ||
} | ||
|
||
func safeRandom(dest []byte) { | ||
if _, err := hookRead(rand.Read)(dest); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func (u uuid) String() string { | ||
buf := make([]byte, 36) | ||
|
||
hex.Encode(buf[0:8], u[0:4]) | ||
buf[8] = '-' | ||
hex.Encode(buf[9:13], u[4:6]) | ||
buf[13] = '-' | ||
hex.Encode(buf[14:18], u[6:8]) | ||
buf[18] = '-' | ||
hex.Encode(buf[19:23], u[8:10]) | ||
buf[23] = '-' | ||
hex.Encode(buf[24:], u[10:]) | ||
|
||
return string(buf) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package utils | ||
|
||
import ( | ||
"crypto" | ||
"crypto/rsa" | ||
"errors" | ||
"io" | ||
"regexp" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGetUUID(t *testing.T) { | ||
uuid := newUUID() | ||
assert.Equal(t, 16, len(uuid)) | ||
assert.Equal(t, 36, len(uuid.String())) | ||
uuidString := GetUUID() | ||
assert.Equal(t, 32, len(uuidString)) | ||
} | ||
|
||
func TestGetMD5Base64(t *testing.T) { | ||
assert.Equal(t, "ERIHLmRX2uZmssDdxQnnxQ==", | ||
GetMD5Base64([]byte("That's all folks!!"))) | ||
assert.Equal(t, "GsJRdI3kAbAnHo/0+3wWJw==", | ||
GetMD5Base64([]byte("中文也没啥问题"))) | ||
} | ||
|
||
func TestGetTimeInFormatISO8601(t *testing.T) { | ||
s := GetTimeInFormatISO8601() | ||
assert.Equal(t, 20, len(s)) | ||
// 2006-01-02T15:04:05Z | ||
re := regexp.MustCompile(`^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$`) | ||
assert.True(t, re.MatchString(s)) | ||
} | ||
|
||
func TestGetURLFormedMap(t *testing.T) { | ||
m := make(map[string]string) | ||
m["key"] = "value" | ||
s := GetURLFormedMap(m) | ||
assert.Equal(t, "key=value", s) | ||
m["key2"] = "http://domain/?key=value&key2=value2" | ||
s2 := GetURLFormedMap(m) | ||
assert.Equal(t, "key=value&key2=http%3A%2F%2Fdomain%2F%3Fkey%3Dvalue%26key2%3Dvalue2", s2) | ||
} | ||
|
||
func TestShaHmac1(t *testing.T) { | ||
result := ShaHmac1("source", "secret") | ||
assert.Equal(t, "Jv4yi8SobFhg5t1C7nWLbhBSFZQ=", result) | ||
|
||
assert.Equal(t, "CqCYIa39h9SSWuXnTz8F5hh9UPA=", ShaHmac1("中文", "secret")) | ||
} | ||
|
||
func TestSha256WithRsa(t *testing.T) { | ||
secret := ` | ||
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOJC+2WXtkXZ+6sa | ||
3+qJp4mDOsiZb3BghHT9nVbjTeaw4hsZWHYxQ6l6XDmTg4twPB59LOGAlAjYrT31 | ||
3pdwEawnmdf6zyF93Zvxxpy7lO2HoxYKSjbtXO4I0pcq3WTnw2xlbhqHvrcuWwt+ | ||
FqH9akzcnwHjc03siZBzt/dwDL3vAgMBAAECgYEAzwgZPqFuUEYgaTVDFDl2ynYA | ||
kNMMzBgUu3Pgx0Nf4amSitdLQYLcdbQXtTtMT4eYCxHgwkpDqkCRbLOQRKNwFo0I | ||
oaCuhjZlxWcKil4z4Zb/zB7gkeuXPOVUjFSS3FogsRWMtnNAMgR/yJRlbcg/Puqk | ||
Magt/yDk+7cJCe6H96ECQQDxMT4S+tVP9nOw//QT39Dk+kWe/YVEhnWnCMZmGlEq | ||
1gnN6qpUi68ts6b3BVgrDPrPN6wm/Z9vpcKNeWpIvxXRAkEA8CcT2UEUwDGRKAUu | ||
WVPJqdAJjpjc072eRF5g792NyO+TAF6thBlDKNslRvFQDB6ymLsjfy8JYCnGbbSb | ||
WqbHvwJBAIs7KeI6+jiWxGJA3t06LpSABQCqyOut0u0Bm8YFGyXnOPGtrXXwzMdN | ||
Fe0zIJp5e69zK+W2Mvt4bL7OgBROeoECQQDsE+4uLw0gFln0tosmovhmp60NcfX7 | ||
bLbtzL2MbwbXlbOztF7ssgzUWAHgKI6hK3g0LhsqBuo3jzmSVO43giZvAkEA08Nm | ||
2TI9EvX6DfCVfPOiKZM+Pijh0xLN4Dn8qUgt3Tcew/vfj4WA2ZV6qiJqL01vMsHc | ||
vftlY0Hs1vNXcaBgEA==` | ||
result := Sha256WithRsa("source", secret) | ||
assert.Equal(t, "UNyJPD27jjSNl70b02E/DUtgtNESdtAuxbNBZTlksk1t/GYjiQNRlFIubp/EGKcWsqs7p5SFKnNiSRqWG3A51VmJFBXXtyW1nwLC9xY/MbUj6JVWNYCuLkPWM942O+GAk7N+G8ZQZt7ib2MhruDAUmv1lLN26lDaCPBX2MJQJCo=", result) | ||
|
||
assert.Equal(t, "CKE0osxUnFFH+oYP3Q427saucBuignE+Mrni63G9w46yZFtVoXFOu5lNiNCnUtaPNpGmBf9X5oGCY+otqPf7bP93nB59rfdteQs0sS65PWH9yjH8RwYCWGCbuyRul/0qIv/nYYGzkLON1C1Vx9Z4Yep6llYuJang5RIXrAkQLmQ=", Sha256WithRsa("中文", secret)) | ||
} | ||
|
||
func TestSha256WithRsa_DecodeString_Error(t *testing.T) { | ||
defer func() { // 进行异常捕捉 | ||
err := recover() | ||
assert.NotNil(t, err) | ||
assert.Equal(t, "illegal base64 data at input byte 0", err.(error).Error()) | ||
}() | ||
secret := `==` | ||
Sha256WithRsa("source", secret) | ||
} | ||
|
||
func TestSha256WithRsa_ParsePKCS8PrivateKey_Error(t *testing.T) { | ||
defer func() { // 进行异常捕捉 | ||
err := recover() | ||
assert.NotNil(t, err) | ||
assert.Equal(t, "asn1: structure error: length too large", err.(error).Error()) | ||
}() | ||
secret := `Jv4yi8SobFhg5t1C7nWLbhBSFZQ=` | ||
Sha256WithRsa("source", secret) | ||
} | ||
|
||
func TestHookRead(t *testing.T) { | ||
fn := func(p []byte) (n int, err error) { | ||
return 0, errors.New("hookRead") | ||
} | ||
result := hookRead(fn) | ||
n, err := result(nil) | ||
assert.Equal(t, 0, n) | ||
assert.Equal(t, "hookRead", err.Error()) | ||
|
||
originHookRead := hookRead | ||
hookRead = func(old func(p []byte) (n int, err error)) func(p []byte) (n int, err error) { | ||
return fn | ||
} | ||
defer func() { | ||
err := recover() | ||
assert.Equal(t, "hookRead", err.(error).Error()) | ||
hookRead = originHookRead | ||
}() | ||
safeRandom([]byte("credentialtest")) | ||
} | ||
|
||
func TestHookRSA(t *testing.T) { | ||
fn := func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) { | ||
return nil, errors.New("hookRSA") | ||
} | ||
result := hookRSA(fn) | ||
hash := crypto.Hash(10) | ||
byt, err := result(nil, nil, hash, nil) | ||
assert.Nil(t, byt) | ||
assert.Equal(t, "hookRSA", err.Error()) | ||
|
||
originHookRSA := hookRSA | ||
hookRSA = func(old func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)) func(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) { | ||
return fn | ||
} | ||
defer func() { | ||
err := recover() | ||
assert.Equal(t, "hookRSA", err.(error).Error()) | ||
hookRSA = originHookRSA | ||
}() | ||
secret := ` | ||
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOJC+2WXtkXZ+6sa | ||
3+qJp4mDOsiZb3BghHT9nVbjTeaw4hsZWHYxQ6l6XDmTg4twPB59LOGAlAjYrT31 | ||
3pdwEawnmdf6zyF93Zvxxpy7lO2HoxYKSjbtXO4I0pcq3WTnw2xlbhqHvrcuWwt+ | ||
FqH9akzcnwHjc03siZBzt/dwDL3vAgMBAAECgYEAzwgZPqFuUEYgaTVDFDl2ynYA | ||
kNMMzBgUu3Pgx0Nf4amSitdLQYLcdbQXtTtMT4eYCxHgwkpDqkCRbLOQRKNwFo0I | ||
oaCuhjZlxWcKil4z4Zb/zB7gkeuXPOVUjFSS3FogsRWMtnNAMgR/yJRlbcg/Puqk | ||
Magt/yDk+7cJCe6H96ECQQDxMT4S+tVP9nOw//QT39Dk+kWe/YVEhnWnCMZmGlEq | ||
1gnN6qpUi68ts6b3BVgrDPrPN6wm/Z9vpcKNeWpIvxXRAkEA8CcT2UEUwDGRKAUu | ||
WVPJqdAJjpjc072eRF5g792NyO+TAF6thBlDKNslRvFQDB6ymLsjfy8JYCnGbbSb | ||
WqbHvwJBAIs7KeI6+jiWxGJA3t06LpSABQCqyOut0u0Bm8YFGyXnOPGtrXXwzMdN | ||
Fe0zIJp5e69zK+W2Mvt4bL7OgBROeoECQQDsE+4uLw0gFln0tosmovhmp60NcfX7 | ||
bLbtzL2MbwbXlbOztF7ssgzUWAHgKI6hK3g0LhsqBuo3jzmSVO43giZvAkEA08Nm | ||
2TI9EvX6DfCVfPOiKZM+Pijh0xLN4Dn8qUgt3Tcew/vfj4WA2ZV6qiJqL01vMsHc | ||
vftlY0Hs1vNXcaBgEA==` | ||
Sha256WithRsa("source", secret) | ||
} |