zhaolei
5 days ago 4a2e5b9a21940f11757be37d99f0944e240e908b
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
162
163
164
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
 
namespace Prow.AlipayAuth
{
    /// <summary>
    /// Alipay 签名操作类
    /// </summary>
    internal static class AlipaySignature
    {
        /// <summary>
        /// 获得待签名参数方法
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private static string GetSignContent(IDictionary<string, string> parameters)
        {
            // 第一步:把字典按Key的字母顺序排序
            var sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal);
 
            // 第二步:把所有参数名和参数值串在一起
            var items = sortedParams.Select(d => $"{d.Key}={d.Value}");
            string content = string.Join("&", items);
 
            return content;
        }
 
        /// <summary>
        /// 签名方法
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="signKey"></param>
        /// <returns></returns>
        public static string Sign(IDictionary<string, string> parameters, string signKey)
        {
            var content = GetSignContent(parameters);
            byte[] data = Encoding.UTF8.GetBytes(content);
            using var rsaService = BuildRSAServiceProvider(Convert.FromBase64String(signKey));
            byte[] sign = rsaService?.SignData(data, "SHA256") ?? new byte[0];
            return Convert.ToBase64String(sign);
        }
 
        private static RSACryptoServiceProvider? BuildRSAServiceProvider(byte[] privateKey)
        {
            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
 
            //set up stream to decode the asn.1 encoded RSA private key
            //wrap Memory Stream with BinaryReader for easy reading
            using var binaryReader = new BinaryReader(new MemoryStream(privateKey));
            var twobytes = binaryReader.ReadUInt16();
            //data read as little endian order (actual data order for Sequence is 30 81)
            if (twobytes == 0x8130)
            {
                //advance 1 byte
                binaryReader.ReadByte();
            }
            else if (twobytes == 0x8230)
            {
                //advance 2 bytes
                binaryReader.ReadInt16();
            }
            else
            {
                return null;
            }
 
            twobytes = binaryReader.ReadUInt16();
            //version number
            if (twobytes != 0x0102)
            {
                return null;
            }
            var bt = binaryReader.ReadByte();
            if (bt != 0x00)
            {
                return null;
            }
 
            //all private key components are Integer sequences
            var elems = GetIntegerSize(binaryReader);
            MODULUS = binaryReader.ReadBytes(elems);
 
            elems = GetIntegerSize(binaryReader);
            E = binaryReader.ReadBytes(elems);
 
            elems = GetIntegerSize(binaryReader);
            D = binaryReader.ReadBytes(elems);
 
            elems = GetIntegerSize(binaryReader);
            P = binaryReader.ReadBytes(elems);
 
            elems = GetIntegerSize(binaryReader);
            Q = binaryReader.ReadBytes(elems);
 
            elems = GetIntegerSize(binaryReader);
            DP = binaryReader.ReadBytes(elems);
 
            elems = GetIntegerSize(binaryReader);
            DQ = binaryReader.ReadBytes(elems);
 
            elems = GetIntegerSize(binaryReader);
            IQ = binaryReader.ReadBytes(elems);
 
            //create RSACryptoServiceProvider instance and initialize with public key
            var rsaService = new RSACryptoServiceProvider();
            var rsaParams = new RSAParameters
            {
                Modulus = MODULUS,
                Exponent = E,
                D = D,
                P = P,
                Q = Q,
                DP = DP,
                DQ = DQ,
                InverseQ = IQ
            };
            rsaService.ImportParameters(rsaParams);
            return rsaService;
        }
 
        private static int GetIntegerSize(BinaryReader binaryReader)
        {
            var bt = binaryReader.ReadByte();
 
            //expect integer
            if (bt != 0x02)
            {
                return 0;
            }
            bt = binaryReader.ReadByte();
 
            int count;
            if (bt == 0x81)
            {
                //data size in next byte
                count = binaryReader.ReadByte();
            }
            else if (bt == 0x82)
            {
                //data size in next 2 bytes
                var highbyte = binaryReader.ReadByte();
                var lowbyte = binaryReader.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32(modint, 0);
            }
            else
            {
                //we already have the data size
                count = bt;
            }
            while (binaryReader.ReadByte() == 0x00)
            {   //remove high order zeros in data
                count -= 1;
            }
            //last ReadByte wasn't a removed zero, so back up a byte
            binaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
            return count;
        }
    }
}