blob: bfc644690e615d64c2f068bb1bef123afd6f32c2 [file] [log] [blame]
Gaurav Shah322536d2010-01-28 15:01:23 -08001/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6/* Implementation of RSA signature verification which uses a pre-processed
7 * key for computation. The code extends Android's RSA verification code to
8 * support multiple RSA key lengths and hash digest algorithms.
9 */
10
Gaurav Shah5411c7a2010-03-31 10:56:49 -070011#include "cryptolib.h"
Gaurav Shah322536d2010-01-28 15:01:23 -080012#include "utility.h"
13
14/* a[] -= mod */
15static void subM(const RSAPublicKey *key, uint32_t *a) {
16 int64_t A = 0;
17 int i;
18 for (i = 0; i < key->len; ++i) {
19 A += (uint64_t)a[i] - key->n[i];
20 a[i] = (uint32_t)A;
21 A >>= 32;
22 }
23}
24
25/* return a[] >= mod */
26static int geM(const RSAPublicKey *key, uint32_t *a) {
27 int i;
28 for (i = key->len; i;) {
29 --i;
30 if (a[i] < key->n[i]) return 0;
31 if (a[i] > key->n[i]) return 1;
32 }
33 return 1; /* equal */
34 }
35
36/* montgomery c[] += a * b[] / R % mod */
37static void montMulAdd(const RSAPublicKey *key,
38 uint32_t* c,
39 const uint32_t a,
40 const uint32_t* b) {
41 uint64_t A = (uint64_t)a * b[0] + c[0];
42 uint32_t d0 = (uint32_t)A * key->n0inv;
43 uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
44 int i;
45
46 for (i = 1; i < key->len; ++i) {
47 A = (A >> 32) + (uint64_t)a * b[i] + c[i];
48 B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
49 c[i - 1] = (uint32_t)B;
50 }
51
52 A = (A >> 32) + (B >> 32);
53
54 c[i - 1] = (uint32_t)A;
55
56 if (A >> 32) {
57 subM(key, c);
58 }
59}
60
61/* montgomery c[] = a[] * b[] / R % mod */
62static void montMul(const RSAPublicKey *key,
63 uint32_t* c,
64 uint32_t* a,
65 uint32_t* b) {
66 int i;
67 for (i = 0; i < key->len; ++i) {
68 c[i] = 0;
69 }
70 for (i = 0; i < key->len; ++i) {
71 montMulAdd(key, c, a[i], b);
72 }
73}
74
75/* In-place public exponentiation. (65537}
76 * Input and output big-endian byte array in inout.
77 */
78static void modpowF4(const RSAPublicKey *key,
79 uint8_t* inout) {
80 uint32_t* a = (uint32_t*) Malloc(key->len * sizeof(uint32_t));
81 uint32_t* aR = (uint32_t*) Malloc(key->len * sizeof(uint32_t));
82 uint32_t* aaR = (uint32_t*) Malloc(key->len * sizeof(uint32_t));
83
84 uint32_t* aaa = aaR; /* Re-use location. */
85 int i;
86
87 /* Convert from big endian byte array to little endian word array. */
88 for (i = 0; i < key->len; ++i) {
89 uint32_t tmp =
90 (inout[((key->len - 1 - i) * 4) + 0] << 24) |
91 (inout[((key->len - 1 - i) * 4) + 1] << 16) |
92 (inout[((key->len - 1 - i) * 4) + 2] << 8) |
93 (inout[((key->len - 1 - i) * 4) + 3] << 0);
94 a[i] = tmp;
95 }
96
97 montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
98 for (i = 0; i < 16; i+=2) {
99 montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
100 montMul(key, aR, aaR, aaR); /* aR = aaR * aaR / R mod M */
101 }
102 montMul(key, aaa, aR, a); /* aaa = aR * a / R mod M */
103
104
105 /* Make sure aaa < mod; aaa is at most 1x mod too large. */
106 if (geM(key, aaa)) {
107 subM(key, aaa);
108 }
109
110 /* Convert to bigendian byte array */
111 for (i = key->len - 1; i >= 0; --i) {
112 uint32_t tmp = aaa[i];
113 *inout++ = tmp >> 24;
114 *inout++ = tmp >> 16;
115 *inout++ = tmp >> 8;
116 *inout++ = tmp >> 0;
117 }
118
119 Free(a);
120 Free(aR);
121 Free(aaR);
122}
123
124/* Verify a RSA PKCS1.5 signature against an expected hash.
125 * Returns 0 on failure, 1 on success.
126 */
Gaurav Shahf5564fa2010-03-02 15:40:01 -0800127int RSAVerify(const RSAPublicKey *key,
128 const uint8_t *sig,
129 const int sig_len,
130 const uint8_t sig_type,
131 const uint8_t *hash) {
Gaurav Shah322536d2010-01-28 15:01:23 -0800132 int i;
133 uint8_t* buf;
134 const uint8_t* padding;
135 int success = 1;
136
137 if (sig_len != (key->len * sizeof(uint32_t))) {
Gaurav Shah5411c7a2010-03-31 10:56:49 -0700138 debug("Signature is of incorrect length!\n");
Gaurav Shah322536d2010-01-28 15:01:23 -0800139 return 0;
140 }
141
142 if (sig_type >= kNumAlgorithms) {
Gaurav Shah5411c7a2010-03-31 10:56:49 -0700143 debug("Invalid signature type!\n");
Gaurav Shah322536d2010-01-28 15:01:23 -0800144 return 0;
145 }
146
Gaurav Shahcae5fa62010-02-28 20:02:29 -0800147 if (key->len != siglen_map[sig_type] / sizeof(uint32_t)) {
Gaurav Shah5411c7a2010-03-31 10:56:49 -0700148 debug("Wrong key passed in!\n");
Gaurav Shah322536d2010-01-28 15:01:23 -0800149 return 0;
150 }
151
152 buf = (uint8_t*) Malloc(sig_len);
153 Memcpy(buf, sig, sig_len);
154
155 modpowF4(key, buf);
156
157 /* Determine padding to use depending on the signature type. */
158 padding = padding_map[sig_type];
159
160 /* Check pkcs1.5 padding bytes. */
161 for (i = 0; i < padding_size_map[sig_type]; ++i) {
162 if (buf[i] != padding[i]) {
163#ifndef NDEBUG
164/* TODO(gauravsh): Replace with a macro call for logging. */
Gaurav Shah5411c7a2010-03-31 10:56:49 -0700165 debug("Padding: Expecting = %02x Got = %02x\n", padding[i],
Gaurav Shah322536d2010-01-28 15:01:23 -0800166 buf[i]);
167#endif
168 success = 0;
169 }
170 }
171
172 /* Check if digest matches. */
173 for (; i < sig_len; ++i) {
174 if (buf[i] != *hash++) {
175#ifndef NDEBUG
176/* TODO(gauravsh): Replace with a macro call for logging. */
Gaurav Shah5411c7a2010-03-31 10:56:49 -0700177 debug("Digest: Expecting = %02x Got = %02x\n", padding[i],
Gaurav Shah322536d2010-01-28 15:01:23 -0800178 buf[i]);
179#endif
180 success = 0;
181 }
182 }
183
184 Free(buf);
185
186 return success;
187}