diff --git a/README.md b/README.md index 0f9c55c..1b7fac7 100755 --- a/README.md +++ b/README.md @@ -5,6 +5,11 @@ A functions wrapping of OpenSSL library for symmetric and asymmetric encryption and decryption +- [AES](#AES) +- [DES](#DES) +- [3DES](#DES) +- [RSA](#RSA) + ## Installation The only requirement is the [Go Programming Language](https://golang.org/dl/) @@ -80,6 +85,19 @@ openssl.Des3CBCEncrypt(src, key, iv, openssl.PKCS7_PADDING) openssl.Des3CBCDecrypt(src, key, iv, openssl.PKCS7_PADDING) ``` +### RSA + +```go +openssl.RSAGenerateKey(bits int, out io.Writer) +openssl.RSAGeneratePublicKey(priKey []byte, out io.Writer) + +openssl.RSAEncrypt(src, pubKey []byte) ([]byte, error) +openssl.RSADecrypt(src, priKey []byte) ([]byte, error) + +openssl.RSASign(src []byte, priKey []byte) ([]byte, error) +openssl.RSAVerify(src, sign, pubKey []byte) error +``` + ## License This project is licensed under the [Apache 2.0 license](LICENSE). diff --git a/rsa.go b/rsa.go new file mode 100644 index 0000000..0687ba2 --- /dev/null +++ b/rsa.go @@ -0,0 +1,133 @@ +package openssl + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/pem" + "errors" + "io" +) + +// RSAGenerateKey generate RSA private key +func RSAGenerateKey(bits int, out io.Writer) error { + privateKey, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return err + } + + X509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey) + + privateBlock := pem.Block{Type: "RSA PRIVATE KEY", Bytes: X509PrivateKey} + + return pem.Encode(out, &privateBlock) +} + +// RSAGeneratePublicKey generate RSA public key +func RSAGeneratePublicKey(priKey []byte, out io.Writer) error { + block, _ := pem.Decode(priKey) + // x509 parse + privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return err + } + publicKey := privateKey.PublicKey + X509PublicKey, err := x509.MarshalPKIXPublicKey(&publicKey) + if err != nil { + return err + } + + publicBlock := pem.Block{Type: "RSA PUBLIC KEY", Bytes: X509PublicKey} + + return pem.Encode(out, &publicBlock) +} + +// RSAEncrypt RSA encrypt +func RSAEncrypt(src, pubKey []byte) ([]byte, error) { + block, _ := pem.Decode(pubKey) + // x509 parse + publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, err + } + + publicKey, ok := publicKeyInterface.(*rsa.PublicKey) + if !ok { + return nil, errors.New("the kind of key is not a rsa.PublicKey") + } + // encrypt + dst, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, src) + if err != nil { + return nil, err + } + + return dst, nil +} + +// RSADecrypt RSA decrypt +func RSADecrypt(src, priKey []byte) ([]byte, error) { + block, _ := pem.Decode(priKey) + // x509 parse + privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + dst, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, src) + if err != nil { + return nil, err + } + + return dst, nil +} + +// RSASign RSA sign, use crypto.SHA256 +func RSASign(src []byte, priKey []byte) ([]byte, error) { + block, _ := pem.Decode(priKey) + // x509 parse + privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + hash := sha256.New() + _, err = hash.Write(src) + if err != nil { + return nil, err + } + + bytes := hash.Sum(nil) + sign, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, bytes) + if err != nil { + return nil, err + } + + return sign, nil +} + +// RSAVerify RSA Verify +func RSAVerify(src, sign, pubKey []byte) error { + block, _ := pem.Decode(pubKey) + // x509 parse + publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return err + } + + publicKey, ok := publicKeyInterface.(*rsa.PublicKey) + if !ok { + return errors.New("the kind of key is not a rsa.PublicKey") + } + + hash := sha256.New() + _, err = hash.Write(src) + if err != nil { + return err + } + + bytes := hash.Sum(nil) + + return rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, bytes, sign) +} diff --git a/rsa_test.go b/rsa_test.go new file mode 100644 index 0000000..5b4c8cb --- /dev/null +++ b/rsa_test.go @@ -0,0 +1,52 @@ +package openssl + +import ( + "bytes" + "encoding/base64" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestRSAEncrypt(t *testing.T) { + priBuf := bytes.NewBuffer(nil) + err := RSAGenerateKey(2048, priBuf) + assert.NoError(t, err) + t.Logf("private key: %s\n", priBuf.Bytes()) + + pubBuf := bytes.NewBuffer(nil) + err = RSAGeneratePublicKey(priBuf.Bytes(), pubBuf) + assert.NoError(t, err) + t.Logf("public key: %s\n", pubBuf.Bytes()) + + src := []byte("123456") + dst, err := RSAEncrypt(src, pubBuf.Bytes()) + assert.NoError(t, err) + t.Logf("encrypt out: %s\n", base64.RawStdEncoding.EncodeToString(dst)) + + dst, err = RSADecrypt(dst, priBuf.Bytes()) + assert.NoError(t, err) + + assert.Equal(t, src, dst) + + t.Logf("src: %s \ndst:%s", src, dst) +} + +func TestRSASign(t *testing.T) { + priBuf := bytes.NewBuffer(nil) + err := RSAGenerateKey(2048, priBuf) + assert.NoError(t, err) + t.Logf("private key: %s\n", priBuf.Bytes()) + + pubBuf := bytes.NewBuffer(nil) + err = RSAGeneratePublicKey(priBuf.Bytes(), pubBuf) + assert.NoError(t, err) + t.Logf("public key: %s\n", pubBuf.Bytes()) + + src := []byte("123456") + sign, err := RSASign(src, priBuf.Bytes()) + assert.NoError(t, err) + t.Logf("sign out: %s\n", base64.RawStdEncoding.EncodeToString(sign)) + + err = RSAVerify(src, sign, pubBuf.Bytes()) + assert.NoError(t, err) +} \ No newline at end of file