2 * @file rsa_public_key.c
4 * @brief Implementation of rsa_public_key_t.
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
32 #include "rsa_public_key.h"
35 #include <crypto/hashers/hasher.h>
36 #include <asn1/asn1.h>
39 /* ASN.1 definition of RSApublicKey */
40 static const asn1Object_t pubkeyObjects
[] = {
41 { 0, "RSAPublicKey", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 0 */
42 { 1, "modulus", ASN1_INTEGER
, ASN1_BODY
}, /* 1 */
43 { 1, "publicExponent", ASN1_INTEGER
, ASN1_BODY
}, /* 2 */
46 #define PUB_KEY_RSA_PUBLIC_KEY 0
47 #define PUB_KEY_MODULUS 1
48 #define PUB_KEY_EXPONENT 2
49 #define PUB_KEY_ROOF 3
51 /* ASN.1 definition of digestInfo */
52 static const asn1Object_t digestInfoObjects
[] = {
53 { 0, "digestInfo", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 0 */
54 { 1, "digestAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 1 */
55 { 1, "digest", ASN1_OCTET_STRING
, ASN1_BODY
}, /* 2 */
59 #define DIGEST_INFO_ALGORITHM 1
60 #define DIGEST_INFO_DIGEST 2
61 #define DIGEST_INFO_ROOF 3
63 typedef struct private_rsa_public_key_t private_rsa_public_key_t
;
66 * Private data structure with signing context.
68 struct private_rsa_public_key_t
{
70 * Public interface for this signer.
72 rsa_public_key_t
public;
90 * Keyid formed as a SHA-1 hash of a publicKeyInfo object
95 * @brief Implements the RSAEP algorithm specified in PKCS#1.
97 * @param this calling object
98 * @param data data to process
99 * @return processed data
101 chunk_t (*rsaep
) (const private_rsa_public_key_t
*this, chunk_t data
);
104 * @brief Implements the RSASVP1 algorithm specified in PKCS#1.
106 * @param this calling object
107 * @param data data to process
108 * @return processed data
110 chunk_t (*rsavp1
) (const private_rsa_public_key_t
*this, chunk_t data
);
113 private_rsa_public_key_t
*rsa_public_key_create_empty(void);
116 * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1
118 static chunk_t
rsaep(const private_rsa_public_key_t
*this, chunk_t data
)
126 mpz_import(m
, data
.len
, 1, 1, 1, 0, data
.ptr
);
128 mpz_powm(c
, m
, this->e
, this->n
);
130 encrypted
.len
= this->k
;
131 encrypted
.ptr
= mpz_export(NULL
, NULL
, 1, encrypted
.len
, 1, 0, c
);
140 * Implementation of rsa_public_key.verify_emsa_pkcs1_signature.
142 static status_t
verify_emsa_pkcs1_signature(const private_rsa_public_key_t
*this,
143 hash_algorithm_t algorithm
,
144 chunk_t data
, chunk_t signature
)
147 status_t res
= FAILED
;
149 /* remove any preceding 0-bytes from signature */
150 while (signature
.len
&& *(signature
.ptr
) == 0x00)
156 if (signature
.len
> this->k
)
161 /* unpack signature */
162 em_ori
= em
= this->rsavp1(this, signature
);
164 /* result should look like this:
165 * EM = 0x00 || 0x01 || PS || 0x00 || T.
166 * PS = 0xFF padding, with length to fill em
170 /* check magic bytes */
171 if (*(em
.ptr
) != 0x00 || *(em
.ptr
+1) != 0x01)
173 DBG2("incorrect padding - probably wrong RSA key");
179 /* find magic 0x00 */
184 /* found magic byte, stop */
189 else if (*em
.ptr
!= 0xFF)
191 /* bad padding, decryption failed ?!*/
200 /* no digestInfo found */
204 /* parse ASN.1-based digestInfo */
210 hash_algorithm_t hash_algorithm
= HASH_UNKNOWN
;
212 asn1_init(&ctx
, em
, 0, FALSE
, FALSE
);
214 while (objectID
< DIGEST_INFO_ROOF
)
216 if (!extract_object(digestInfoObjects
, &objectID
, &object
, &level
, &ctx
))
223 if (em
.len
> object
.len
)
225 DBG1("digestInfo field in signature is followed by %u surplus bytes",
226 em
.len
- object
.len
);
230 case DIGEST_INFO_ALGORITHM
:
232 int hash_oid
= parse_algorithmIdentifier(object
, level
+1, NULL
);
234 hash_algorithm
= hasher_algorithm_from_oid(hash_oid
);
235 if (hash_algorithm
== HASH_UNKNOWN
236 || (algorithm
!= HASH_UNKNOWN
&& hash_algorithm
!= algorithm
))
238 DBG1("wrong hash algorithm used in signature");
243 case DIGEST_INFO_DIGEST
:
246 hasher_t
*hasher
= hasher_create(hash_algorithm
);
248 if (object
.len
!= hasher
->get_hash_size(hasher
))
250 DBG1("hash size in signature is %u bytes instead of %u bytes",
251 object
.len
, hasher
->get_hash_size(hasher
));
252 hasher
->destroy(hasher
);
256 /* build our own hash */
257 hasher
->allocate_hash(hasher
, data
, &hash
);
258 hasher
->destroy(hasher
);
260 /* compare the hashes */
261 res
= memeq(object
.ptr
, hash
.ptr
, hash
.len
) ? SUCCESS
: FAILED
;
278 * Implementation of rsa_public_key.get_key.
280 static status_t
get_key(const private_rsa_public_key_t
*this, chunk_t
*key
)
285 n
.ptr
= mpz_export(NULL
, NULL
, 1, n
.len
, 1, 0, this->n
);
287 e
.ptr
= mpz_export(NULL
, NULL
, 1, e
.len
, 1, 0, this->e
);
289 key
->len
= this->k
* 2;
290 key
->ptr
= malloc(key
->len
);
291 memcpy(key
->ptr
, n
.ptr
, n
.len
);
292 memcpy(key
->ptr
+ n
.len
, e
.ptr
, e
.len
);
300 * Implementation of rsa_public_key.save_key.
302 static status_t
save_key(const private_rsa_public_key_t
*this, char *file
)
304 return NOT_SUPPORTED
;
308 * Implementation of rsa_public_key.get_modulus.
310 static mpz_t
*get_modulus(const private_rsa_public_key_t
*this)
312 return (mpz_t
*)&this->n
;
316 * Implementation of rsa_public_key.get_keysize.
318 static size_t get_keysize(const private_rsa_public_key_t
*this)
324 * Implementation of rsa_public_key.get_keyid.
326 static chunk_t
get_keyid(const private_rsa_public_key_t
*this)
332 * Implementation of rsa_public_key.clone.
334 static rsa_public_key_t
* _clone(const private_rsa_public_key_t
*this)
336 private_rsa_public_key_t
*clone
= rsa_public_key_create_empty();
338 mpz_init_set(clone
->n
, this->n
);
339 mpz_init_set(clone
->e
, this->e
);
340 clone
->keyid
= chunk_clone(this->keyid
);
343 return &clone
->public;
347 * Implementation of rsa_public_key.destroy.
349 static void destroy(private_rsa_public_key_t
*this)
353 free(this->keyid
.ptr
);
358 * Generic private constructor
360 private_rsa_public_key_t
*rsa_public_key_create_empty(void)
362 private_rsa_public_key_t
*this = malloc_thing(private_rsa_public_key_t
);
364 /* public functions */
365 this->public.verify_emsa_pkcs1_signature
= (status_t (*) (const rsa_public_key_t
*,hash_algorithm_t
,chunk_t
,chunk_t
))verify_emsa_pkcs1_signature
;
366 this->public.get_key
= (status_t (*) (const rsa_public_key_t
*,chunk_t
*))get_key
;
367 this->public.save_key
= (status_t (*) (const rsa_public_key_t
*,char*))save_key
;
368 this->public.get_modulus
= (mpz_t
*(*) (const rsa_public_key_t
*))get_modulus
;
369 this->public.get_keysize
= (size_t (*) (const rsa_public_key_t
*))get_keysize
;
370 this->public.get_keyid
= (chunk_t (*) (const rsa_public_key_t
*))get_keyid
;
371 this->public.clone
= (rsa_public_key_t
* (*) (const rsa_public_key_t
*))_clone
;
372 this->public.destroy
= (void (*) (rsa_public_key_t
*))destroy
;
374 /* private functions */
376 this->rsavp1
= rsaep
; /* same algorithm */
382 * Build a DER-encoded publicKeyInfo object from an RSA public key.
383 * Also used in rsa_private_key.c.
385 chunk_t
rsa_public_key_info_to_asn1(const mpz_t n
, const mpz_t e
)
387 chunk_t rawKey
= asn1_wrap(ASN1_SEQUENCE
, "mm",
388 asn1_integer_from_mpz(n
),
389 asn1_integer_from_mpz(e
));
392 u_char
*pos
= build_asn1_object(&publicKey
, ASN1_BIT_STRING
, 1 + rawKey
.len
);
395 memcpy(pos
, rawKey
.ptr
, rawKey
.len
);
398 return asn1_wrap(ASN1_SEQUENCE
, "cm", ASN1_rsaEncryption_id
,
405 rsa_public_key_t
*rsa_public_key_create_from_chunk(chunk_t blob
)
412 private_rsa_public_key_t
*this = rsa_public_key_create_empty();
417 asn1_init(&ctx
, blob
, 0, FALSE
, FALSE
);
419 while (objectID
< PUB_KEY_ROOF
)
421 if (!extract_object(pubkeyObjects
, &objectID
, &object
, &level
, &ctx
))
428 case PUB_KEY_MODULUS
:
429 mpz_import(this->n
, object
.len
, 1, 1, 1, 0, object
.ptr
);
431 case PUB_KEY_EXPONENT
:
432 mpz_import(this->e
, object
.len
, 1, 1, 1, 0, object
.ptr
);
438 this->k
= (mpz_sizeinbase(this->n
, 2) + 7) / 8;
440 /* form the keyid as a SHA-1 hash of a publicKeyInfo object */
442 chunk_t publicKeyInfo
= rsa_public_key_info_to_asn1(this->n
, this->e
);
443 hasher_t
*hasher
= hasher_create(HASH_SHA1
);
445 hasher
->allocate_hash(hasher
, publicKeyInfo
, &this->keyid
);
446 hasher
->destroy(hasher
);
447 free(publicKeyInfo
.ptr
);
450 return &this->public;
456 rsa_public_key_t
*rsa_public_key_create_from_file(char *filename
)
459 chunk_t chunk
= chunk_empty
;
460 rsa_public_key_t
*pubkey
= NULL
;
462 if (!pem_asn1_load_file(filename
, NULL
, "public key", &chunk
, &pgp
))
465 pubkey
= rsa_public_key_create_from_chunk(chunk
);