1 /*
2 * The RSA public-key cryptosystem
3 *
4 * Copyright (C) 2006-2011, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; If not, see <http://www.gnu.org/licenses/>.
23 */
24 /*
25 * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman.
26 *
27 * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
28 * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
29 */
30
31 #include "tcg.h"
32 #include "polarssl/sha1.h"
33
34 #include <stdlib.h>
35 #include <stdio.h>
36
37 #include "tpmrsa.h"
38
39 #define HASH_LEN 20
40
tpmrsa_set_pubkey(tpmrsa_context * ctx,const unsigned char * key,int keylen,const unsigned char * exponent,int explen)41 void tpmrsa_set_pubkey(tpmrsa_context* ctx,
42 const unsigned char* key,
43 int keylen,
44 const unsigned char* exponent,
45 int explen) {
46
47 tpmrsa_free(ctx);
48
49 if(explen == 0) { //Default e= 2^16+1
50 mpi_lset(&ctx->E, 65537);
51 } else {
52 mpi_read_binary(&ctx->E, exponent, explen);
53 }
54 mpi_read_binary(&ctx->N, key, keylen);
55
56 ctx->len = ( mpi_msb(&ctx->N) + 7) >> 3;
57 }
58
tpmrsa_public(tpmrsa_context * ctx,const unsigned char * input,unsigned char * output)59 static TPM_RESULT tpmrsa_public( tpmrsa_context *ctx,
60 const unsigned char *input,
61 unsigned char *output )
62 {
63 int ret;
64 size_t olen;
65 mpi T;
66
67 mpi_init( &T );
68
69 MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
70
71 if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
72 {
73 mpi_free( &T );
74 return TPM_ENCRYPT_ERROR;
75 }
76
77 olen = ctx->len;
78 MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
79 MPI_CHK( mpi_write_binary( &T, output, olen ) );
80
81 cleanup:
82
83 mpi_free( &T );
84
85 if( ret != 0 )
86 return TPM_ENCRYPT_ERROR;
87
88 return TPM_SUCCESS;
89 }
90
91 static const unsigned char rsa_der_header[] = {
92 0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
93 };
94
tpmrsa_sigcheck(tpmrsa_context * ctx,const unsigned char * input,const unsigned char * sha1)95 TPM_RESULT tpmrsa_sigcheck(tpmrsa_context *ctx, const unsigned char *input, const unsigned char *sha1)
96 {
97 unsigned char *tmp = alloca(ctx->len);
98 TPM_RESULT rv;
99 int i;
100 rv = tpmrsa_public(ctx, input, tmp);
101 if (rv)
102 return rv;
103 if (tmp[0] != 0 || tmp[1] != 1)
104 return TPM_INAPPROPRIATE_SIG;
105 for(i=2; i < 220; i++) {
106 if (tmp[i] != 0xFF)
107 return TPM_INAPPROPRIATE_SIG;
108 }
109 if (memcmp(tmp + 220, rsa_der_header, sizeof(rsa_der_header)))
110 return TPM_INAPPROPRIATE_SIG;
111 if (memcmp(tmp + 236, sha1, 20))
112 return TPM_DECRYPT_ERROR;
113 return TPM_SUCCESS;
114 }
115
mgf_mask(unsigned char * dst,int dlen,unsigned char * src,int slen)116 static void mgf_mask( unsigned char *dst, int dlen, unsigned char *src, int slen)
117 {
118 unsigned char mask[HASH_LEN];
119 unsigned char counter[4] = {0, 0, 0, 0};
120 int i;
121 sha1_context mctx;
122
123 //We always hash the src with the counter, so save the partial hash
124 sha1_starts(&mctx);
125 sha1_update(&mctx, src, slen);
126
127 // Generate and apply dbMask
128 while(dlen > 0) {
129 //Copy the sha1 context
130 sha1_context ctx = mctx;
131
132 //compute hash for input || counter
133 sha1_update(&ctx, counter, sizeof(counter));
134 sha1_finish(&ctx, mask);
135
136 //Apply the mask
137 for(i = 0; i < (dlen < HASH_LEN ? dlen : HASH_LEN); ++i) {
138 *(dst++) ^= mask[i];
139 }
140
141 //Increment counter
142 ++counter[3];
143
144 dlen -= HASH_LEN;
145 }
146 }
147
148 /*
149 * Add the message padding, then do an RSA operation
150 */
tpmrsa_pub_encrypt_oaep(tpmrsa_context * ctx,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng,size_t ilen,const unsigned char * input,unsigned char * output)151 TPM_RESULT tpmrsa_pub_encrypt_oaep( tpmrsa_context *ctx,
152 int (*f_rng)(void *, unsigned char *, size_t),
153 void *p_rng,
154 size_t ilen,
155 const unsigned char *input,
156 unsigned char *output )
157 {
158 int ret;
159 int olen;
160 unsigned char* seed = output + 1;
161 unsigned char* db = output + HASH_LEN +1;
162
163 olen = ctx->len-1;
164
165 if( f_rng == NULL )
166 return TPM_ENCRYPT_ERROR;
167
168 if( ilen > olen - 2 * HASH_LEN - 1)
169 return TPM_ENCRYPT_ERROR;
170
171 output[0] = 0;
172
173 //Encoding parameter p
174 sha1((unsigned char*)"TCPA", 4, db);
175
176 //PS
177 memset(db + HASH_LEN, 0,
178 olen - ilen - 2 * HASH_LEN - 1);
179
180 //constant 1 byte
181 db[olen - ilen - HASH_LEN -1] = 0x01;
182
183 //input string
184 memcpy(db + olen - ilen - HASH_LEN,
185 input, ilen);
186
187 //Generate random seed
188 if( ( ret = f_rng( p_rng, seed, HASH_LEN ) ) != 0 )
189 return TPM_ENCRYPT_ERROR;
190
191 // maskedDB: Apply dbMask to DB
192 mgf_mask( db, olen - HASH_LEN, seed, HASH_LEN);
193
194 // maskedSeed: Apply seedMask to seed
195 mgf_mask( seed, HASH_LEN, db, olen - HASH_LEN);
196
197 // Do the crypto op
198 return tpmrsa_public(ctx, output, output);
199 }
200