|
|
package starcrypto
|
|
|
|
|
|
import (
|
|
|
"crypto"
|
|
|
"crypto/rand"
|
|
|
"crypto/rsa"
|
|
|
"crypto/x509"
|
|
|
"encoding/pem"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
"math/big"
|
|
|
)
|
|
|
|
|
|
func GenerateRsaKey(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
|
|
private, err := rsa.GenerateKey(rand.Reader, bits)
|
|
|
if err != nil {
|
|
|
return nil, nil, err
|
|
|
}
|
|
|
return private, &private.PublicKey, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
func EncodeRsaPrivateKey(private *rsa.PrivateKey, secret string) ([]byte, error) {
|
|
|
if secret == "" {
|
|
|
return pem.EncodeToMemory(&pem.Block{
|
|
|
Bytes: x509.MarshalPKCS1PrivateKey(private),
|
|
|
Type: "RSA PRIVATE KEY",
|
|
|
}), nil
|
|
|
}
|
|
|
chiper := x509.PEMCipherAES256
|
|
|
blk, err := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(private), []byte(secret), chiper)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return pem.EncodeToMemory(blk), err
|
|
|
}
|
|
|
|
|
|
func EncodeRsaPublicKey(public *rsa.PublicKey) ([]byte, error) {
|
|
|
publicBytes, err := x509.MarshalPKIXPublicKey(public)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return pem.EncodeToMemory(&pem.Block{
|
|
|
Bytes: publicBytes,
|
|
|
Type: "PUBLIC KEY",
|
|
|
}), nil
|
|
|
}
|
|
|
|
|
|
func DecodeRsaPrivateKey(private []byte, password string) (*rsa.PrivateKey, error) {
|
|
|
var prikey *rsa.PrivateKey
|
|
|
var err error
|
|
|
var bytes []byte
|
|
|
blk, _ := pem.Decode(private)
|
|
|
if blk == nil {
|
|
|
return nil, errors.New("private key error!")
|
|
|
}
|
|
|
if password != "" {
|
|
|
tmp, err := x509.DecryptPEMBlock(blk, []byte(password))
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
bytes = tmp
|
|
|
} else {
|
|
|
bytes = blk.Bytes
|
|
|
}
|
|
|
prikey, err = x509.ParsePKCS1PrivateKey(bytes)
|
|
|
if err != nil {
|
|
|
tmp, err := x509.ParsePKCS8PrivateKey(bytes)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
prikey = tmp.(*rsa.PrivateKey)
|
|
|
}
|
|
|
return prikey, err
|
|
|
}
|
|
|
|
|
|
func DecodeRsaPublicKey(pubStr []byte) (*rsa.PublicKey, error) {
|
|
|
blk, _ := pem.Decode(pubStr)
|
|
|
if blk == nil {
|
|
|
return nil, errors.New("public key error")
|
|
|
}
|
|
|
pub, err := x509.ParsePKIXPublicKey(blk.Bytes)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return pub.(*rsa.PublicKey), nil
|
|
|
}
|
|
|
|
|
|
func EncodeRsaSSHPublicKey(public *rsa.PublicKey) ([]byte, error) {
|
|
|
publicKey, err := ssh.NewPublicKey(public)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return ssh.MarshalAuthorizedKey(publicKey), nil
|
|
|
}
|
|
|
|
|
|
func GenerateRsaSSHKeyPair(bits int, secret string) (string, string, error) {
|
|
|
pkey, pubkey, err := GenerateRsaKey(bits)
|
|
|
if err != nil {
|
|
|
return "", "", err
|
|
|
}
|
|
|
|
|
|
pub, err := EncodeRsaSSHPublicKey(pubkey)
|
|
|
if err != nil {
|
|
|
return "", "", err
|
|
|
}
|
|
|
|
|
|
priv, err := EncodeRsaPrivateKey(pkey, secret)
|
|
|
if err != nil {
|
|
|
return "", "", err
|
|
|
}
|
|
|
return string(priv), string(pub), nil
|
|
|
}
|
|
|
|
|
|
// RSAEncrypt RSA公钥加密
|
|
|
func RSAEncrypt(pub *rsa.PublicKey, data []byte) ([]byte, error) {
|
|
|
return rsa.EncryptPKCS1v15(rand.Reader, pub, data)
|
|
|
}
|
|
|
|
|
|
// RSADecrypt RSA私钥解密
|
|
|
func RSADecrypt(prikey *rsa.PrivateKey, data []byte) ([]byte, error) {
|
|
|
return rsa.DecryptPKCS1v15(rand.Reader, prikey, data)
|
|
|
}
|
|
|
|
|
|
// RSASign RSA私钥签名加密
|
|
|
func RSASign(msg, priKey []byte, password string, hashType crypto.Hash) ([]byte, error) {
|
|
|
var prikey *rsa.PrivateKey
|
|
|
var err error
|
|
|
var bytes []byte
|
|
|
blk, _ := pem.Decode(priKey)
|
|
|
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)
|
|
|
}
|
|
|
hashMethod := hashType.New()
|
|
|
_, err = hashMethod.Write(msg)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return rsa.SignPKCS1v15(rand.Reader, prikey, hashType, hashMethod.Sum(nil))
|
|
|
}
|
|
|
|
|
|
// RSAVerify RSA公钥签名验证
|
|
|
func RSAVerify(data, msg, pubKey []byte, hashType crypto.Hash) error {
|
|
|
blk, _ := pem.Decode(pubKey)
|
|
|
if blk == nil {
|
|
|
return errors.New("public key error!")
|
|
|
}
|
|
|
pubkey, err := x509.ParsePKIXPublicKey(blk.Bytes)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
hashMethod := hashType.New()
|
|
|
_, err = hashMethod.Write(msg)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return rsa.VerifyPKCS1v15(pubkey.(*rsa.PublicKey), hashType, hashMethod.Sum(nil), data)
|
|
|
}
|
|
|
|
|
|
// copy from crypt/rsa/pkcs1v5.go
|
|
|
var hashPrefixes = map[crypto.Hash][]byte{
|
|
|
crypto.MD5: {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
|
|
|
crypto.SHA1: {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
|
|
|
crypto.SHA224: {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c},
|
|
|
crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
|
|
|
crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
|
|
|
crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
|
|
|
crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix.
|
|
|
crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
|
|
|
}
|
|
|
|
|
|
// copy from crypt/rsa/pkcs1v5.go
|
|
|
func encrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int {
|
|
|
e := big.NewInt(int64(pub.E))
|
|
|
c.Exp(m, e, pub.N)
|
|
|
return c
|
|
|
}
|
|
|
|
|
|
// copy from crypt/rsa/pkcs1v5.go
|
|
|
func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {
|
|
|
// Special case: crypto.Hash(0) is used to indicate that the data is
|
|
|
// signed directly.
|
|
|
if hash == 0 {
|
|
|
return inLen, nil, nil
|
|
|
}
|
|
|
|
|
|
hashLen = hash.Size()
|
|
|
if inLen != hashLen {
|
|
|
return 0, nil, errors.New("crypto/rsa: input must be hashed message")
|
|
|
}
|
|
|
prefix, ok := hashPrefixes[hash]
|
|
|
if !ok {
|
|
|
return 0, nil, errors.New("crypto/rsa: unsupported hash function")
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// copy from crypt/rsa/pkcs1v5.go
|
|
|
func leftPad(input []byte, size int) (out []byte) {
|
|
|
n := len(input)
|
|
|
if n > size {
|
|
|
n = size
|
|
|
}
|
|
|
out = make([]byte, size)
|
|
|
copy(out[len(out)-n:], input)
|
|
|
return
|
|
|
}
|
|
|
func unLeftPad(input []byte) (out []byte) {
|
|
|
n := len(input)
|
|
|
t := 2
|
|
|
for i := 2; i < n; i++ {
|
|
|
if input[i] == 0xff {
|
|
|
t = t + 1
|
|
|
} else {
|
|
|
if input[i] == input[0] {
|
|
|
t = t + int(input[1])
|
|
|
}
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
out = make([]byte, n-t)
|
|
|
copy(out, input[t:])
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// copy&modified from crypt/rsa/pkcs1v5.go
|
|
|
func publicDecrypt(pub *rsa.PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (out []byte, err error) {
|
|
|
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
tLen := len(prefix) + hashLen
|
|
|
k := (pub.N.BitLen() + 7) / 8
|
|
|
if k < tLen+11 {
|
|
|
return nil, fmt.Errorf("length illegal")
|
|
|
}
|
|
|
|
|
|
c := new(big.Int).SetBytes(sig)
|
|
|
m := encrypt(new(big.Int), pub, c)
|
|
|
em := leftPad(m.Bytes(), k)
|
|
|
out = unLeftPad(em)
|
|
|
|
|
|
err = nil
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func RSAEncryptByPrivkey(privt *rsa.PrivateKey, data []byte) ([]byte, error) {
|
|
|
signData, err := rsa.SignPKCS1v15(nil, privt, crypto.Hash(0), data)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return signData, nil
|
|
|
}
|
|
|
|
|
|
func RSADecryptByPubkey(pub *rsa.PublicKey, data []byte) ([]byte, error) {
|
|
|
decData, err := publicDecrypt(pub, crypto.Hash(0), nil, data)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return decData, nil
|
|
|
}
|