blob: 17a2de2c79961435240df5d2f2ceb2dece1386d9 [file] [log] [blame]
Doug Zongker35d9ad52012-07-25 12:08:33 -07001/* rsa_e_f4.c
2**
3** Copyright 2012, The Android Open Source Project
4**
5** Redistribution and use in source and binary forms, with or without
6** modification, are permitted provided that the following conditions are met:
7** * Redistributions of source code must retain the above copyright
8** notice, this list of conditions and the following disclaimer.
9** * Redistributions in binary form must reproduce the above copyright
10** notice, this list of conditions and the following disclaimer in the
11** documentation and/or other materials provided with the distribution.
12** * Neither the name of Google Inc. nor the names of its contributors may
13** be used to endorse or promote products derived from this software
14** without specific prior written permission.
15**
16** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
17** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "mincrypt/rsa.h"
29#include "mincrypt/sha.h"
Doug Zongker515e1632013-04-10 09:22:02 -070030#include "mincrypt/sha256.h"
Doug Zongker35d9ad52012-07-25 12:08:33 -070031
32// a[] -= mod
33static void subM(const RSAPublicKey* key,
34 uint32_t* a) {
35 int64_t A = 0;
36 int i;
37 for (i = 0; i < key->len; ++i) {
38 A += (uint64_t)a[i] - key->n[i];
39 a[i] = (uint32_t)A;
40 A >>= 32;
41 }
42}
43
44// return a[] >= mod
45static int geM(const RSAPublicKey* key,
46 const uint32_t* a) {
47 int i;
48 for (i = key->len; i;) {
49 --i;
50 if (a[i] < key->n[i]) return 0;
51 if (a[i] > key->n[i]) return 1;
52 }
53 return 1; // equal
54}
55
56// montgomery c[] += a * b[] / R % mod
57static void montMulAdd(const RSAPublicKey* key,
58 uint32_t* c,
59 const uint32_t a,
60 const uint32_t* b) {
61 uint64_t A = (uint64_t)a * b[0] + c[0];
62 uint32_t d0 = (uint32_t)A * key->n0inv;
63 uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
64 int i;
65
66 for (i = 1; i < key->len; ++i) {
67 A = (A >> 32) + (uint64_t)a * b[i] + c[i];
68 B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
69 c[i - 1] = (uint32_t)B;
70 }
71
72 A = (A >> 32) + (B >> 32);
73
74 c[i - 1] = (uint32_t)A;
75
76 if (A >> 32) {
77 subM(key, c);
78 }
79}
80
81// montgomery c[] = a[] * b[] / R % mod
82static void montMul(const RSAPublicKey* key,
83 uint32_t* c,
84 const uint32_t* a,
85 const uint32_t* b) {
86 int i;
87 for (i = 0; i < key->len; ++i) {
88 c[i] = 0;
89 }
90 for (i = 0; i < key->len; ++i) {
91 montMulAdd(key, c, a[i], b);
92 }
93}
94
95// In-place public exponentiation.
96// Input and output big-endian byte array in inout.
97static void modpowF4(const RSAPublicKey* key,
98 uint8_t* inout) {
99 uint32_t a[RSANUMWORDS];
100 uint32_t aR[RSANUMWORDS];
101 uint32_t aaR[RSANUMWORDS];
102 uint32_t* aaa = aaR; // Re-use location.
103 int i;
104
105 // Convert from big endian byte array to little endian word array.
106 for (i = 0; i < key->len; ++i) {
107 uint32_t tmp =
108 (inout[((key->len - 1 - i) * 4) + 0] << 24) |
109 (inout[((key->len - 1 - i) * 4) + 1] << 16) |
110 (inout[((key->len - 1 - i) * 4) + 2] << 8) |
111 (inout[((key->len - 1 - i) * 4) + 3] << 0);
112 a[i] = tmp;
113 }
114
115 montMul(key, aR, a, key->rr); // aR = a * RR / R mod M
116 for (i = 0; i < 16; i += 2) {
117 montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M
118 montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M
119 }
120 montMul(key, aaa, aR, a); // aaa = aR * a / R mod M
121
122 // Make sure aaa < mod; aaa is at most 1x mod too large.
123 if (geM(key, aaa)) {
124 subM(key, aaa);
125 }
126
127 // Convert to bigendian byte array
128 for (i = key->len - 1; i >= 0; --i) {
129 uint32_t tmp = aaa[i];
130 *inout++ = tmp >> 24;
131 *inout++ = tmp >> 16;
132 *inout++ = tmp >> 8;
133 *inout++ = tmp >> 0;
134 }
135}
136
137// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
138// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
139// other flavor which omits the optional parameter entirely). This code does not
140// accept signatures without the optional parameter.
141/*
Doug Zongker515e1632013-04-10 09:22:02 -0700142static const uint8_t sha_padding[RSANUMBYTES] = {
Doug Zongker35d9ad52012-07-25 12:08:33 -07001430x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
144};
Doug Zongker515e1632013-04-10 09:22:02 -0700145
146static const uint8_t sha256_padding[RSANUMBYTES] = {
147 0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
148 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
149 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
150 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
151 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
152
153 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
154 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
155 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
156 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
157 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
158
159 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
160 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
161 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
162 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
163 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
164
165 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x30,0x31,0x30,
166 0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,
167 0x00,0x04,0x20,
168
169 // 32 bytes of hash go here.
170 0,0,0,0,0,0,0,0,
171 0,0,0,0,0,0,0,0,
172 0,0,0,0,0,0,0,0,
173 0,0,0,0,0,0,0,0,
174};
175
Doug Zongker35d9ad52012-07-25 12:08:33 -0700176*/
177
Doug Zongker515e1632013-04-10 09:22:02 -0700178// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
Doug Zongker35d9ad52012-07-25 12:08:33 -0700179// At the location of the bytes of the hash all 00 are hashed.
180static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
181 0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e, 0x6e, 0xfc,
182 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68, 0x7c, 0xfb, 0xf1, 0x67
183};
184
Doug Zongker515e1632013-04-10 09:22:02 -0700185// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
186// At the location of the bytes of the hash all 00 are hashed.
187static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
188 0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
189 0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
190 0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
191 0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
192};
193
Doug Zongker35d9ad52012-07-25 12:08:33 -0700194// Verify a 2048 bit RSA e=65537 PKCS1.5 signature against an expected
195// SHA-1 hash. Returns 0 on failure, 1 on success.
196int RSA_e_f4_verify(const RSAPublicKey* key,
197 const uint8_t* signature,
198 const int len,
Doug Zongker515e1632013-04-10 09:22:02 -0700199 const uint8_t* hash,
200 const int hash_len) {
Doug Zongker35d9ad52012-07-25 12:08:33 -0700201 uint8_t buf[RSANUMBYTES];
202 int i;
Doug Zongker515e1632013-04-10 09:22:02 -0700203 const uint8_t* padding_hash;
204
205 switch (hash_len) {
206 case SHA_DIGEST_SIZE:
207 padding_hash = kExpectedPadShaRsa2048;
208 break;
209 case SHA256_DIGEST_SIZE:
210 padding_hash = kExpectedPadSha256Rsa2048;
211 break;
212 default:
213 return 0; // unsupported hash
214 }
Doug Zongker35d9ad52012-07-25 12:08:33 -0700215
216 if (key->len != RSANUMWORDS) {
217 return 0; // Wrong key passed in.
218 }
219
220 if (len != sizeof(buf)) {
221 return 0; // Wrong input length.
222 }
223
224 if (key->exponent != 65537) {
225 return 0; // Wrong exponent.
226 }
227
228 for (i = 0; i < len; ++i) { // Copy input to local workspace.
229 buf[i] = signature[i];
230 }
231
232 modpowF4(key, buf); // In-place exponentiation.
233
234 // Xor sha portion, so it all becomes 00 iff equal.
Doug Zongker515e1632013-04-10 09:22:02 -0700235 for (i = len - hash_len; i < len; ++i) {
236 buf[i] ^= *hash++;
Doug Zongker35d9ad52012-07-25 12:08:33 -0700237 }
238
239 // Hash resulting buf, in-place.
Doug Zongker515e1632013-04-10 09:22:02 -0700240 switch (hash_len) {
241 case SHA_DIGEST_SIZE:
242 SHA_hash(buf, len, buf);
243 break;
244 case SHA256_DIGEST_SIZE:
245 SHA256_hash(buf, len, buf);
246 break;
247 default:
248 return 0;
249 }
Doug Zongker35d9ad52012-07-25 12:08:33 -0700250
251 // Compare against expected hash value.
Doug Zongker515e1632013-04-10 09:22:02 -0700252 for (i = 0; i < hash_len; ++i) {
253 if (buf[i] != padding_hash[i]) {
Doug Zongker35d9ad52012-07-25 12:08:33 -0700254 return 0;
255 }
256 }
257
258 return 1; // All checked out OK.
259}