b52da8908389cf561566be187163f8a008b21038
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_hasher.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "openssl_hasher.h"
19
20 #include <openssl/evp.h>
21
22 typedef struct private_openssl_hasher_t private_openssl_hasher_t;
23
24 /**
25 * Private data of openssl_hasher_t
26 */
27 struct private_openssl_hasher_t {
28
29 /**
30 * Public part of this class.
31 */
32 openssl_hasher_t public;
33
34 /**
35 * data collected to hash
36 */
37 chunk_t data;
38
39 /*
40 * the hasher to use
41 */
42 const EVP_MD *hasher;
43 };
44
45 /**
46 * Mapping from the algorithms defined in IKEv2 to
47 * OpenSSL algorithm names
48 */
49 typedef struct {
50 /**
51 * Identifier specified in IKEv2
52 */
53 int ikev2_id;
54
55 /**
56 * Name of the algorithm, as used in OpenSSL
57 */
58 char *name;
59 } openssl_algorithm_t;
60
61 #define END_OF_LIST -1
62
63 /**
64 * Algorithms for integrity
65 */
66 static openssl_algorithm_t integrity_algs[] = {
67 {HASH_MD2, "md2"},
68 {HASH_MD5, "md5"},
69 {HASH_SHA1, "sha1"},
70 {HASH_SHA256, "sha256"},
71 {HASH_SHA384, "sha384"},
72 {HASH_SHA512, "sha512"},
73 {END_OF_LIST, NULL},
74 };
75
76 /**
77 * Look up an OpenSSL algorithm name
78 */
79 static char* lookup_algorithm(openssl_algorithm_t *openssl_algo,
80 u_int16_t ikev2_algo)
81 {
82 while (openssl_algo->ikev2_id != END_OF_LIST)
83 {
84 if (ikev2_algo == openssl_algo->ikev2_id)
85 {
86 return openssl_algo->name;
87 }
88 openssl_algo++;
89 }
90 return NULL;
91 }
92
93 /**
94 * append data to the to-be-hashed buffer
95 */
96 static void append_data(private_openssl_hasher_t *this, chunk_t data)
97 {
98 this->data.ptr = realloc(this->data.ptr, this->data.len + data.len);
99 memcpy(this->data.ptr + this->data.len, data.ptr, data.len);
100 this->data.len += data.len;
101 }
102
103 /**
104 * hash a buffer of data
105 */
106 static void hash_data(private_openssl_hasher_t *this, chunk_t data, u_int8_t *digest)
107 {
108 EVP_MD_CTX ctx;
109 EVP_MD_CTX_init(&ctx);
110 EVP_DigestInit_ex(&ctx, this->hasher, NULL);
111 EVP_DigestUpdate(&ctx, data.ptr, data.len);
112 EVP_DigestFinal_ex(&ctx, digest, NULL);
113 EVP_MD_CTX_cleanup(&ctx);
114 }
115
116 /**
117 * Implementation of hasher_t.get_hash_size.
118 */
119 static size_t get_hash_size(private_openssl_hasher_t *this)
120 {
121 return this->hasher->md_size;
122 }
123
124 /**
125 * Implementation of hasher_t.reset.
126 */
127 static void reset(private_openssl_hasher_t *this)
128 {
129 chunk_free(&this->data);
130 }
131
132 /**
133 * Implementation of hasher_t.get_hash.
134 */
135 static void get_hash(private_openssl_hasher_t *this, chunk_t chunk,
136 u_int8_t *hash)
137 {
138 if (hash)
139 {
140 if (this->data.len)
141 {
142 append_data(this, chunk);
143 hash_data(this, this->data, hash);
144 }
145 else
146 { /* hash directly if no previous data found */
147 hash_data(this, chunk, hash);
148 }
149 reset(this);
150 }
151 else
152 {
153 append_data(this, chunk);
154 }
155 }
156
157 /**
158 * Implementation of hasher_t.allocate_hash.
159 */
160 static void allocate_hash(private_openssl_hasher_t *this, chunk_t chunk,
161 chunk_t *hash)
162 {
163 if (hash)
164 {
165 *hash = chunk_alloc(get_hash_size(this));
166 get_hash(this, chunk, hash->ptr);
167 }
168 else
169 {
170 get_hash(this, chunk, NULL);
171 }
172 }
173
174 /**
175 * Implementation of hasher_t.destroy.
176 */
177 static void destroy (private_openssl_hasher_t *this)
178 {
179 free(this->data.ptr);
180 free(this);
181 }
182
183 /*
184 * Described in header
185 */
186 openssl_hasher_t *openssl_hasher_create(hash_algorithm_t algo)
187 {
188 private_openssl_hasher_t *this;
189
190 char* name = lookup_algorithm(integrity_algs, algo);
191 if (!name)
192 {
193 /* algo unavailable */
194 return NULL;
195 }
196
197 this = malloc_thing(private_openssl_hasher_t);
198
199 this->hasher = EVP_get_digestbyname(name);
200 if (!this->hasher)
201 {
202 /* OpenSSL does not support the requested algo */
203 free(this);
204 return NULL;
205 }
206
207 this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash;
208 this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
209 this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size;
210 this->public.hasher_interface.reset = (void (*) (hasher_t*))reset;
211 this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy;
212
213 this->data = chunk_empty;
214
215 return &this->public;
216 }