Skip to content

Commit

Permalink
feat:add rsa related functions
Browse files Browse the repository at this point in the history
  • Loading branch information
R22627 authored and R22627 committed Sep 6, 2023
1 parent 87f1f4d commit 63b8a72
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 10 deletions.
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ A modern, comprehensive and efficient utility library of Go.

- Comprehensive, efficient and reusable.
- Numerous util functions, support string, slice, map, datetime, crypto...
- Only depend on the go standard library.
- Only depend on the go standard and golang.org/x library.
- High unit test coverage for exported functions.

# Encoding
Expand Down Expand Up @@ -295,17 +295,24 @@ HMACSHA512("", "") // B936CEE86C9F87AA5D3C6F2E84CB5A4239A5FE50480A6EC66B70AB5B1F

// Encryption functions.
p := []byte("plaintext")
key16 := []byte("12345678abcdefgh")
c, _ := Base64AESCBCEncrypt(p, key16) // A67NhD3RBiNaMgG6HTm8LQ==
p, _ = Base64AESCBCDecrypt(c, key16) // plaintext

key8 := []byte("12345678")
c, _ := Base64DESCBCEncrypt(p, key8) // UZS/y4By6ksePYMBbvZdig==
p, _ := Base64DESCBCDecrypt(c, key8) // plaintext
Base64DESCBCEncrypt(p, key8) // UZS/y4By6ksePYMBbvZdig==
Base64DESCBCDecrypt(c, key8) // plaintext

key24 := []byte("12345678abcdefgh12345678")
c, _ := Base64TriDESCBCEncrypt(p, key24) // dau0DzmDGQbHasZaOvxxwg==
p, _ := Base64TriDESCBCDecrypt(c, key24) // plaintext
Base64TriDESCBCEncrypt(p, key24) // dau0DzmDGQbHasZaOvxxwg==
Base64TriDESCBCDecrypt(c, key24) // plaintext

key16 := []byte("12345678abcdefgh")
Base64AESCBCEncrypt(p, key16) // A67NhD3RBiNaMgG6HTm8LQ==
Base64AESCBCDecrypt(c, key16) // plaintext

// RSA encryption, decryption, sign and verify signature.
GenRsaKey(bits int) (prvkey, pubkey []byte, err error)
RsaEncrypt(pubkey, data []byte) ([]byte, error)
RsaDecrypt(prvkey, cipher []byte) ([]byte, error)
RsaSign(prvkey []byte, hash crypto.Hash, data []byte) ([]byte, error)
RsaVerifySign(pubkey []byte, hash crypto.Hash, data, sig []byte) error
```

# Rand
Expand Down
126 changes: 126 additions & 0 deletions crypto/rsa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package crypto

import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"encoding/pem"
"errors"
)

// GenRsaKey generates an PKCS#1 RSA keypair of the given bit size in PEM format.
func GenRsaKey(bits int) (prvkey, pubkey []byte, err error) {
// Generates private key.
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return
}
derStream := x509.MarshalPKCS1PrivateKey(privateKey)
block := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: derStream,
}
prvkey = pem.EncodeToMemory(block)

// Generates public key from private key.
publicKey := &privateKey.PublicKey
derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return
}
block = &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: derPkix,
}
pubkey = pem.EncodeToMemory(block)
return
}

// RsaEncrypt encrypts data using rsa public key.
func RsaEncrypt(pubkey, data []byte) ([]byte, error) {
block, _ := pem.Decode(pubkey)
if block == nil {
return nil, errors.New("decode public key error")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
return rsa.EncryptPKCS1v15(rand.Reader, pub.(*rsa.PublicKey), data)
}

// RsaDecrypt decrypts data using rsa private key.
func RsaDecrypt(prvkey, cipher []byte) ([]byte, error) {
block, _ := pem.Decode(prvkey)
if block == nil {
return nil, errors.New("decode private key error")
}
prv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return rsa.DecryptPKCS1v15(rand.Reader, prv, cipher)
}

// RsaSign signs using private key in PEM format.
func RsaSign(prvkey []byte, hash crypto.Hash, data []byte) ([]byte, error) {
block, _ := pem.Decode(prvkey)
if block == nil {
return nil, errors.New("decode private key error")
}
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}

// MD5 and SHA1 are not supported as they are not secure.
var hashed []byte
switch hash {
case crypto.SHA224:
h := sha256.Sum224(data)
hashed = h[:]
case crypto.SHA256:
h := sha256.Sum256(data)
hashed = h[:]
case crypto.SHA384:
h := sha512.Sum384(data)
hashed = h[:]
case crypto.SHA512:
h := sha512.Sum512(data)
hashed = h[:]
}
return rsa.SignPKCS1v15(rand.Reader, privateKey, hash, hashed)
}

// RsaVerifySign verifies signature using public key in PEM format.
func RsaVerifySign(pubkey []byte, hash crypto.Hash, data, sig []byte) error {
block, _ := pem.Decode(pubkey)
if block == nil {
return errors.New("decode public key error")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return err
}

// SHA1 and MD5 are not supported as they are not secure.
var hashed []byte
switch hash {
case crypto.SHA224:
h := sha256.Sum224(data)
hashed = h[:]
case crypto.SHA256:
h := sha256.Sum256(data)
hashed = h[:]
case crypto.SHA384:
h := sha512.Sum384(data)
hashed = h[:]
case crypto.SHA512:
h := sha512.Sum512(data)
hashed = h[:]
}
return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), hash, hashed, sig)
}
73 changes: 73 additions & 0 deletions crypto/rsa_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package crypto

import (
"crypto"
"testing"

"github.com/dablelv/go-huge-util/internal"
)

func TestRsaEncryptDecrypt(t *testing.T) {
assert := internal.NewAssert(t, "RsaEncryptDecrypt")

data := []byte("foo")

// Encrypt and decrypt data using 2048 bits length key.
prvkey, pubkey, err := GenRsaKey(2048)
assert.IsNil(err)

// Encrypt data.
cipher, err := RsaEncrypt(pubkey, data)
assert.IsNil(err)
assert.Equal(2048/8, len(cipher))

// Decrypt data.
plain, err := RsaDecrypt(prvkey, cipher)
assert.IsNil(err)
assert.Equal(data, plain)

// Encrypt and decrypt data using 4096 bits length key.
prvkey, pubkey, err = GenRsaKey(4096)
assert.IsNil(err)

// Encrypt data.
cipher, err = RsaEncrypt(pubkey, data)
assert.IsNil(err)
assert.Equal(4096/8, len(cipher))

// Decrypt data.
plain, err = RsaDecrypt(prvkey, cipher)
assert.IsNil(err)
assert.Equal(data, plain)

// Encrypt and decrypt data using 8192 bits length key.
prvkey, pubkey, err = GenRsaKey(8192)
assert.IsNil(err)

// Encrypt data.
cipher, err = RsaEncrypt(pubkey, data)
assert.IsNil(err)
assert.Equal(8192/8, len(cipher))

// Decrypt data.
plain, err = RsaDecrypt(prvkey, cipher)
assert.IsNil(err)
assert.Equal(data, plain)
}

func TestRsaSignAndVerify(t *testing.T) {
assert := internal.NewAssert(t, "RsaSignAndVerify")

msg := []byte("foo")
prvkey, pubkey, err := GenRsaKey(2048)
assert.IsNil(err)

// Using SHA256 to hash msg and then use rsa private key to sign.
sig, err := RsaSign(prvkey, crypto.SHA256, msg)
assert.IsNil(err)
assert.Equal(2048/8, len(sig))

// Using public key to verify signature.
err = RsaVerifySign(pubkey, crypto.SHA256, msg, sig)
assert.IsNil(err)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/dablelv/go-huge-util
module github.com/dablelv/cyan

go 1.19

Expand Down

0 comments on commit 63b8a72

Please sign in to comment.