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