2 * @file rsa_public_key.c
4 * @brief Implementation of rsa_public_key_t.
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28 #include "rsa_public_key.h"
31 #include <crypto/hashers/hasher.h>
32 #include <asn1/asn1.h>
36 * we use these predefined values for
37 * hash algorithm OIDs. These also contain
38 * the length of the following hash.
39 * These values are also used in rsa_private_key.c.
40 * TODO: We may move them in asn1 sometime...
43 u_int8_t md2_oid
[] = {
44 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,
45 0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,
49 u_int8_t md5_oid
[] = {
50 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,
51 0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,
55 u_int8_t sha1_oid
[] = {
56 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,
57 0x03,0x02,0x1a,0x05,0x00,0x04,0x14
60 u_int8_t sha256_oid
[] = {
61 0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,
62 0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,
66 u_int8_t sha384_oid
[] = {
67 0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,
68 0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,
72 u_int8_t sha512_oid
[] = {
73 0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,
74 0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,
78 /* ASN.1 definition public key */
79 static const asn1Object_t pubkey_objects
[] = {
80 { 0, "RSAPublicKey", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 0 */
81 { 1, "modulus", ASN1_INTEGER
, ASN1_BODY
}, /* 1 */
82 { 1, "publicExponent", ASN1_INTEGER
, ASN1_BODY
}, /* 2 */
85 #define PUB_KEY_RSA_PUBLIC_KEY 0
86 #define PUB_KEY_MODULUS 1
87 #define PUB_KEY_EXPONENT 2
88 #define PUB_KEY_ROOF 3
90 typedef struct private_rsa_public_key_t private_rsa_public_key_t
;
93 * Private data structure with signing context.
95 struct private_rsa_public_key_t
{
97 * Public interface for this signer.
99 rsa_public_key_t
public;
117 * @brief Implements the RSAEP algorithm specified in PKCS#1.
119 * @param this calling object
120 * @param data data to process
121 * @return processed data
123 chunk_t (*rsaep
) (private_rsa_public_key_t
*this, chunk_t data
);
126 * @brief Implements the RSASVP1 algorithm specified in PKCS#1.
128 * @param this calling object
129 * @param data data to process
130 * @return processed data
132 chunk_t (*rsavp1
) (private_rsa_public_key_t
*this, chunk_t data
);
136 typedef struct rsa_public_key_info_t rsa_public_key_info_t
;
139 * KeyInfo, as it appears in a public key file
141 struct rsa_public_key_info_t
{
143 * Algorithm for this key
145 chunk_t algorithm_oid
;
148 * Public key, parseable with rsa_public_key_rules
153 private_rsa_public_key_t
*rsa_public_key_create_empty();
156 * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1
158 static chunk_t
rsaep(private_rsa_public_key_t
*this, chunk_t data
)
166 mpz_import(m
, data
.len
, 1, 1, 1, 0, data
.ptr
);
168 mpz_powm(c
, m
, this->e
, this->n
);
170 encrypted
.len
= this->k
;
171 encrypted
.ptr
= mpz_export(NULL
, NULL
, 1, encrypted
.len
, 1, 0, c
);
180 * Implementation of rsa_public_key.verify_emsa_pkcs1_signature.
182 static status_t
verify_emsa_pkcs1_signature(private_rsa_public_key_t
*this, chunk_t data
, chunk_t signature
)
184 hasher_t
*hasher
= NULL
;
189 if (signature
.len
> this->k
)
194 /* unpack signature */
195 em
= this->rsavp1(this, signature
);
197 /* result should look like this:
198 * EM = 0x00 || 0x01 || PS || 0x00 || T.
199 * PS = 0xFF padding, with length to fill em
203 /* check magic bytes */
204 if ((*(em
.ptr
) != 0x00) ||
205 (*(em
.ptr
+1) != 0x01))
211 /* find magic 0x00 */
213 while (pos
<= em
.ptr
+ em
.len
)
217 /* found magic byte, stop */
221 else if (*pos
!= 0xFF)
223 /* bad padding, decryption failed ?!*/
230 if (pos
+ 20 > em
.ptr
+ em
.len
)
232 /* not enought room for oid compare */
237 if (memcmp(md2_oid
, pos
, sizeof(md2_oid
)) == 0)
239 hasher
= hasher_create(HASH_MD2
);
240 pos
+= sizeof(md2_oid
);
242 else if (memcmp(md5_oid
, pos
, sizeof(md5_oid
)) == 0)
244 hasher
= hasher_create(HASH_MD5
);
245 pos
+= sizeof(md5_oid
);
247 else if (memcmp(sha1_oid
, pos
, sizeof(sha1_oid
)) == 0)
249 hasher
= hasher_create(HASH_SHA1
);
250 pos
+= sizeof(sha1_oid
);
252 else if (memcmp(sha256_oid
, pos
, sizeof(sha256_oid
)) == 0)
254 hasher
= hasher_create(HASH_SHA256
);
255 pos
+= sizeof(sha256_oid
);
257 else if (memcmp(sha384_oid
, pos
, sizeof(sha384_oid
)) == 0)
259 hasher
= hasher_create(HASH_SHA384
);
260 pos
+= sizeof(sha384_oid
);
262 else if (memcmp(sha512_oid
, pos
, sizeof(sha512_oid
)) == 0)
264 hasher
= hasher_create(HASH_SHA512
);
265 pos
+= sizeof(sha512_oid
);
270 /* not supported hash algorithm */
272 return NOT_SUPPORTED
;
275 if (pos
+ hasher
->get_hash_size(hasher
) != em
.ptr
+ em
.len
)
279 hasher
->destroy(hasher
);
283 /* build own hash for a compare */
284 hasher
->allocate_hash(hasher
, data
, &hash
);
285 hasher
->destroy(hasher
);
287 if (memcmp(hash
.ptr
, pos
, hash
.len
) != 0)
289 /* hash does not equal */
303 * Implementation of rsa_public_key.get_key.
305 static status_t
get_key(private_rsa_public_key_t
*this, chunk_t
*key
)
310 n
.ptr
= mpz_export(NULL
, NULL
, 1, n
.len
, 1, 0, this->n
);
312 e
.ptr
= mpz_export(NULL
, NULL
, 1, e
.len
, 1, 0, this->e
);
314 key
->len
= this->k
* 2;
315 key
->ptr
= malloc(key
->len
);
316 memcpy(key
->ptr
, n
.ptr
, n
.len
);
317 memcpy(key
->ptr
+ n
.len
, e
.ptr
, e
.len
);
325 * Implementation of rsa_public_key.save_key.
327 static status_t
save_key(private_rsa_public_key_t
*this, char *file
)
329 return NOT_SUPPORTED
;
333 * Implementation of rsa_public_key.get_modulus.
335 static mpz_t
*get_modulus(private_rsa_public_key_t
*this)
341 * Implementation of rsa_public_key.clone.
343 static rsa_public_key_t
* _clone(private_rsa_public_key_t
*this)
345 private_rsa_public_key_t
*clone
= rsa_public_key_create_empty();
347 mpz_init_set(clone
->n
, this->n
);
348 mpz_init_set(clone
->e
, this->e
);
351 return &clone
->public;
355 * Implementation of rsa_public_key.destroy.
357 static void destroy(private_rsa_public_key_t
*this)
365 * Generic private constructor
367 private_rsa_public_key_t
*rsa_public_key_create_empty()
369 private_rsa_public_key_t
*this = malloc_thing(private_rsa_public_key_t
);
371 /* public functions */
372 this->public.verify_emsa_pkcs1_signature
= (status_t (*) (rsa_public_key_t
*,chunk_t
,chunk_t
))verify_emsa_pkcs1_signature
;
373 this->public.get_key
= (status_t (*) (rsa_public_key_t
*,chunk_t
*))get_key
;
374 this->public.save_key
= (status_t (*) (rsa_public_key_t
*,char*))save_key
;
375 this->public.get_modulus
= (mpz_t
*(*) (rsa_public_key_t
*))get_modulus
;
376 this->public.clone
= (rsa_public_key_t
* (*) (rsa_public_key_t
*))_clone
;
377 this->public.destroy
= (void (*) (rsa_public_key_t
*))destroy
;
379 /* private functions */
381 this->rsavp1
= rsaep
; /* same algorithm */
389 rsa_public_key_t
*rsa_public_key_create_from_chunk(chunk_t blob
)
395 private_rsa_public_key_t
*this;
397 this = rsa_public_key_create_empty();
401 asn1_init(&ctx
, blob
, 0, FALSE
);
403 while (objectID
< PUB_KEY_ROOF
)
405 if (!extract_object(pubkey_objects
, &objectID
, &object
, &level
, &ctx
))
412 case PUB_KEY_MODULUS
:
413 mpz_import(this->n
, object
.len
, 1, 1, 1, 0, object
.ptr
);
415 case PUB_KEY_EXPONENT
:
416 mpz_import(this->e
, object
.len
, 1, 1, 1, 0, object
.ptr
);
422 this->k
= (mpz_sizeinbase(this->n
, 2) + 7) / 8;
423 return &this->public;
429 rsa_public_key_t
*rsa_public_key_create_from_file(char *filename
)
436 if (stat(filename
, &stb
) == -1)
441 buffer
= alloca(stb
.st_size
);
443 file
= fopen(filename
, "r");
449 if (fread(buffer
, stb
.st_size
, 1, file
) != 1)
455 chunk
.len
= stb
.st_size
;
457 return rsa_public_key_create_from_chunk(chunk
);