-
Notifications
You must be signed in to change notification settings - Fork 41
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
Showing
2 changed files
with
202 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,117 @@ | ||
package crypto | ||
|
||
import ( | ||
"crypto" | ||
"crypto/hmac" | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/sha256" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
"strings" | ||
) | ||
|
||
// Signer is an interface that can be used to sign messages | ||
type Signer interface { | ||
Sign(msg []byte) ([]byte, error) | ||
} | ||
|
||
// SignFunc is a wrapper of sign functions to implement Signer interface | ||
type SignFunc func(msg []byte) ([]byte, error) | ||
|
||
func (sf SignFunc) Sign(msg []byte) ([]byte, error) { | ||
return sf(msg) | ||
} | ||
|
||
// NewSHA256WithRSASigner returns Signer instance which signs msg using SHA256WithRSA and private key | ||
func NewSHA256WithRSASigner(privateKey *rsa.PrivateKey) SignFunc { | ||
return func(msg []byte) ([]byte, error) { | ||
return SHA256WithRSA(msg, privateKey) | ||
} | ||
} | ||
|
||
// NewHMACSHA256Signer returns Signer instance which signs msg using HMACSHA256S and key | ||
func NewHMACSHA256Signer(key string) SignFunc { | ||
return func(msg []byte) ([]byte, error) { | ||
return HMACSHA256(msg, key) | ||
} | ||
} | ||
|
||
// SHA256WithRSA signs SHA256 hash of the message with RSA privateKey | ||
func SHA256WithRSA(msg []byte, privateKey *rsa.PrivateKey) ([]byte, error) { | ||
if privateKey == nil { | ||
return nil, errors.New("private key is empty") | ||
} | ||
|
||
h := sha256.New() | ||
_, err := h.Write(msg) | ||
if err != nil { | ||
return nil, fmt.Errorf("write bytes: %v", err) | ||
} | ||
|
||
res, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, h.Sum(nil)) | ||
if err != nil { | ||
return nil, fmt.Errorf("SignPKCS1v15: %v", err) | ||
} | ||
|
||
return res, nil | ||
} | ||
|
||
// HMACSHA256 signs message with HMAC SHA256 using key | ||
func HMACSHA256(msg []byte, key string) ([]byte, error) { | ||
h := hmac.New(sha256.New, []byte(key)) | ||
_, err := h.Write(msg) | ||
if err != nil { | ||
return nil, fmt.Errorf("hmac write: %v", err) | ||
} | ||
return h.Sum(nil), nil | ||
} | ||
|
||
// GetRSAPrivateKey reads RSA private key from the reader | ||
func GetRSAPrivateKey(reader io.Reader) (*rsa.PrivateKey, error) { | ||
bs, err := io.ReadAll(reader) | ||
if err != nil { | ||
return nil, fmt.Errorf("read bytes: %v", err) | ||
} | ||
|
||
privPem, _ := pem.Decode(bs) | ||
if privPem == nil { | ||
return nil, errors.New("decoded key is empty") | ||
} | ||
|
||
if privPem.Type != "RSA PRIVATE KEY" { | ||
return nil, errors.New("key type is not RSA private key") | ||
} | ||
|
||
var parsedKey interface{} | ||
parsedKey, err = x509.ParsePKCS1PrivateKey(privPem.Bytes) | ||
if err != nil { | ||
return nil, fmt.Errorf("parse PKCS1 private key: %v", err) | ||
} | ||
|
||
privateKey, ok := parsedKey.(*rsa.PrivateKey) | ||
if !ok { | ||
return nil, errors.New("parsed key is not RSA private key") | ||
} | ||
|
||
return privateKey, nil | ||
} | ||
|
||
// GetRSAPrivateKeyFromFile reads RSA private key from file | ||
func GetRSAPrivateKeyFromFile(fileName string) (*rsa.PrivateKey, error) { | ||
file, err := os.Open(fileName) | ||
if err != nil { | ||
return nil, fmt.Errorf("open file: %v", err) | ||
} | ||
|
||
return GetRSAPrivateKey(file) | ||
} | ||
|
||
// GetRSAPrivateKeyFromString reads RSA private key from string | ||
func GetRSAPrivateKeyFromString(s string) (*rsa.PrivateKey, error) { | ||
return GetRSAPrivateKey(strings.NewReader(s)) | ||
} |
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,85 @@ | ||
package crypto | ||
|
||
import ( | ||
"bytes" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"encoding/base64" | ||
"encoding/pem" | ||
"fmt" | ||
"os" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
var privateKey = `-----BEGIN RSA PRIVATE KEY----- | ||
MIIBOgIBAAJBAK1ASa283Iotdl+Sbp5IRNjumvuTs/r0ZSt1S/8dqe08WN2GiDXn | ||
f+U1UOJPDp5qN7d+AoQSMUg2bHXeLjrxxCUCAwEAAQJAcYfJQGKcmqfEBEju2CY/ | ||
h3CEewuFS5RPn7TTwi/sJJrtEkeha4CYgGJJusAr8K3J0O8EBnMtEz+KltYDWd6i | ||
AQIhANSWLwXtb0lUqemqoslj3RKirsHac30IyyiJ45NQWp5BAiEA0KGuouUQdNbL | ||
vso31iilbUnJJ54k1C8hREoEAqx9NOUCIQC5INByaQKw6XnOczqwBrdOsz1cs9A+ | ||
4pmJBAubDi7cAQIgOIFx4SCVQm/iovv1/4TmuSDg4GAOrYFOS0aYq3i4OJkCIAQw | ||
PklhQYvKRwjm1jiktUyTyRHIDSVSmveZ/8N6zJSW | ||
-----END RSA PRIVATE KEY----- | ||
` | ||
|
||
func testCompareKeys(t *testing.T, exp string, act *rsa.PrivateKey) { | ||
var buf bytes.Buffer | ||
assert.NoError(t, pem.Encode(&buf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(act)})) | ||
|
||
assert.Equal(t, exp, string(buf.Bytes())) | ||
} | ||
|
||
func TestGetRSAPrivateKey(t *testing.T) { | ||
key, err := GetRSAPrivateKey(strings.NewReader(privateKey)) | ||
assert.NoError(t, err) | ||
|
||
testCompareKeys(t, privateKey, key) | ||
} | ||
|
||
func TestHMACSHA256(t *testing.T) { | ||
res, err := HMACSHA256([]byte("test"), "e9a9b09e-6dfb-455e-8c27-7b206bec08a1") | ||
assert.NoError(t, err) | ||
assert.Equal( | ||
t, | ||
"9e99537c0a09c501bb348bc12743707beee35eba0b1bd885de15f91bc9311047", | ||
fmt.Sprintf("%x", string(res)), | ||
) | ||
} | ||
|
||
func TestSHA256WithRSA(t *testing.T) { | ||
key, err := GetRSAPrivateKey(strings.NewReader(privateKey)) | ||
assert.NoError(t, err) | ||
|
||
res, err := SHA256WithRSA([]byte("test"), key) | ||
assert.NoError(t, err) | ||
assert.Equal( | ||
t, | ||
"dUiTbTPRbMhL0GyTuAE+BAbSxfEwdbWdzQuF2r3esVKg0CMtEa2btCN7O0eQezQFDRIQVXmhKRccqWPQw/Zjbw==", | ||
base64.StdEncoding.EncodeToString(res), | ||
) | ||
} | ||
|
||
func TestGetRSAPrivateKeyFromFile(t *testing.T) { | ||
f, err := os.CreateTemp("", "test") | ||
assert.NoError(t, err) | ||
defer os.Remove(f.Name()) | ||
|
||
_, err = f.Write([]byte(privateKey)) | ||
assert.NoError(t, err) | ||
assert.NoError(t, f.Sync()) | ||
|
||
key, err := GetRSAPrivateKeyFromFile(f.Name()) | ||
assert.NoError(t, err) | ||
|
||
testCompareKeys(t, privateKey, key) | ||
} | ||
|
||
func TestGetRSAPrivateKeyFromString(t *testing.T) { | ||
key, err := GetRSAPrivateKeyFromString(privateKey) | ||
assert.NoError(t, err) | ||
|
||
testCompareKeys(t, privateKey, key) | ||
} |