forked from wheelcomplex/kmg
/
rsa.go
161 lines (149 loc) · 4.19 KB
/
rsa.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package kmgCrypto
import (
"crypto"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"math/big"
)
//使用和rsa.SignPKCS1v15相同的算法,但是返回解密后的数据
func RsaPublicDecryptPKCS1v15(pub *rsa.PublicKey, enc []byte) (data []byte, err error) {
c := new(big.Int).SetBytes(enc)
m := RsaEncrypt(new(big.Int), pub, c)
data = m.Bytes()
//还原数据长度
for i := 2; i < len(data); i++ {
if data[i] == 0 {
return data[i+1:], nil
}
}
return nil, ErrDecryption
//e := big.NewInt(int64(pub.E))
//c.Exp(m, e, pub.N)
}
func RsaEncrypt(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
}
var (
ErrInputSize = errors.New("input size too large")
ErrEncryption = errors.New("encryption error")
ErrDecryption = errors.New("decryption error")
ErrNotRsaTypePublicKey = errors.New("public key is not rsa type.")
)
func RsaPrivateEncryptPKCS1v15(priv *rsa.PrivateKey, data []byte) (enc []byte, err error) {
return rsa.SignPKCS1v15(nil, priv, crypto.Hash(0), data)
/*
k := (priv.N.BitLen() + 7) / 8
tLen := len(data)
// rfc2313, section 8:
// The length of the data D shall not be more than k-11 octets
if tLen > k-11 {
err = ErrInputSize
return
}
em := make([]byte, k)
em[1] = 1
for i := 2; i < k-tLen-1; i++ {
em[i] = 0xff
}
copy(em[k-tLen:k], data)
c := new(big.Int).SetBytes(em)
if c.Cmp(priv.N) > 0 {
err = ErrEncryption
return
}
var m *big.Int
var ir *big.Int
if priv.Precomputed.Dp == nil {
m = new(big.Int).Exp(c, priv.D, priv.N)
} else {
// We have the precalculated values needed for the CRT.
m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0])
m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1])
m.Sub(m, m2)
if m.Sign() < 0 {
m.Add(m, priv.Primes[0])
}
m.Mul(m, priv.Precomputed.Qinv)
m.Mod(m, priv.Primes[0])
m.Mul(m, priv.Primes[1])
m.Add(m, m2)
for i, values := range priv.Precomputed.CRTValues {
prime := priv.Primes[2+i]
m2.Exp(c, values.Exp, prime)
m2.Sub(m2, m)
m2.Mul(m2, values.Coeff)
m2.Mod(m2, prime)
if m2.Sign() < 0 {
m2.Add(m2, prime)
}
m2.Mul(m2, values.R)
m.Add(m, m2)
}
}
if ir != nil {
// Unblind.
m.Mul(m, ir)
m.Mod(m, priv.N)
}
enc = m.Bytes()
return
*/
}
func RsaParseOpensslPrivateKey(b []byte) (key *rsa.PrivateKey, err error) {
block, _ := pem.Decode(b)
return x509.ParsePKCS1PrivateKey(block.Bytes)
}
func RsaParseOpensslPublicKey(b []byte) (pub *rsa.PublicKey, err error) {
block, _ := pem.Decode(b)
pk, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return
}
pub, ok := pk.(*rsa.PublicKey)
if !ok {
return nil, ErrNotRsaTypePublicKey
}
return pub, nil
}
func RsaOpensslSign(pub *rsa.PrivateKey, h crypto.Hash, msg []byte) (s []byte, err error) {
h1 := h.New()
h1.Write(msg)
digest := h1.Sum(nil)
s, err = rsa.SignPKCS1v15(nil, pub, h, digest)
return
}
//这个接口应该和php版的openssl_verify在使用rsa公钥的时候有完全相同的输入输出,加密的坑简直太多了..
//msg是需要验证签名的消息,sig是签名之后生成的
func RsaOpensslVerify(pub *rsa.PublicKey, h crypto.Hash, msg []byte, sig []byte) (err error) {
h1 := h.New()
h1.Write(msg)
digest := h1.Sum(nil)
err = rsa.VerifyPKCS1v15(pub, h, digest, sig)
return
}
//支付宝签名的默认方式,
// 放在这里主要用于文档该功能如何实现,
// 并且提供一种签名的方式
// 读入 PKCS1格式私钥字符串 , 需要签名的数据
// 返回 签名后的数据
func RsaWithSha1PKCS1OpensslSignBase64(PKCS1privateKey []byte, msg []byte) (s string, err error) {
block, _ := pem.Decode(PKCS1privateKey)
private, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return
}
b, err := RsaOpensslSign(private, crypto.SHA1, msg)
if err != nil {
return
}
return base64.StdEncoding.EncodeToString(b), nil
}
//有时候会得到一个没有头没有尾的publicKey,使用这个函数加上 -----BEGIN PUBLIC KEY----- -----END PUBLIC KEY-----
func PemAddStartEnd(in string) []byte {
return []byte("-----BEGIN PUBLIC KEY-----\n" + in + "\n-----END PUBLIC KEY-----")
}